사전 백필
개념

백필

gabury1고친 사람 github-actions[bot]

백필은 지나간 기간의 데이터를 뒤늦게 채워 넣는 작업입니다. 데이터를 모아 가공하는 작업은 평소에 새로 들어온 몫만 처리합니다. 백필은 비거나 틀린 과거 기간에 같은 처리를 다시 돌려 메웁니다. 데이터베이스에 새 열을 만든 뒤 기존 행에 값을 채우는 일도 같은 이름으로 부릅니다.

쉽고 빠른 이해

백필은 지난 날짜의 결과를 나중에 채우는 일입니다. 매일 밤 어제 하루 치 매출을 집계하는 작업을 오늘 처음 켰다고 합시다. 지난달 매출은 비어 있습니다.

왜 하나 — 매일 도는 작업은 새로 들어온 날짜만 봅니다. 작업을 새로 만들었거나 틀린 계산을 고쳤을 때 지나간 날짜는 아무도 다시 계산해 주지 않습니다.

어떻게 도나:

  1. 채울 기간을 고릅니다. 예를 들어 지난 30일입니다
  2. 평소에 돌던 작업을 그 기간의 날짜마다 한 번씩 돌립니다
  3. 각 실행이 그 날짜의 결과를 새로 채웁니다

무엇이 나빠지나 — 과거를 한꺼번에 다시 읽으니 시간이 걸립니다. 원본 데이터베이스도 그만큼 바빠집니다. 작업이 결과를 덮어쓰지 않고 덧붙이게 짜여 있으면 같은 날짜가 두 벌 쌓입니다.

상세

가계부를 이번 달부터 쓰기 시작했다고 합시다. 지난 석 달 치도 보고 싶으면 서랍 속 영수증을 꺼내 그 달 칸에 하나씩 옮겨 적습니다. 적는 방법은 이번 달과 같습니다. 날짜만 지난달입니다.

파이프라인은 데이터를 읽고 고치고 저장하는 단계를 차례로 이어 놓은 처리입니다. 원본에서 주문 기록을 읽어 날짜별 매출로 묶은 뒤 결과 테이블에 쓰는 처리가 한 예입니다.

백필은 이 파이프라인이 평소에 처리하지 않은 지난 기간을 골라 같은 처리를 다시 돌리는 작업입니다. 일별 매출 집계를 오늘 새로 만들었다면 지난 1년 치 날짜마다 집계를 한 번씩 돌려 결과 테이블을 채웁니다.

영어 backfill 은 파낸 구덩이를 흙으로 다시 메운다는 말입니다. 데이터에서는 비어 있는 과거 기간이 그 구덩이입니다.

정기 실행이 맡는 기간

백필은 파이프라인이 평소 하던 일을 날짜만 바꿔 되풀이합니다. 이 소절은 파이프라인이 평소에 어떻게 도는지부터 봅니다.

데이터 파이프라인은 대개 정해 둔 시각마다 실행됩니다. 매일 새벽에 한 번 돌아 어제 하루 치를 처리하는 식입니다. 이렇게 정해 둔 시각마다 도는 실행을 정기 실행이라고 합니다. 정기 실행 한 번이 맡는 기간은 하루로 정해져 있습니다.

결과 테이블도 날짜로 나눠 두는 경우가 많습니다. 커다란 테이블을 기준 값에 따라 여러 조각으로 나눴을 때 그 조각 하나를 파티션이라고 부릅니다. 날짜로 나눈 테이블이라면 하루 치 결과가 파티션 하나에 들어갑니다. 실행 한 번은 파티션 하나만 쓰고 끝납니다. 그러니 날짜끼리 서로 건드리지 않습니다.

실행 하나를 이루는 단계 하나하나가 태스크입니다. 태스크가 처리할 날짜를 인자로 받으면 같은 태스크를 어느 날짜로든 돌릴 수 있습니다. 백필은 이 성질에 기댑니다.

반대로 태스크 안에서 지금 시각을 읽으면 백필이 망가집니다. 태스크를 06-02(6월 2일)로 돌렸다고 합시다. 그런데 코드가 「어제」를 지금 시각에서 구하면 오늘 기준의 어제를 처리합니다. 처리할 날짜는 언제나 인자로 받아야 합니다.

