LabHub

데이터 파이프라인 · 멱등성과 재처리 · 이론

멱등성 — 파이프라인은 반드시 다시 돌게 된다

LabHub 에서 이어서 보기

한 줄 요약

파이프라인은 실패하고, 실패하면 다시 돌리며, 그때 결과가 달라지면 데이터가 오염되므로, 재실행 안전성은 선택이 아니라 설계의 전제다.

왜 이게 필요했나

배치가 새벽에 실패했다고 하자. 아침에 다시 돌린다. 그런데 실패 지점이 적재 중간이었다면 일부는 이미 들어가 있다. 그대로 다시 넣으면 중복이 생기고, 통째로 지우고 다시 넣으면 그 사이 들어온 다른 데이터까지 날아간다.

이 상황을 매번 사람이 판단하게 두면 언젠가 실수가 난다. 애초에 몇 번을 넣어도 같은 결과가 되도록 만드는 편이 낫다.

어떻게 동작하나

멱등성의 출발점은 자연 키다. 각 행을 유일하게 식별하는 값이 있어야 "이미 들어온 것"을 알아볼 수 있다. 전표 번호, 주문 번호, 이벤트 ID 같은 것이다. 이 값에 유일 제약을 걸면 데이터베이스가 중복을 대신 막아 준다.

그다음이 upsert 다.

INSERT INTO orders_final (order_ref, amount, status, content_hash)SELECT ...ON CONFLICT (order_ref) DO UPDATE  SET amount = EXCLUDED.amount,      status = EXCLUDED.status,      content_hash = EXCLUDED.content_hash,      updated_at = now()  WHERE orders_final.content_hash IS DISTINCT FROM EXCLUDED.content_hash;

마지막 WHERE 절이 중요하다. 이것이 없으면 내용이 하나도 안 바뀐 재실행에서도 모든 행의 updated_at 이 갱신된다. 그러면 "무엇이 실제로 바뀌었는가"를 알 수 없게 되고, 하류에서 변경분만 가져가는 증분 소비도 망가진다.

내용 해시를 두면 비교가 간단해진다. 값들을 정해진 순서로 이어 붙여 해시를 계산하고, 그 값이 다를 때만 갱신한다. 컬럼이 많아져도 비교 로직이 한 줄로 유지된다.

중복 제거도 필요하다. 같은 전표가 두 번 적재되었다면 어느 쪽을 남길지 규칙을 정해야 한다. 보통 나중에 들어온 것을 남긴다. 원본에 적재 순서를 나타내는 증가 키가 있으면 전표별로 최대값 행만 고르면 된다.

현장에서 만나는 모습

실행 로그를 남기는 것이 큰 도움이 된다. 실행마다 삽입 건수와 갱신 건수를 기록해 두면, 아무것도 바뀌지 않은 실행은 둘 다 0 으로 남고 늦게 도착한 변경이 반영된 실행은 갱신 건수가 올라간다. 이 두 숫자만 봐도 파이프라인이 정상인지, 원천에 이상이 있는지 판단할 수 있다.

그리고 재시도 코드 안에는 데이터베이스 작업만 넣어야 한다. 메일 발송이나 외부 API 호출이 섞여 있으면 재시도할 때마다 그 부수 효과가 반복된다. 외부 호출이 필요하다면 그쪽도 멱등성 키를 받는 방식이어야 한다.

다음 실습에서 할 것

자연 키에 기본 키를 걸고, 중복 전표를 제거하고, 내용 해시로 변경 여부를 판단하는 upsert 를 만든다. 그리고 아무것도 바뀌지 않은 재실행과 한 건만 바뀐 재실행이 각각 어떻게 기록되는지 확인한다.