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

content-addressed identity

~11 min · content-addressing, identity, at-most-once, hashing

Level 0Empty Shelf
0 XP0/35 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"같은 오디오, 같은 설정은 같은 구매야. 돈은 한 번 들어야 해."

두 호출을 '같다' 고 만드는 건 뭐야?

지난 레슨의 예약 ledger 는 두 호출이 같은 호출이라는 걸 알아볼 수 있어야만 이중 지출을 막아. 그래서 유료 호출의 identity 는 진짜 신경 써서 골라야 하고. 뻔한 선택지들이 왜 안 되는지부터 보자.

  • 파일명 — 오디오가 그대로인데 파일이 이름 바뀌거나 옮겨질 수 있고, 다른 두 파일이 이름을 공유할 수 있어. 파일명은 콘텐츠가 아냐.
  • 랜덤 request id — 시도할 때마다 새로 생기니까, 같은 호출을 재시도해도 새 id 를 받아 완전히 새것처럼 보여. 이중 결제를 막기는커녕 보장하는 셈이야.
  • 타임스탬프 — 매번 다르니까 랜덤 id 랑 똑같이 실패해.

하나같이 같은 오디오를 두 번 결제하게 놔두는 것들이야. identity 는 실제로 비용과 결과를 결정하는 데서 나와야 해. 바로 콘텐츠에서.

identity 는 콘텐츠 + config 의 hash 야

Recall 의 유료 호출 identity 는 hash 한 쌍이야: 보내는 정확한 오디오 chunk 의 SHA-256, 그리고 정확한 provider 설정의 SHA-256. 같은 설정 아래 같은 오디오 바이트는 같은 hash 를 내고, 그게 같은 identity 가 돼. 그래서 재시도가 이미 있는 ledger 행에 착지해서 완료된 걸 찾고, 다시 결제하는 대신 저장된 응답을 재사용해. identity 당 한 번만 결제하는 게 이름이나 시계가 아니라 콘텐츠로 보장되는 거지.

그럼 config 는 왜 identity 에 들어갈까? 같은 오디오라도 다른 model 이나 다른 설정으로 전사하면 진짜 다른 호출이거든. 다른 증거가 나오고, 돈이 또 드는 것도 정당하고. config hash 를 key 에 접어 넣으면 '같은 오디오, 같은 config' 는 유료 identity 하나고, '같은 오디오, 새 config' 는 제대로 새것이 돼. identity 에는 출력을 결정하는 것만 정확히 담기는 거야. 바이트와 설정, 그 외에는 아무것도.

content-addressing, 이제 돈을 위해

content-addressing 은 트랙 3 에서 이미 만났어. release 의 content hash 로 요약이 stale 인지 감지하던 그거. 이번엔 같은 아이디어를 지출에 겨눈 거고. identity 가 콘텐츠에서 나오면 '이미 했나?' 가 추측이 아니라 조회가 돼. 입력을 hash 하고 ledger 를 확인하면 완료된 작업을 찾거나 못 찾거나 둘 중 하나야. 사람이 붙인 라벨이나 시계가 찍은 값 대신 콘텐츠로 이름을 지으면, '두 번 결제 안 함' 이 희망 섞인 관례에서 기계가 보장하는 것으로 바뀌어.

Code

콘텐츠 + config 에서 identity, ledger 대조·python
import hashlib

def paid_identity(audio_chunk: bytes, config: dict) -> tuple[str, str]:
    chunk_hash = hashlib.sha256(audio_chunk).hexdigest()
    config_hash = hashlib.sha256(canonical_json(config)).hexdigest()
    return (chunk_hash, config_hash)   # 유료 호출 key

def reserve(audio_chunk, config):
    key = paid_identity(audio_chunk, config)
    existing = ledger.find(key)
    if existing and existing.status == 'completed':
        return existing.response      # 이미 결제됨 — 재사용, POST 안 함
    return ledger.create_reservation(key)  # 새 identity — 예약

# 같은 바이트 + 같은 config -> 같은 key -> 최대 한 번 결제
# 같은 바이트 + 새 config  -> 새 key  -> 정당하게 새 호출

External links

Exercise

네 일에서 실수로 두 번 돌 수 있는, 비싸거나 부작용 있는 작업을 찾아봐. 유료 API 호출, 무거운 계산, 이메일 같은 거. 그리고 물어봐. 지금 그 identity 가 뭐야? 파일명이나 랜덤 id 나 타임스탬프라면, 결과와 비용을 실제로 결정하는 입력을 나열해. 그 입력에서 content-addressed key 를 설계하고, '이미 했나?' 체크가 그걸 어떻게 쓸지 설명해봐.
Hint
key 는 사고 실험 두 개로 테스트해. 하나, 똑같은 작업을 재시도하면 key 가 그대로라서 재시도가 no-op 이 돼? 둘, 진짜 다른 입력이 들어와서 결과나 가격이 바뀌면 key 도 바뀌어서 제대로 새 작업으로 다뤄져? 좋은 identity 는 둘 다 '그렇다' 야. 보통은 비용을 결정하는 입력을 전부 hash 하고, 그 외에는 아무것도 안 넣으면 돼.

Progress

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

댓글 0

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

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