flowchart TD
    S["정기 실행 · 어제 하루 치"] --> T["태스크 · 날짜 하나를 받아 처리"]
    B["백필 · 지난 날짜 목록"] --> T
    subgraph 결과 테이블
        P1["06-01 파티션"]
        P2["06-02 파티션"]
        P3["06-03 파티션 · 어제"]
    end
    T -->|정기 실행| P3
    T -->|백필| P1
    T -->|백필| P2

두 입구가 같은 태스크를 부릅니다. 정기 실행은 어제 파티션 하나를 채웁니다. 백필은 날짜 목록을 넘겨 그보다 앞선 파티션들을 채웁니다.

백필이 필요해지는 때

지난 기간이 비거나 틀리는 사정은 여럿입니다. 이 소절은 흔한 사정을 표로 모읍니다. 그 사정들이 어떻게 한 이름으로 묶이는지도 봅니다.

때 무엇이 비거나 틀렸나
파이프라인을 새로 만들었다 만든 날 이전의 결과가 하나도 없다
계산 로직의 버그를 고쳤다 고치기 전 날짜에 틀린 값이 남아 있다
결과에 새 열을 더했다 지난 날짜의 결과에는 그 열이 비어 있다
장애로 며칠 실행이 멈췄다 멈춘 동안의 날짜가 빠져 있다
원본 데이터가 늦게 도착했다 그 날짜를 처리할 때 원본이 모자랐다

파이프라인을 만들기 전의 날짜와 실행이 멈췄던 날짜는 결과가 아예 없습니다. 백필이 그 날짜의 파티션을 처음으로 채웁니다.

버그를 고쳤거나 원본이 늦게 온 날짜는 결과가 있지만 틀렸습니다. 원본이 늦게 온 날짜는 모자란 원본으로 계산했기 때문에 틀린 것입니다. 백필이 그 날짜의 파티션을 다시 계산해 덮어씁니다.

새 열을 더하기 전의 날짜도 같은 방법으로 채웁니다. 그 날짜의 파티션을 다시 계산하면 새 열까지 값이 들어갑니다.

어느 쪽이든 지난 날짜로 같은 처리를 돌린다는 점은 같습니다. 그래서 모두 백필입니다.

다시 돌려도 한 벌만 남는 태스크

백필은 이미 결과가 있는 날짜를 다시 돌리는 일이 잦습니다. 이 소절은 그때 결과가 두 벌 쌓이지 않으려면 태스크를 어떻게 짜야 하는지 코드로 봅니다. 두 코드에서 total(day) 는 그 날짜의 매출 합계를 구하는 함수입니다.

먼저 결과에 줄을 덧붙이는 태스크입니다.

Python
rows = []

def run(day):
    rows.append((day, total(day)))

run("06-02")      # 정기 실행
run("06-02")      # 백필로 한 번 더
len(rows)         # 2

같은 날짜로 두 번 돌자 06-02 의 줄이 둘이 됐습니다. 이 줄들로 그날 매출을 더하면 두 배로 잡힙니다. 한 번 반영될 결과가 두 번 쌓이는 이 고장을 중복 처리라고 부릅니다.

다음은 날짜를 키로 삼아 그 날짜의 값을 덮어쓰는 태스크입니다.

Python
sales = {}

def run(day):
    sales[day] = total(day)

run("06-02")      # 정기 실행
run("06-02")      # 백필로 한 번 더
len(sales)        # 1

몇 번을 돌려도 06-02 의 값은 하나입니다. 테이블이라면 그 날짜의 파티션을 비우고 새로 채우는 것이 이 코드에 해당합니다.

같은 일을 여러 번 해도 결과가 한 번 한 것과 같은 성질을 멱등성이라고 부릅니다. 두 번째 태스크는 멱등합니다. 첫 번째 태스크는 멱등하지 않습니다. 멱등하지 않은 태스크로 백필하려면 돌리기 전에 그 기간의 결과를 먼저 지워야 합니다.

여러 날을 한꺼번에 돌리는 방법

백필은 날짜 수만큼 실행이 생깁니다. 1년 치면 365번입니다. 이 소절은 그 많은 실행을 어떤 순서와 속도로 흘려보내는지 봅니다.

날짜끼리 서로 기대지 않으면 여러 날을 동시에 돌릴 수 있습니다. 동시에 많이 돌릴수록 빨리 끝납니다. 대신 원본 데이터베이스가 한꺼번에 많은 읽기를 받습니다.

원본이 사용자 요청을 받는 서비스의 데이터베이스라면 그 읽기가 사용자 요청을 느리게 만듭니다. 그래서 동시에 도는 실행 수에 상한을 둡니다.

