티스토리 뷰

1. 왜 더 자주 돌리려 하나

지금 Silver는 일배치(하루 1번)다.

근데 대시보드 운영자는 더 신선한 데이터를 보고 싶어한다. 어제 숫자만 보이면 답답하니까. (내가 그랬다)

그래서 Silver를 15분 (또는 더 잘게)으로 당기는 작업을 했다.

참고: Bronze는 이미 60초 스트리밍이라 raw는 실시간에 가깝다. 신선도 병목은 Silver/Gold 배치라서 거기를 당기는 거다.

2. 빈도를 올리면 "스케줄만" 바꾸는게 끝이 아니었다.

`@daily → */15`로 한줄 바꾸면 될줄 알았지만, 3개의 레버가 같이 움직이는 거라 아니었다.

레버 일배치 15분
스케줄 @daily `*/15 * * * *`
읽는 범위 dt >= 오늘 - 7일 최근 N시간만(incremental) ← 안 바꾸면 매시간 7일 다시 읽어 낭비
쓰기 모드 COW COW 유지 (스케일 커질 시 MOR 고려)
compaction - 이미 인라인 self-throttle(지난 작업)
expire 7일 보존 2일로 단축 (스냅샷 폭증)

3. 결정 ① - incremental 읽기 (ingested_at 기준)

매 실행 7일 재독은 낭비다.

그래서 `--lookback-hours`를 추가해서 Bronze를 `ingested_at`(적재시각) 최근 N 시간만 읽게 했다.

if lookback_hours is not None:
    df = df.where(F.col("ingested_at") >= F.expr(f"current_timestamp() - INTERVAL {N} HOURS"))
else:
    df = df.where(F.col("dt") >= ...)   # 기존 sliding 유지

 

lookback 관련 보충 설명

`--lookback-hours 3` = "지금 기준 최근 3시간 안에 적재된 것만 읽어라"

그니까 얼마나 거슬러 읽을지의 범위인것이다.

 

왜쓰냐? 자주 돌릴 때 매번 전체를 다시 읽는 낭비를 막기위해서 사용한다.

만약 lookback 없이 15분마다 7일치를 읽으면 아래와 같은 상황이 발생하게 된다.

12:00 run → 7일치(280만) 처리
12:15 run → 또 7일치(280만) 처리 ← 방금 한 거 또 함 (낭비) 하루 96번 = 같은 280만을 96번 재처리

그니까 이미 처리한 옛날 데이터를 매번 다시 MERGE하느라 느리고 낭비인거다. 자주 돌리는 의미가 희석된다.

 

'그래서 지난 사이 새로 들어온 것만' = 최근N시간 적재분만 읽는다. 각 run이 작아져서 빨라지고 15분 안에 여유있게 끝난다.

 

그래서 왜 lookback을 스케줄 간격(15분)보다 크게(3h)?

딱 15분으로 하면 run이 한 번 밀리거나 데이터가 좀 늦게 도착했을 때 그 사이 적재분을 놓친다(틈 생김).

그래서 간격보다 넉넉히(3h) 잡아 매 run이 이전 걸 좀 겹쳐 읽게 한다.

그니까 아래와 같은 상황이 있을 수 있다는 것이다.

12:00 run → 09:00~12:00 읽음 ┐ 09:15~12:00은 둘 다 읽음(겹침)
12:15 run → 09:15~12:15 읽음 ┘ → run 밀려도/데이터 늦어도 안 놓침

 

겹쳐 읽으면 중복 아닌가 싶겠지만 MERGE가 멱등하게 되기 때문에 이미 처이된건 no-op(처리 안함)

그래서 겹쳐도 결과가 똑같다. 

4. 결정 ② - 쓰기는 COW 유지 

=> 우선은 COW로 개발하였지만,, 사실 많은 데이터가 있는 것을 가정하기 때문에 MOR 로 전환을 해야한다..
다만 우선 아직 개발하지 못해서 문서로만 남겨둘 예정이다.

5. 결정 ③ - expire 보존 단축 (고빈도 부작용)

15분 x (MERGE + compaction)이면 스냅샷이 하루 수백 개 쌓인다.

그래서 GC DAG의 expire 보존을 7일 → 2일로 줄였다.

(time-travel 창도 2일로 줄지만, 백필은 raw 재처리라 무관)

 

과거를 다루는 두 가지 방법

과거로 돌아가는 걸 2일로 줄였으면, 옛날 데이터는 못고치는거 아닌가 싶었다.

근데 알고 보니 과거 데이터를 다루는 방법에 대한 정확한 이해가 없어 헷갈린거였다.

방법 개념 무엇에 의존 한계
time-travel / rollback 테이블을 과거 버전으로 보거나
되돌리기
스냅샷(버전 기록) 보존기간만큼만 (지금은 2일)
backfill Bronze raw를 다시 읽어 Silver를
새로 만들기
Bronze raw (영구 보존) 무제한 (raw가 살아있으니 3개월 전도 OK)

 

위에 보면 아래와 같은 문장이 있다.

(time-travel 창도 2일로 줄지만, 백필은 raw 재처리라 무관)

 

"time-travel 창도 2일로 줄지만"

  • expire 보존을 7일 → 2일로 줄였으니, 그냅샷이 2일치만 남는다.
  • 스냅샷이 time-travel의 재료니까 → "2일 전까지만"과거 조회, 롤백 가능 (7일전은 이제 못봄)

"백필은 raw 재처리라 무관"

  • 근데 3개월전 데이터를 고쳐야 할 때 우리가 쓰는건 time-travel이 아니다.
  • 백필 = Bronze raw (3개월 전 것도 영구 보존됨)를 다시 읽어 → 고친 Silver 로직으로 → 다시 만든다.
  • → 스냅샷이 2일치만 있어도, Bronze raw가 살아 있으니 3개월 전이든 재생성 가능

6. 덤 - DAG 이름을 고쳤다 (`silver_processed` → `medallion`)

작업하다 보니 이름이 실제 DAG 구조와 안 맞았다.

`silver_processed`라는 DAG가 사실은 silver + gold + 양쪽 compaction = 메달리온 변환 전체를 돌고있었다.

medallion DAG:
  silver_merge >> gold_aggregate >> compact_gold
  silver_merge >> compact_silver

 

gold를 분리할까 고민했는데 굳이 라는 생각이 들었다.

gold는 silver 직후 같은 DAG에서 유기적으로 바로 갱신된다.

대시보드가 Gold를 읽으니 Gold도 15분 신선해야 맞다(분리 하면 cross-DAG 의존성만 복잡해진다)

그래서 한 DAG유지하고 이름만 `medallion`으로 정정했다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/07   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함