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

Lock 과 Idempotency

~10 min · locks, idempotency, retries, verify-separately

Level 0Lone Machine
0 XP0/37 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"여러 기계에 걸친 작업에서 '두 번 돌았다' 는 드문 버그가 아니라 일상이야. 두 번이 한 번이 되게 설계해."

retry 는 평범한 날씨

명령 도중에 연결이 끊겨. worker 가 재시작하고 큐를 다시 집어. spinner 가 멈춘 것 같아서 사람이 버튼을 또 눌러. 이 중 어느 것도 edge case 가 아냐. 네트워크를 건너는 작업이면 다 겪는 일이야. operation 이 정확히 한 번 돌 때만 맞으면, 안 맞는 거야.

per-host lock: 기계 하나에 한 번에 mutation 하나

per-host mutation lock 은 두 operation 이 같은 Mac 에 동시에 손 못 대게 해. 업데이트랑 재부팅이 한 기계에서 뒤엉키면 안 되니까. 결정적으로 lock 은 전체 fleet 이 아니라 host 에 걸려. 그래서 독립된 기계들은 여전히 병렬로 돌아. 세상 전체가 아니라 부딪치는 지점만 줄 세우는 거야.

idempotency key: 같은 요청 두 번이 효과 하나

mutating 요청마다 idempotency key 를 달아. executor 는 이미 적용한 key 를 기억해. 그래서 다시 온 요청은, reconnect 든 retry 든 double-click 이든, 또 하는 대신 첫 결과를 돌려줘. key 하나에 효과 하나. 요청이 몇 번 도착하든.

exit code 랑 따로 verify 할 수 있는 명령을 골라

exit code 는 거짓말할 수 있어. 명령이 이미 성공한 뒤 timeout 날 수도, 진짜 효과는 안 났는데 0 을 돌려줄 수도 있어. 그러니 성공을 따로 확인할 수 있는 operation 을 골라. 재시작 뒤엔 SSH 가 0 을 돌려줬다고 믿지 마. 서비스가 loaded 됐고 last-run 타임스탬프가 전진했는지 확인해. 반환값 말고 세상을 verify 해.

다시 돌아도 안전하게 만들고, 그다음 retry 를 안 무서워해. per-host lock 은 두 operation 이 부딪치는 걸 막고, idempotency key 는 한 operation 이 두 번 세는 걸 막아. 둘이 같이 있으면 '또 돌았네' 가 큰일이 아니라 그냥 넘어갈 일이 돼.

Code

host 를 lock, request 에 key·python
request = {
    "op": "restart_service",
    "host": "server",
    "idempotency_key": "op_7f3a:server:restart",   # 의도한 효과마다 stable
}

with per_host_lock("server"):                 # 이 host 에 한 번에 mutation 하나
    if executor.already_applied(request["idempotency_key"]):
        return executor.first_result(request["idempotency_key"])   # 다시 온 거 -> no-op
    result = executor.apply(request)
    executor.remember(request["idempotency_key"], result)

# 끊긴 연결 + retry 가 이제 재시작 하나를 내지, 둘이 아냐.
# lock 은 같은 Mac 에서 동시 재부팅이 뒤엉키는 걸 막아.
# 독립 host 는 독립 lock 을 쥐어서, fleet 은 여전히 넓게 돌아.

External links

Exercise

두 번 돌면 나쁠 행동을 잡아. 카드 청구, 이메일 발송, 기계 재부팅 같은 거. 거기에 idempotency key 를 설계해. 뭐가 두 요청을 '같은 요청' 으로 만들어? 그다음 명령의 exit code 를 안 믿고 효과가 진짜 났는지 verify 할 방법을 하나 대봐.
Hint
좋은 key 는 순간이 아니라 의도한 효과를 담아. 'operation op_7f3a 를 위해 host server 재부팅' 은 retry 를 건너도 stable 해. '09:03:11.442 에 재부팅' 은 아니고. retry 는 새 타임스탬프를 달고 오니까 새 요청처럼 보이는데, 그게 딱 그 버그야.

Progress

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

댓글 0

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

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