앞 날짜의 결과에 기대는 계산은 순서대로 돌려야 합니다. 누적 가입자 수처럼 어제 값에 오늘 늘어난 수를 더하는 집계가 그렇습니다. 06-02 를 고치면 그 뒤 날짜의 누적값도 모두 다시 계산해야 합니다.

태스크를 순서대로 띄우고 실패를 지켜보는 프로그램이 오케스트레이션 도구입니다. 이런 도구에는 흔히 백필 명령이 따로 있습니다. 시작 날짜와 끝 날짜를 주면 날짜마다 실행을 하나씩 만듭니다. 그 실행들을 정해 준 동시 실행 수와 순서에 맞춰 돌립니다.

테이블 열을 채우는 백필

데이터베이스를 다루는 쪽에서도 같은 이름을 씁니다. 이 소절은 테이블에 새 열을 만들었을 때 기존 행을 채우는 백필을 봅니다.

테이블에 새 열을 더하면 이미 있던 행에는 그 열의 값이 없습니다. 새로 들어오는 행은 애플리케이션이 값을 넣습니다. 기존 행은 누군가 따로 채워야 합니다. 이 채우는 작업도 백필입니다.

데이터베이스는 고치는 행에 락을 걸어 다른 쓰기가 끼어들지 못하게 막습니다. 수백만 행을 한 번에 고치면 그 락을 오래 잡습니다. 그동안 같은 행을 쓰려는 다른 요청은 기다립니다. 그러니 행을 작은 묶음으로 나눠 조금씩 고칩니다.

테이블 구조를 바꾸는 작업이 스키마 마이그레이션입니다. 열 백필은 흔히 그 가운데 한 단계로 들어갑니다. 순서는 대개 이렇습니다.

  1. 값이 비어도 되는 열로 먼저 만듭니다
  2. 애플리케이션이 새 행에 그 열의 값을 넣기 시작합니다
  3. 기존 행을 묶음으로 나눠 채웁니다. 이것이 백필입니다
  4. 다 채운 뒤에 「비어 있으면 안 된다」는 제약을 겁니다

넷째를 먼저 하면 아직 안 채운 기존 행이 그 제약에 걸립니다. 그래서 백필이 제약보다 앞에 섭니다.

백필과 헷갈리는 처리 방식

지난 데이터를 다시 다루는 일은 이름이 여럿입니다. 무엇을 처리하는지와 언제 돌리는지로 셋을 가르면 이렇습니다.

이름 무엇을 처리하나 언제 돌리나
재시도 방금 실패한 실행 하나 실패 직후에 자동으로
백필 사람이 고른 지난 기간 파이프라인을 만들거나 고친 뒤에
증분 처리 지난 실행 뒤에 새로 들어온 데이터 정기 실행마다

재시도는 실패한 실행을 되살립니다. 백필은 이미 성공한 날짜까지 일부러 다시 돌릴 수 있습니다.

증분 처리는 정기 실행의 방식입니다. 새로 들어온 것만 보니 빠릅니다. 그 대신 지나간 기간은 다시 보지 않습니다. 백필은 증분 처리가 지나쳐 간 기간을 메웁니다.

관련 항목

백필이 과거 날짜로 다시 돌리는 처리

파이프라인 · 데이터 파이프라인 · 태스크 · 워크플로 · DAG · 배치 처리 · ETL · ELT

백필이 채우는 저장 구조

파티션 · 파티셔닝 · 테이블 · 열 · 행 · 데이터 웨어하우스

백필을 안전하게 만드는 성질과 기법

멱등성 · 결정성 · UPSERT · 트랜잭션

백필이 잘못 돌 때 나는 장애

중복 처리 · 중복 적재 · 과부하 · 락 경합

백필을 띄우고 지켜보는 도구

오케스트레이션 · Apache Airflow · Dagster · 크론

백필과 맞세워지는 처리 방식

재시도 · 재처리 · 증분 처리 · 스트리밍 처리

백필을 부르는 데이터 사정

지연 도착 데이터 · 데이터 품질 · 데이터 계보 · 장애 복구

열 백필이 끼는 스키마 변경

스키마 마이그레이션 · 스키마 진화 · 확장과 축소 · 온라인 스키마 변경 · ALTER TABLE

백필을 다루는 분야와 역할

데이터 엔지니어링 · 데이터 엔지니어 · 분석 엔지니어링 · 데이터 플랫폼

다른 이름: backfill · backfilling · 소급 적재