Tag: 중급

  • 실무에서 바로 쓰는 RAG 파이프라인 구축 단계별 튜토리얼

    실무에서 바로 쓰는 RAG 파이프라인 구축 단계별 튜토리얼

    RAG(검색 증강 생성)는 LLM에 우리 회사의 문서나 최신 정보를 결합해 답하게 만드는 가장 현실적인 방법입니다. 파인튜닝보다 비용이 낮고, 출처를 제시할 수 있으며, 데이터가 바뀌어도 모델을 다시 학습할 필요가 없습니다. 이 글에서는 동작하는 RAG 파이프라인을 다섯 단계로 나눠 구축합니다.

    1단계: 문서 적재와 정제

    RAG의 품질은 입력 문서의 품질을 넘지 못합니다. PDF, HTML, 노션 등에서 텍스트를 추출할 때 머리말·바닥글·내비게이션 같은 노이즈를 제거하고, 표와 코드 블록의 구조를 최대한 보존해야 합니다. 정제되지 않은 문서를 그대로 넣으면 이후 단계가 아무리 좋아도 엉뚱한 답이 나옵니다.

    2단계: 청킹 전략

    문서를 검색 단위로 쪼개는 청킹은 RAG에서 가장 과소평가되는 단계입니다. 너무 작게 자르면 문맥이 끊기고, 너무 크게 자르면 관련 없는 내용까지 섞입니다. 일반 문서는 300~600토큰에 10~20% 오버랩을 주는 것이 무난한 출발점입니다.

    • 고정 크기 청킹: 단순하지만 문장이 중간에 끊길 수 있음
    • 문장/문단 기준 청킹: 의미 단위 보존에 유리
    • 구조 기반 청킹: 제목 계층을 활용해 섹션 단위로 분리

    3단계: 임베딩과 벡터 저장

    각 청크를 임베딩 모델로 벡터화한 뒤 벡터 DB에 저장합니다. 이때 청크 본문뿐 아니라 문서 제목, 출처 URL, 작성일 같은 메타데이터를 함께 저장해야 나중에 필터링과 출처 표시가 가능합니다. 메타데이터 설계를 미루면 운영 단계에서 반드시 후회합니다.

    chunk = {
      "text": "...본문...",
      "embedding": [0.12, -0.04, ...],
      "source": "policy_2026.pdf",
      "page": 12,
      "updated_at": "2026-03-01"
    }

    4단계: 검색과 재정렬

    사용자 질문을 임베딩해 벡터 검색으로 상위 K개 청크를 가져옵니다. 여기서 끝내지 말고, 가져온 후보를 리랭커(reranker)로 다시 정렬하면 정확도가 눈에 띄게 올라갑니다. 보통 벡터 검색으로 20~30개를 넉넉히 뽑은 뒤 리랭커로 상위 3~5개만 추리는 2단계 구성을 권장합니다.

    5단계: 생성과 출처 표기

    마지막으로 추려진 청크를 프롬프트에 문맥으로 넣고 LLM에게 답하게 합니다. 이때 “제공된 문맥에만 근거해 답하고, 근거가 없으면 모른다고 답하라”는 지침을 명시해 환각을 억제합니다. 또한 각 청크의 출처를 답변에 함께 노출해 사용자가 검증할 수 있게 합니다.

    처음부터 완벽한 파이프라인을 만들려 하지 마세요. 청킹과 검색 K값만 바꿔도 체감 품질이 크게 달라지므로, 작게 만들고 평가셋으로 반복 개선하는 것이 정석입니다.

    다음 단계로는 검색 정확도를 정량 측정하는 방법과, 답변 품질을 평가하는 지표를 도입해 보길 권합니다. 측정 없이 개선하는 RAG는 결국 감에 의존하게 됩니다.

  • 벡터검색 정확도가 낮을 때 점검해야 할 7가지 원인

    벡터검색 정확도가 낮을 때 점검해야 할 7가지 원인

    RAG를 만들었는데 “분명 문서에 있는데 검색이 못 찾는다”는 문제는 거의 모든 팀이 겪습니다. 생성 모델이 아무리 좋아도 검색이 관련 문맥을 못 가져오면 답은 무너집니다. 이 글에서는 벡터검색 정확도가 낮을 때 점검할 원인을 우선순위대로 정리합니다.

    원인 1~2: 청킹과 정제 문제

    가장 흔한 원인은 검색이 아니라 그 앞 단계에 있습니다. 청크가 너무 커서 하나의 벡터에 여러 주제가 섞이면 임베딩이 흐려져 어떤 질문에도 어중간하게 매칭됩니다. 반대로 너무 작으면 핵심 문장이 문맥 없이 떠다닙니다. 또한 정제가 부실해 머리말·각주가 본문에 섞이면 노이즈가 임베딩을 오염시킵니다.

    원인 3: 부적합한 임베딩 모델

    영어 위주로 학습된 임베딩 모델을 한국어 문서에 쓰면 의미가 비슷한 문장끼리도 벡터 거리가 멀어집니다. 도메인 용어가 많은 경우(의료·법률·금융)에는 일반 모델보다 해당 언어와 도메인을 잘 반영하는 모델을 선택해야 합니다.

    원인 4: 거리 측정과 정규화

    코사인 유사도를 가정한 모델인데 벡터를 정규화하지 않고 유클리드 거리로 검색하면 결과가 망가집니다. 임베딩 모델 문서가 권장하는 거리 측정 방식과 정규화 여부를 반드시 확인하세요. 이 작은 설정 하나가 정확도를 좌우합니다.

    • 코사인 유사도: 정규화된 벡터, 의미 유사도에 일반적
    • 내적(dot product): 정규화 안 된 벡터에서 사용, 크기 반영
    • 유클리드 거리: 절대적 거리, 일부 모델에서만 적합

    원인 5~6: 질문과 문서의 표현 격차

    사용자는 “환불 어떻게 해요”라고 묻지만 문서에는 “청약 철회 절차”라고 적혀 있으면 순수 의미 검색만으로는 잘 안 잡힙니다. 이런 어휘 격차에는 키워드 검색(BM25)과 벡터 검색을 함께 쓰는 하이브리드 검색이 효과적입니다. 또한 질문을 LLM으로 확장·재작성하는 쿼리 변환도 도움이 됩니다.

    원인 7: 리랭킹 부재

    벡터 검색의 상위 결과가 정확히 1등은 아닐 때가 많습니다. 상위 후보를 넉넉히 뽑은 뒤 리랭커로 다시 정렬하면, 같은 검색 결과에서도 실제로 답에 쓰이는 청크의 적중률이 올라갑니다.

    진단 순서를 기억하세요: 정제 → 청킹 → 임베딩 모델 → 거리 설정 → 하이브리드/쿼리 변환 → 리랭킹. 위에서부터 막혀 있으면 아래를 아무리 손봐도 효과가 없습니다.

    정리

    벡터검색 문제는 대부분 검색 알고리즘이 아니라 그 앞뒤 단계에서 발생합니다. 작은 평가셋(질문-정답 청크 쌍)을 만들어 두고, 한 번에 한 가지 변수만 바꾸며 적중률을 측정하면 원인을 빠르게 좁힐 수 있습니다.

  • 임베딩 모델 선택 가이드: 한국어 RAG에서 무엇을 기준으로 고를까

    임베딩 모델 선택 가이드: 한국어 RAG에서 무엇을 기준으로 고를까

    RAG 파이프라인에서 임베딩 모델은 검색 품질의 천장을 결정합니다. 그런데 모델 종류가 너무 많아 무엇을 기준으로 골라야 할지 막막합니다. 이 글에서는 한국어 RAG를 전제로 임베딩 모델 선택 기준을 실무적으로 비교합니다.

    기준 1: 다국어·한국어 성능

    한국어 문서를 다룬다면 다국어 학습 데이터 비중과 한국어 벤치마크 점수를 먼저 봐야 합니다. 영어 전용 모델은 영어 벤치마크에서 아무리 높아도 한국어 의미 검색에서 무너지는 경우가 흔합니다. 가능하면 자신의 실제 문서로 작은 테스트셋을 만들어 직접 비교하는 것이 가장 확실합니다.

    기준 2: 벡터 차원과 저장 비용

    차원이 높을수록 표현력은 좋아지지만 저장 공간과 검색 지연이 늘어납니다. 1024차원과 384차원은 메모리 사용량이 거의 3배 차이가 납니다. 문서가 수백만 건이라면 차원 수가 인프라 비용에 직접 반영됩니다.

    • 384차원: 가볍고 빠름, 대규모 인덱스에 유리
    • 768차원: 균형점, 가장 보편적
    • 1024차원 이상: 표현력 우수, 비용과 지연 증가

    기준 3: 최대 입력 길이

    임베딩 모델마다 한 번에 처리 가능한 토큰 한도가 다릅니다. 512토큰 한도 모델에 800토큰 청크를 넣으면 뒷부분이 잘려 의미가 손실됩니다. 청킹 전략과 임베딩 모델의 입력 한도는 반드시 함께 설계해야 합니다.

    기준 4: 호스팅 방식과 비용

    API형 임베딩은 도입이 쉽지만 호출량이 많으면 비용이 누적되고 외부로 데이터가 나갑니다. 오픈 모델을 자체 호스팅하면 데이터 통제와 단가는 좋아지지만 GPU 운영 부담이 생깁니다. 민감 데이터가 있다면 자체 호스팅이 사실상 필수입니다.

    벤치마크 1위 모델이 우리 데이터에서도 1위라는 보장은 없습니다. 공개 리더보드는 후보를 좁히는 용도로만 쓰고, 최종 선택은 자체 평가셋으로 검증하세요.

    흔한 실수

    가장 흔한 실수는 한 번 고른 임베딩 모델을 나중에 바꾸는 것을 가볍게 보는 것입니다. 모델을 바꾸면 전체 문서를 다시 임베딩해야 하므로, 수백만 건 규모에서는 상당한 시간과 비용이 듭니다. 그래서 처음 선택 시 확장성을 함께 고려해야 합니다. 또 다른 실수는 질문과 문서를 서로 다른 모델로 임베딩하는 것으로, 이 경우 벡터 공간이 달라 검색이 전혀 동작하지 않습니다.

    정리

    임베딩 모델은 한국어 성능, 차원, 입력 길이, 호스팅 비용의 네 축으로 비교하고, 최종 결정은 반드시 자체 데이터로 검증하세요. 작은 평가셋 하나가 리더보드 100개보다 정확한 답을 줍니다.

  • 파인튜닝 vs 프롬프트 엔지니어링, 언제 무엇을 선택할까

    파인튜닝 vs 프롬프트 엔지니어링, 언제 무엇을 선택할까

    “우리도 파인튜닝해야 하나요?”는 LLM 도입 팀이 가장 자주 던지는 질문입니다. 결론부터 말하면 대부분의 경우 프롬프트 엔지니어링과 RAG로 먼저 시도하고, 그래도 한계가 명확할 때 파인튜닝을 고려하는 것이 맞습니다. 이 글은 둘의 손익분기점을 실무 기준으로 비교합니다.

    두 접근의 본질적 차이

    프롬프트 엔지니어링은 모델은 그대로 두고 지시와 예시로 행동을 유도합니다. 파인튜닝은 모델의 가중치 자체를 추가 학습해 특정 작업에 맞춥니다. 전자는 즉시 바꿀 수 있고 비용이 낮은 대신 컨텍스트를 매번 소모하고, 후자는 일관된 스타일과 형식을 내재화하지만 데이터 준비와 재학습 비용이 듭니다.

    파인튜닝이 유리한 경우

    • 특정 출력 형식·말투를 매우 일관되게 유지해야 할 때
    • 프롬프트에 예시를 많이 넣어야 해서 토큰 비용이 과한 때
    • 충분한 양질의 학습 데이터(보통 수백~수천 건)가 있을 때
    • 지연 시간을 줄이기 위해 프롬프트를 짧게 만들어야 할 때

    프롬프트가 유리한 경우

    요구사항이 자주 바뀌거나, 학습 데이터가 부족하거나, 빠르게 실험해야 하는 초기 단계라면 프롬프트가 압도적으로 유리합니다. 또한 “최신 정보”나 “회사 문서 기반 답변”이 필요한 경우는 파인튜닝이 아니라 RAG의 영역입니다. 지식 주입을 파인튜닝으로 해결하려는 것은 흔한 오해입니다.

    기억하세요: 파인튜닝은 “어떻게 말할지(형식·스타일)”를 가르치는 데 강하고, RAG는 “무엇을 말할지(지식)”를 공급하는 데 강합니다. 둘은 경쟁이 아니라 보완 관계입니다.

    비용 관점의 손익분기

    파인튜닝은 초기 학습 비용이 들지만 프롬프트를 짧게 만들어 호출당 비용을 낮춥니다. 따라서 호출량이 매우 많은 서비스라면 누적 절감이 학습 비용을 넘어서는 지점이 생깁니다. 반대로 호출량이 적으면 학습 투자를 회수하기 어렵습니다. 일 호출 수, 절감되는 토큰, 학습 비용을 표로 계산해 손익분기 호출량을 직접 구해 보길 권합니다.

    실무 권장 순서

    현실적인 순서는 프롬프트 엔지니어링으로 빠르게 검증하고, 지식이 필요하면 RAG를 붙이고, 그래도 형식·말투의 일관성이나 비용 문제가 남으면 마지막에 파인튜닝을 도입하는 것입니다. 처음부터 파인튜닝으로 시작하면 데이터 준비에 시간을 쏟다가 정작 제품 검증이 늦어지기 쉽습니다.

    정리

    파인튜닝과 프롬프트는 양자택일이 아닙니다. 작업의 성격(형식 vs 지식), 데이터 보유량, 호출량 세 가지로 판단하고, 가장 싸고 빠른 방법부터 단계적으로 올라가는 것이 가장 합리적인 전략입니다.

  • 멀티모달 AI 실무 활용: 이미지와 텍스트를 함께 다루는 5가지 패턴

    멀티모달 AI 실무 활용: 이미지와 텍스트를 함께 다루는 5가지 패턴

    이제 LLM은 텍스트만 다루지 않습니다. 이미지, 표, 차트, 문서 스캔본을 함께 이해하는 멀티모달 모델이 보편화되면서, 기존에 자동화하기 어렵던 업무가 풀리고 있습니다. 이 글에서는 멀티모달 AI를 실무에 적용하는 다섯 가지 대표 패턴을 소개합니다.

    패턴 1: 문서 이해와 정보 추출

    계약서, 영수증, 송장 같은 문서는 텍스트뿐 아니라 레이아웃이 의미를 가집니다. 멀티모달 모델은 이미지 형태의 문서에서 항목과 값을 구조화해 추출할 수 있어, 기존 OCR+규칙 기반 파이프라인보다 양식 변화에 훨씬 강합니다.

    패턴 2: 표와 차트 해석

    PDF 안의 표나 차트는 텍스트 추출로는 구조가 깨지기 일쑤입니다. 멀티모달 모델은 표를 이미지로 보고 행·열 관계를 이해해 마크다운 표나 JSON으로 변환할 수 있습니다. 다만 복잡한 병합 셀이나 흐릿한 스캔본에서는 검증 단계가 반드시 필요합니다.

    패턴 3: 시각 기반 검색

    이미지를 임베딩해 “비슷한 제품 사진 찾기”나 “이 도면과 유사한 부품 찾기” 같은 검색을 구현할 수 있습니다. 텍스트와 이미지를 같은 벡터 공간에 임베딩하면, 텍스트로 이미지를 검색하거나 그 반대도 가능해집니다.

    • 제품 이미지 유사도 기반 추천
    • 텍스트 질의로 사내 도면·자산 검색
    • 불량 이미지와 정상 이미지 비교 분류

    패턴 4: 시각 정보가 포함된 RAG

    매뉴얼이나 보고서에는 그림과 그래프가 핵심 정보를 담는 경우가 많습니다. 이런 문서로 RAG를 만들 때 그림을 버리면 답변 품질이 떨어집니다. 그림을 캡션·설명 텍스트로 변환해 함께 인덱싱하거나, 멀티모달 검색을 결합하면 시각 정보까지 답변에 반영할 수 있습니다.

    패턴 5: 품질 검수 자동화

    제조·물류에서 제품 사진을 보고 결함 여부를 판정하거나, 마케팅 소재가 브랜드 가이드를 지키는지 검토하는 작업에 멀티모달 모델을 쓸 수 있습니다. 사람의 1차 스크리닝을 대체해 검수 인력의 부담을 크게 줄입니다.

    멀티모달은 강력하지만 만능이 아닙니다. 숫자가 중요한 표나 안전이 걸린 판정에는 반드시 사람 검증 단계를 두고, 모델 출력의 신뢰도를 함께 기록하세요.

    정리

    멀티모달 AI는 문서 이해, 표·차트 해석, 시각 검색, 시각 RAG, 검수 자동화의 다섯 영역에서 즉시 가치를 냅니다. 텍스트만으로 풀던 문제에 이미지 차원을 더하면 자동화 범위가 크게 넓어집니다. 우선 반복적이고 양식이 다양한 문서 업무부터 적용해 보길 권합니다.

  • 레이크하우스 아키텍처 설계: 데이터 레이크와 웨어하우스를 하나로

    레이크하우스 아키텍처 설계: 데이터 레이크와 웨어하우스를 하나로

    데이터 조직이 일정 규모를 넘어서면 두 가지 인프라를 동시에 운영하는 비용에 직면합니다. 원천 로그와 비정형 데이터를 담는 데이터 레이크, 그리고 BI와 리포팅을 위한 데이터 웨어하우스입니다. 두 시스템 사이에서 데이터를 복제하다 보면 동일한 지표가 두 곳에서 다른 값을 내는 일이 흔합니다. 레이크하우스는 이 이중 구조를 단일 저장 계층으로 통합하려는 시도입니다.

    이 글에서는 레이크하우스가 해결하려는 문제부터 테이블 포맷 선택, 계층 설계, 운영 시 마주치는 함정까지 단계적으로 다룹니다. 약 500TB 규모의 분석 환경을 기준으로 설명하지만 원리는 더 작은 환경에도 그대로 적용됩니다.

    왜 레이크하우스인가

    전통적인 구조에서는 객체 스토리지(S3, GCS)에 원본을 쌓고, ETL로 정제한 뒤 별도의 웨어하우스로 적재합니다. 문제는 두 가지입니다. 첫째, 웨어하우스 스토리지 비용이 객체 스토리지의 5배에서 10배에 달합니다. 둘째, 복제 지연 때문에 데이터 신선도가 떨어집니다.

    레이크하우스는 값싼 객체 스토리지 위에 ACID 트랜잭션, 스키마 강제, 타임 트래블 같은 웨어하우스급 기능을 제공하는 테이블 포맷을 얹어 이 문제를 해결합니다. 동일한 데이터를 SQL 엔진과 ML 프레임워크가 함께 읽을 수 있다는 점이 핵심 가치입니다.

    테이블 포맷 선택

    레이크하우스의 심장은 테이블 포맷입니다. 대표적으로 Delta Lake, Apache Iceberg, Apache Hudi 세 가지가 경쟁합니다. 선택 기준을 표로 정리하면 다음과 같습니다.

    포맷강점적합 시나리오
    Delta LakeSpark 생태계 통합, 성숙도Databricks 중심 환경
    Iceberg엔진 중립성, 숨은 파티셔닝멀티 엔진 운영
    Hudi업서트, 증분 처리CDC 기반 적재

    여러 쿼리 엔진(Trino, Spark, Flink)을 함께 쓴다면 Iceberg의 엔진 중립성이 유리합니다. CDC로 잦은 업데이트가 발생한다면 Hudi의 업서트 성능이 빛을 발합니다.

    메달리온 계층 설계

    실무에서 가장 널리 쓰이는 구조는 브론즈-실버-골드로 나누는 메달리온 아키텍처입니다. 브론즈는 원천을 거의 그대로 적재한 불변 레이어, 실버는 정제와 조인을 거친 레이어, 골드는 비즈니스 지표가 집계된 소비 레이어입니다.

    • 브론즈: append-only, 스키마 검증 최소화, 재처리 기준점
    • 실버: 중복 제거, 타입 정규화, 품질 규칙 적용
    • 골드: 차원 모델 또는 와이드 테이블, BI 직접 연결

    이 분리의 이점은 명확합니다. 비즈니스 로직이 바뀌어도 브론즈는 그대로 두고 실버부터 다시 만들면 됩니다. 원본 손실 없이 전체 파이프라인을 재현할 수 있다는 뜻입니다.

    운영과 트러블슈팅

    레이크하우스에서 가장 흔한 운영 이슈는 작은 파일 문제입니다. 스트리밍이나 잦은 커밋으로 수십 KB짜리 파일이 수백만 개 쌓이면 쿼리 시 메타데이터 스캔만으로 수십 초가 소요됩니다. 해결책은 정기적인 컴팩션(OPTIMIZE)과 적절한 파일 크기 목표(128MB에서 1GB) 설정입니다.

    또 하나는 메타데이터 누적입니다. 타임 트래블을 위해 보관하는 스냅샷이 무한정 쌓이면 스토리지와 메타 처리 비용이 증가합니다. VACUUM 또는 expire_snapshots를 7일에서 30일 보존 정책으로 스케줄링하세요. 단, 진행 중인 장기 쿼리가 참조하는 스냅샷을 삭제하지 않도록 보존 기간을 보수적으로 잡는 것이 안전합니다.

    레이크하우스의 성패는 포맷 선택보다 컴팩션과 보존 정책 같은 운영 자동화에서 갈립니다.

    정리

    레이크하우스는 레이크와 웨어하우스의 이중 구조를 단일 계층으로 합쳐 비용과 신선도를 동시에 개선합니다. 핵심은 적합한 테이블 포맷을 고르고, 메달리온 계층으로 책임을 분리하며, 컴팩션과 스냅샷 관리를 자동화하는 것입니다. 작게 시작해 브론즈부터 구축하고 점진적으로 골드 레이어를 확장하는 접근을 권합니다.

  • Airflow로 데이터 파이프라인 오케스트레이션 제대로 하기

    Airflow로 데이터 파이프라인 오케스트레이션 제대로 하기

    데이터 파이프라인이 십수 개를 넘어가면 cron과 셸 스크립트로는 더 이상 감당이 안 됩니다. 어떤 작업이 실패했는지, 무엇이 먼저 끝나야 다음이 도는지, 재실행은 어떻게 하는지를 사람이 일일이 추적해야 하기 때문입니다. Apache Airflow는 이 워크플로를 코드로 정의하고 의존성과 재시도를 자동으로 관리하는 오케스트레이터입니다.

    이 글에서는 Airflow의 핵심 개념인 DAG와 태스크 의존성, 스케줄링 동작, 그리고 멱등성 있는 파이프라인을 만드는 운영 노하우를 다룹니다.

    오케스트레이션이 필요한 이유

    파이프라인은 단순히 스크립트를 시간 맞춰 실행하는 것이 아닙니다. A가 끝나야 B를 시작하고, B가 실패하면 C를 건너뛰며, 특정 작업은 세 번까지 재시도하는 식의 의존성과 조건이 얽혀 있습니다. cron은 이 관계를 표현하지 못합니다. Airflow는 작업 간 관계를 방향성 비순환 그래프(DAG)로 표현해 이 복잡성을 명시적으로 관리합니다.

    DAG와 태스크의 구조

    DAG는 노드(태스크)와 방향성 엣지(의존성)로 이뤄진 그래프입니다. 각 태스크는 오퍼레이터로 구현되며, 비트시프트 연산자로 순서를 선언합니다.

    with DAG("daily_sales", schedule="0 2 * * *",
             start_date=datetime(2026,1,1), catchup=False) as dag:
        extract = PythonOperator(task_id="extract", python_callable=pull)
        transform = PythonOperator(task_id="transform", python_callable=clean)
        load = PythonOperator(task_id="load", python_callable=write)
        extract >> transform >> load

    여기서 catchup=False는 중요한 설정입니다. True로 두면 start_date부터 현재까지의 모든 누락된 실행을 한꺼번에 채우려 들어 시스템에 부하가 집중됩니다. 의도적인 백필이 아니라면 끄는 것이 안전합니다.

    스케줄링과 execution_date

    Airflow 입문자를 가장 혼란스럽게 하는 개념이 실행 시점과 데이터 기간의 분리입니다. 일 단위 DAG는 해당 기간이 끝난 직후에 실행됩니다. 즉 6월 24일 데이터의 처리는 6월 25일 새벽에 트리거됩니다. 이 논리적 기간(data interval)을 기준으로 쿼리를 작성해야 멱등성이 보장됩니다.

    태스크 내부에서는 현재 시각이 아니라 data_interval_start와 data_interval_end를 사용해 처리 범위를 한정하세요. 그래야 재실행이나 백필 시에도 항상 같은 결과를 냅니다.

    운영과 트러블슈팅

    운영에서 가장 자주 마주치는 문제는 태스크 적체입니다. 스케줄러가 태스크를 큐에 넣었는데 워커가 부족하면 queued 상태에서 멈춥니다. 동시성 관련 파라미터를 점검하세요.

    • parallelism: 전체 동시 실행 태스크 상한
    • max_active_runs: 한 DAG의 동시 실행 인스턴스 수
    • pool: 외부 DB 커넥션 등 공유 자원 보호용 슬롯

    또한 멱등성이 깨진 태스크는 재시도 시 데이터 중복을 낳습니다. INSERT보다 파티션 단위 덮어쓰기나 MERGE를 사용해 같은 입력에 항상 같은 출력이 나오도록 설계하세요. 무거운 연산은 Airflow 워커에서 직접 돌리지 말고 Spark나 웨어하우스로 위임하는 것이 안정적입니다.

    Airflow는 작업을 실행하는 도구가 아니라 작업을 지휘하는 도구다. 무거운 연산은 외부 엔진에 맡겨라.

    정리

    Airflow는 파이프라인의 의존성, 스케줄, 재시도를 코드로 관리해 운영 복잡성을 길들입니다. DAG로 관계를 명시하고, data interval 기반으로 멱등성을 지키며, 동시성 파라미터로 자원을 보호하는 것이 안정 운영의 핵심입니다. Airflow는 지휘자 역할에 집중시키고 연산은 전문 엔진에 위임하세요.

  • dbt로 데이터 변환 모델링하기: 분석 엔지니어링의 표준

    dbt로 데이터 변환 모델링하기: 분석 엔지니어링의 표준

    웨어하우스에 데이터를 적재한 뒤 그것을 분석 가능한 형태로 변환하는 일은 오랫동안 복잡한 SQL 스크립트 더미와 수작업으로 이뤄졌습니다. 누가 어떤 테이블을 만들었는지, 의존 관계가 무엇인지 아무도 모르는 상태가 흔했습니다. dbt는 이 변환 계층(ELT의 T)을 소프트웨어 엔지니어링 원칙으로 다루게 해주는 도구입니다.

    이 글에서는 dbt의 모델, 참조 시스템, 테스트, 문서화를 차례로 살펴보고, 실무에서 모델 구조를 어떻게 잡아야 하는지 다룹니다.

    dbt가 바꾸는 것

    dbt의 출발점은 단순합니다. 모든 변환은 SELECT 문 하나로 표현되는 모델이고, dbt가 그것을 CREATE TABLE 또는 VIEW로 감싸 실행합니다. 엔지니어는 결과 테이블이 아니라 그 테이블을 정의하는 쿼리에 집중합니다. 여기에 버전 관리, 테스트, 의존성 그래프가 따라옵니다.

    핵심 마법은 ref 함수입니다. 모델끼리 직접 테이블명을 쓰지 않고 ref로 참조하면 dbt가 의존 그래프를 자동 구성하고 올바른 순서로 빌드합니다. 환경(dev, prod) 간 스키마 전환도 ref가 알아서 처리합니다.

    모델 계층 구조

    잘 설계된 dbt 프로젝트는 보통 세 계층으로 나눕니다. 이 구조는 변경에 강하고 재사용이 쉽습니다.

    • staging: 원천 테이블당 1:1, 컬럼명 정리와 타입 캐스팅만
    • intermediate: 여러 staging을 조합한 중간 로직, 재사용 단위
    • marts: 비즈니스 도메인별 최종 산출물, BI 연결
    -- models/marts/fct_orders.sql
    with orders as (
        select * from {{ ref('stg_orders') }}
    ),
    payments as (
        select * from {{ ref('stg_payments') }}
    )
    select o.order_id, o.customer_id, sum(p.amount) as total
    from orders o left join payments p using (order_id)
    group by 1, 2

    테스트와 문서화

    dbt의 진짜 강점은 데이터 품질 테스트를 선언적으로 붙일 수 있다는 점입니다. YAML에 not_null, unique, accepted_values, relationships 같은 제약을 명시하면 빌드마다 자동 검증됩니다. 기본 테스트로 부족하면 SQL로 커스텀 테스트를 작성합니다.

    같은 YAML에 컬럼 설명을 적으면 dbt docs가 자동으로 데이터 카탈로그와 계보 그래프를 생성합니다. 코드와 문서가 한곳에 있어 문서가 낡지 않는다는 점이 큰 가치입니다.

    운영과 성능

    모델이 수백 개를 넘으면 전체 빌드 시간이 부담스러워집니다. 매번 전체 테이블을 새로 만드는 대신 incremental 모델로 새 데이터만 추가 처리하세요. is_incremental 분기로 증분 조건을 걸면 빌드 시간이 수십 분에서 수 분으로 줄어듭니다.

    또한 dbt build와 함께 상태 비교 선택(state:modified)을 쓰면 변경된 모델과 그 하위만 빌드해 CI 시간을 절약할 수 있습니다. 한 가지 주의점은 증분 모델의 고유 키 설정 오류로 인한 중복인데, unique 테스트로 반드시 방어하세요.

    dbt는 분석가를 엔지니어로 만든다. 버전 관리, 테스트, 문서화가 SQL 워크플로에 자연스럽게 녹아들기 때문이다.

    정리

    dbt는 변환 계층을 모듈화된 SQL 모델로 다루며 ref 기반 의존성, 선언적 테스트, 자동 문서화를 제공합니다. staging-intermediate-marts 계층으로 구조를 잡고, 증분 모델로 성능을 확보하며, 테스트로 품질을 지키는 것이 분석 엔지니어링의 표준 워크플로입니다.

  • 데이터 파이프라인 관측성: 신뢰를 만드는 모니터링 체계

    데이터 파이프라인 관측성: 신뢰를 만드는 모니터링 체계

    전통적인 모니터링은 잡이 성공했는지 실패했는지를 봅니다. 그런데 데이터 세계에는 더 교묘한 문제가 있습니다. 잡은 분명히 초록불로 성공했는데, 실제 데이터는 절반이 비어 있거나 어제보다 10분의 1로 줄어든 경우입니다. 이런 침묵의 장애를 잡으려면 잡 상태가 아니라 데이터 자체를 관측해야 합니다. 이것이 데이터 관측성입니다.

    이 글에서는 데이터 관측성의 다섯 기둥, 구현 방법, 그리고 경보 피로를 피하는 운영 전략을 다룹니다.

    왜 잡 성공만으로는 부족한가

    파이프라인이 성공했다는 신호는 코드가 예외 없이 끝났다는 뜻일 뿐입니다. 원천 API가 빈 응답을 주거나, 업스트림 조인 키가 바뀌어 매칭이 0건이 되어도 코드는 멀쩡히 성공합니다. 비즈니스 대시보드의 숫자가 이상하다고 누군가 제보하기 전까지 아무도 모릅니다.

    실제로 데이터 장애의 상당수는 코드 버그가 아니라 데이터 자체의 변화에서 옵니다. 그래서 관측 대상이 인프라에서 데이터로 확장되어야 합니다.

    데이터 관측성의 다섯 기둥

    업계에서 합의된 관측성의 다섯 축은 다음과 같습니다. 각각이 서로 다른 유형의 장애를 잡아냅니다.

    • 신선도(Freshness): 데이터가 기대한 시점에 갱신됐는가
    • 양(Volume): 행 수가 평소 범위 안에 있는가
    • 분포(Distribution): 값의 범위와 null 비율이 정상인가
    • 스키마(Schema): 컬럼과 타입이 바뀌지 않았는가
    • 계보(Lineage): 어느 업스트림이 어느 다운스트림에 영향을 주는가

    신선도와 양만 잘 잡아도 침묵의 장애 대부분을 조기에 발견할 수 있습니다. 계보는 장애 발생 시 영향 범위를 빠르게 파악하는 데 결정적입니다.

    구현 방법

    가장 단순한 시작점은 핵심 테이블에 품질 검사를 거는 것입니다. dbt test, Great Expectations, Soda 같은 도구로 행 수 임계, null 비율, 고유성, 값 범위를 선언적으로 검증합니다.

    # Soda 체크 예시
    checks for fct_orders:
      - row_count between 9000 and 15000
      - missing_percent(customer_id) < 1%
      - freshness(created_at) < 6h
      - duplicate_count(order_id) = 0

    한 단계 더 나아가면 과거 패턴을 학습해 동적 임계치를 만드는 이상 탐지를 도입할 수 있습니다. 요일별, 시간대별 패턴을 반영하면 고정 임계보다 오탐이 크게 줍니다.

    경보 피로를 피하는 운영

    관측성을 도입하면 처음엔 경보가 폭주합니다. 너무 많은 경보는 곧 무시되고, 무시되는 경보는 없는 것과 같습니다. 따라서 심각도를 계층화하세요. 비즈니스 핵심 테이블의 신선도 장애는 즉시 호출(page), 부차적 테이블의 분포 경고는 일일 다이제스트로 묶는 식입니다.

    • SLA가 정의된 골드 테이블에만 강한 경보를 건다
    • 경보마다 담당자(owner)와 런북을 명시한다
    • 오탐이 잦은 검사는 임계를 조정하거나 제거한다

    데이터 신뢰는 정확한 데이터에서 오는 것이 아니라, 틀렸을 때 가장 먼저 아는 데서 온다.

    정리

    데이터 관측성은 잡 성공을 넘어 데이터 자체의 신선도, 양, 분포, 스키마, 계보를 감시합니다. 핵심 테이블부터 선언적 품질 검사를 걸고, 동적 임계로 오탐을 줄이며, 심각도를 계층화해 경보 피로를 막으세요. 목표는 완벽한 데이터가 아니라, 문제가 생겼을 때 사용자보다 먼저 아는 것입니다.

  • 데이터 적재 품질을 지키는 7가지 실전 원칙

    데이터 적재 품질을 지키는 7가지 실전 원칙

    데이터 품질 논의는 흔히 분석 단계나 대시보드 단계에 집중되지만, 진짜 싸움은 파이프라인 가장 앞단인 적재(ingestion)에서 벌어집니다. 입구에서 오염된 데이터는 하류로 내려갈수록 정화 비용이 기하급수적으로 커집니다. 한 번 잘못 들어간 데이터는 수십 개 다운스트림 테이블을 오염시키고, 추적과 복구에 며칠이 걸립니다.

    이 글에서는 적재 단계에서 품질을 지키기 위한 일곱 가지 실전 원칙을 사례와 함께 정리합니다.

    1. 입구에서 검증하라

    가장 기본은 적재 시점의 스키마와 제약 검증입니다. 필수 필드 존재, 타입 일치, 값 범위를 적재 직전에 확인하세요. 검증을 뒤로 미룰수록 오염 범위가 넓어집니다. 입구에서 거른 한 건이 하류의 백 건 복구를 막습니다.

    2. 멱등성을 보장하라

    파이프라인은 반드시 재실행됩니다. 같은 데이터가 두 번 적재돼도 결과가 같아야 합니다. INSERT 대신 자연 키 기반 MERGE나 파티션 덮어쓰기를 사용하세요. 멱등하지 않은 적재는 재시도 한 번에 중복 폭탄이 됩니다.

    MERGE INTO target t
    USING staging s ON t.event_id = s.event_id
    WHEN MATCHED THEN UPDATE SET *
    WHEN NOT MATCHED THEN INSERT *;

    3. 불량 레코드를 격리하라

    검증에 실패한 레코드를 만났을 때 전체 배치를 통째로 실패시키면 정상 데이터까지 막힙니다. 반대로 조용히 버리면 손실을 모릅니다. 정답은 불량 레코드 격리(quarantine)입니다. 실패한 행을 별도 데드레터 테이블로 보내 정상 흐름은 유지하되 추적은 가능하게 하세요.

    4. 원본을 보존하라

    적재 단계에서 변환을 과하게 하지 마세요. 원본을 거의 그대로 담는 불변 레이어(브론즈)를 두면, 로직 오류를 발견했을 때 원천 재요청 없이 재처리할 수 있습니다. 원본 보존은 가장 값싼 보험입니다.

    5. 메타데이터를 함께 적재하라

    각 레코드에 적재 시각, 원천 식별자, 배치 ID, 파일명 같은 메타데이터를 붙이세요. 문제가 터졌을 때 어느 배치, 어느 파일에서 왔는지 즉시 추적할 수 있습니다. 이 작은 컬럼들이 장애 대응 시간을 시간 단위에서 분 단위로 줄입니다.

    • _ingested_at: 적재 타임스탬프
    • _source_file: 원천 파일 경로
    • _batch_id: 적재 배치 식별자
    • _record_hash: 변경 감지용 해시

    6. 양과 신선도를 감시하라

    적재된 행 수가 평소 범위를 벗어나거나 기대 시각에 데이터가 없으면 즉시 경보하세요. 원천 API가 빈 응답을 줘 0건이 적재돼도 잡은 성공으로 끝나기 때문에, 양 기반 검사가 이런 침묵의 장애를 잡는 마지막 방어선입니다.

    7. 백필을 설계에 포함하라

    과거 데이터를 다시 적재하는 백필은 예외가 아니라 일상입니다. 처음부터 특정 기간을 지정해 재적재할 수 있도록 파라미터화하고, 백필이 운영 트래픽을 방해하지 않도록 자원을 분리하세요. 사후에 백필을 끼워 넣으면 항상 고통스럽습니다.

    품질은 마지막에 검사하는 것이 아니라 입구에서 설계하는 것이다. 쓰레기가 들어오면 쓰레기가 나간다.

    정리

    적재 품질의 핵심은 입구 검증, 멱등성, 불량 격리, 원본 보존, 메타데이터, 양·신선도 감시, 백필 설계입니다. 이 일곱 원칙은 화려하지 않지만, 하류의 수많은 복구 작업을 미리 막아주는 가장 효율적인 투자입니다. 파이프라인 품질은 결국 입구에서 결정됩니다.