본문 바로가기
C.W.K.
Stream
Lesson 04 of 04 · published

원본과 그 사본

~12 min · storage, architecture, records, design

Level 0젖은 흙
0 XP0/38 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

모양 둘을 원하는데 믿을 수 있는 건 하나

작업 단위마다 하나씩 두는 추가 전용 파일은 아름다운 기록이야. 단일 기록자가 덧붙이기를 전부 직렬화하니까 남의 레코드가 반쯤 쓰이다 만 것 때문에 망가질 일이 없고, 대상 둘이 같은 파일을 안 건드리니까 충돌 없이 병합되고, 아무거나로 읽히고, 이력이 곧 내용이야. 그리고 네가 실제로 던지는 질문엔 쓸모가 없어. 지난달에 이 종류 패스가 몇 번 돌았나, 검증이 없는 단위가 뭐냐, 이 시스템이 코퍼스 전체에서 뭘 내놨나.

관계형 저장소는 그걸 전부 즉시 답하고 기록으로는 훨씬 나빠. 그래서 둘 다 두고, 설계 전체가 미리 내린 결정 하나에 얹혀. 파일이 기록이고, 저장소는 파생된 사본이다.

미리 선언하는 게 요령의 전부인 이유

같은 사실을 담은 저장소 둘은 결국 어긋나. 한쪽에선 성공하고 한쪽에선 실패한 쓰기, 열을 떨군 스키마 이관, 낡은 사본에 대고 돈 재구축. 어긋남 자체가 비상은 아냐. 비상은 어느 쪽을 믿어야 하는지 아무도 모른다는 걸 사건 한복판에서, 지금 결정이 필요한 상황에 발견하는 거야.

권위를 미리 선언하면 그 비상이 작업으로 바뀌어. 기록에서 사본을 다시 지어. 십 분, 판단할 것 없음, 데이터 손실 불가능. 사본은 기록에 없는 걸 담은 적이 없으니까.

따라 나오는 규칙. 기록에서 유도 안 되는 건 사본에 절대 안 쓴다. 누가 저장소에만 있는 편리한 열을 하나 더하는 순간, 사본은 두 번째 기록이 됐고 재구축은 이제 파괴적이야.

이걸 싸게 만드는 배치 선택들

큰 파일 하나 대신 대상마다 파일 하나. 그래야 망가진 파일이 대상 하나의 이력만 다치고 끝나. 사주는 건 이거야. 작업 단위는 위임이고, 한 대상에 위임 여럿이 붙으면 파일을 같이 쓰니까, 병렬 작업은 여전히 같은 자리에 떨어지고 덧붙이기 자체가 안전해야 해. 줄바꿈으로 구분되는 레코드. 그래야 덧붙이기가 쓰기 한 번이고 읽기가 흘려보내기 가능해. 그리고 멱등한 재구축. 그래야 헷갈리는 사람 누구나 아무 때나 돌릴 수 있어. 사람들이 무서워하는 수리 작업은 안 돌아가는 작업이거든.

셋 다 같은 성질을 사고 있어. 뭔가 잘못됐을 때 손해 범위가 미리 정해져 있다는 것. 파일 하나가 망가져도 한 단위, 사본이 어긋나도 재구축 한 번, 쓰기가 반쯤 끊겨도 마지막 줄 하나. 저장 설계에서 고를 값어치가 있는 건 대개 제일 빠른 쪽이 아니라 최악의 경우가 제일 작은 쪽이야.

같은 사실을 두 군데 둘 때는, 알아야 할 일이 생기기 전에 어느 쪽이 권위 있는지 적어둬. 그 결정은 오늘 거의 공짜고 사건 중엔 거의 불가능해. 그때쯤이면 양쪽 다 그럴듯한 데이터를 갖고 있고 누군가 기다리고 있으니까.

Code

기록, 사본, 그리고 둘을 맞추는 작업·bash
# GROUND TRUTH - one newline-delimited file per SUBJECT.
# Appending is one write, and a corrupted file costs one
# subject's history rather than everything. Note what it does
# NOT buy: the unit of work is the delegation, and several
# delegations against one subject share a file - so the append
# still has to be safe on its own.

  <data-dir>/logs/<subject>.jsonl
    {"ts":"...","event":"claimed","by":"...","pipeline":"create"}
    {"ts":"...","event":"stage_done","stage":"sweep","note":"..."}
    {"ts":"...","event":"review_done","verdict":"blocked", ...}
    {"ts":"...","event":"verified","passed":true, ...}
    {"ts":"...","event":"landed","commit":"...", ...}

# MIRROR - a relational store, rebuilt from the files. Answers
# the questions the files cannot: counts, joins, "which units
# have no verification", "what did this system produce".

# THE OPERATION - available to anyone, any time, idempotent.
  $ <tool> admin rebuild-log-mirror
  read 1,284 records from 82 files -> mirror rebuilt

# Because the mirror holds NOTHING that is not derivable from
# the files, this is never destructive and never needs a
# judgment call. The moment somebody adds a column that exists
# only in the mirror, that stops being true - and the rebuild
# quietly becomes a data-loss operation.

External links

Exercise

네 시스템에서 같은 사실을 담고 있는 자리 둘을 찾아봐. 캐시랑 그 출처, 검색 색인이랑 데이터베이스, 보고용 테이블이랑 그 뒤의 거래 기록. 쌍마다 어느 쪽이 권위 있고 다른 쪽을 어떻게 다시 지을지 적어. 둘 중 어느 답이든 한 문장을 넘어가면, 네 다음 헷갈리는 사건을 만들 쌍을 찾은 거야.
Hint
티가 나는 건 둘 중 한쪽에만 있는 필드야. 거기 두는 게 편해서 추가됐고, 그게 있다는 건 파생 저장소가 더 이상 순수하게 파생이 아니라는 뜻이지. 그러니 네가 믿고 있던 재구축이 조용히 아무도 시험 안 해본 데이터 손실 작업이 돼 있는 거야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.