Skip to content

[Store] Carry upstream #4180: centralize client session lifecycle and resource ownership - #20

Closed
Juhyun-Kim-Memphis wants to merge 1 commit into
our_mainfrom
inf-522/carry-4180
Closed

Juhyun-Kim-Memphis wants to merge 1 commit into
our_mainfrom
inf-522/carry-4180

Conversation

@Juhyun-Kim-Memphis

@Juhyun-Kim-Memphis Juhyun-Kim-Memphis commented Sep 21, 2026 •

Copy link
Copy Markdown
Collaborator

upstream PR kvcache-ai/Mooncake#4180 (아직 열려 있음)을 our_main 위에 net diff 커밋 하나로 얹는다. #15 와 같은 방식이다. INF-522 의 P3 단계이며, 병합은 rig 판정 뒤 P5 에서 한다. 그 전까지 이 PR 은 draft 로 둔다.

kvcache-ai#4180 이 바꾸는 것

  • 클라이언트 세션을 새 ClientSessionRegistry 가 소유한다. 클라이언트마다 슬롯이 있고, 슬롯마다 admission gate 와 shared/exclusive operation_mutex 가 있다. 세션 만료도 registry 의 자체 스레드가 처리한다.
  • 상태 전이 이벤트는 새 ClientSessionEventDispatcher 가 registry 잠금 밖의 별도 스레드에서 전달한다.
  • MasterService 에서 client_mutex_, ok_client_, client_liveness_records_, ClientMonitorFunc 가 빠진다.
  • ClientLivenessRecord 에서 ServingGuard·RetainingGuard·ObserveAndRun 이 빠지므로, 레코드별 잠금은 O(1) 작업 동안만 잡힌다.
  • 그 결과 Ping 은 더 이상 master 전역 client_mutex_ 나 레코드별 잠금을 오래 기다리지 않는다. 경로는 registry 의 shared 잠금으로 슬롯을 찾고, Observe 한 뒤, remount_completed 를 확인하는 것뿐이다.
  • 스레드 격리는 하지 않는다. rpc_service 는 그대로이고, heartbeat 가 데이터 경로와 같은 RPC 스레드를 쓰는 문제는 #4183 의 몫이다. 그건 별도 이슈로 다룬다.

왜 upstream 병합 전에 들고 오는가

sync(#17)로 upstream #2991(2단계 liveness)이 our_main 에 들어왔다. kvcache-ai#2991 은 Ping 이 레코드별 잠금과 client_mutex_ 를 기다리게 만드는 지점을 추가한다. INF-504 rig(키 1,800만 개)에서, 폭풍 중 이런 잠금 의존이 heartbeat 를 멈추게 하면 정상 클라이언트가 OFFLINE 으로 오판되고 그 클라이언트의 키가 대량 삭제되는 것을 확인했다. kvcache-ai#4180 이 그 잠금 의존을 없앤다.

그래서 kvcache-ai#2991 은 있고 kvcache-ai#4180 은 없는 master 는 절대 롤하지 않는다. 이 규칙은 INF-522 의 magma PR 에서 research/mooncake/README.md Constraints 로 고정한다. 다음 이미지 빌드(INF-522 P6)가 이 PR 병합 뒤의 our_main 에서 나오도록 순서를 잡았다. 자세한 배경은 INF-507 과 INF-522 에 있다.

무엇을 얹었나

재검증 방침

upstream head 는 아직 움직이는 중이다(2026-09-21 하루에만 커밋 5개). 그래서 P5 에서 병합하기 직전에 다음을 한다.

  1. [Store] Centralize client session lifecycle and resource ownership kvcache-ai/Mooncake#4180 의 최신 head 를 다시 확인한다. upstream 이 먼저 병합했다면 이 carry 대신 그 merge commit 까지 두 번째 sync 를 한다.
  2. head 가 바뀌었다면 최신 head 로 이 커밋을 다시 만들고, unit gate 와 폭풍 rig 를 다시 돌린다.
  3. 재검증 도중 head 가 또 바뀌면, 검증을 마친 head 로 병합하고 그 사실을 이 PR 에 기록한다.

검증 결과

로컬 unit gate: PASS. magma oss/build/mooncake/Dockerfile.unittest(INF-522 확장판, MAX_JOBS=3 만 변경)를 Mac Docker(linux/amd64, ubuntu 24.04 / GCC 13)에서 실행했다. w-0529 가 다른 캠페인에 점유되어 있어 클러스터 Job 대신 로컬에서 돌렸고, #16~#19 와 같은 방식이다.

  • attest commit 36e3cc2cc953dde26d95c0a08a0e6243238db67e, 2026-09-21 10:13:07Z → 10:33:56Z = 20분 49초 (컴파일 781초, 테스트 331초)
  • [unit-gate] suites: 줄에서 [Store] Centralize client session lifecycle and resource ownership kvcache-ai/Mooncake#4180 의 client_session_* 세 suite 가 자동으로 선택된 것을 확인했다.
  • 12개 suite 100% 통과: client_session_registry_test 36, client_session_event_dispatcher_test 5, client_session_expiry_test 11, client_liveness_test 4, master_heartbeat_metric_test 14, master_service_test 63, master_service_config_test 7, master_service_ssd_test 7, promotion_on_hit_test 55, rpc_timeout_test 8, segment_test 25, file_storage_test 26 (숫자는 테스트 케이스 수). 재시도 없이 한 번에 통과했다.
  • 우리 carry patch 와의 통합 문제로 고친 것은 없다.

fork CI(ci.yml 수동 실행): https://github.com/vessl-ai/Mooncake/actions/runs/35587571670 — 결과는 아래 댓글로 덧붙인다. Check code format 은 workflow_dispatch 에 base branch 가 없어서 매번 실패하고, 그 때문에 wheel job 들은 skip 된다(#17 과 같다).

rig 검증은 아직이다. 폭풍 rig 판정(INF-522 P4)이 나온 뒤 P5 에서 병합 여부를 정한다.

Upstream: kvcache-ai#4180

…ecycle and resource ownership

Net diff of upstream kvcache-ai#4180 (still open) at head
9a698e0, squashed onto our_main.
Its base 31dedeb and the upstream main it merged are ancestors of
our_main, so this commit carries only the PR's own changes. Applied
cleanly with no conflicts.

Upstream commits (oldest first):
  74ea924 [Store] Centralize client session lifecycle and resource ownership
  7204b80 Merge origin/main and adapt session tests to MasterServiceTestPeer
  2f83731 [Store] Isolate client session operations in per-client slots
  2fc6b3d Merge origin/main and preserve session checks with offload metrics
  30fc9ed [Store] Fix snapshot test helper formatting
  1655ced [Store] Keep client heartbeats independent of session admission
  37e8a0e [Store] Split client session ownership from transition delivery
  4da335a [Store] Format session test call sites with clang-format 20
  a634363 [Store] Let the session registry act on the transitions it causes
  fc3cf7e [Store] Keep the atomic session state buildable on GCC 11
  9a698e0 [Store] Bind the ping loop's client id by reference

Upstream: kvcache-ai#4180
@Juhyun-Kim-Memphis Juhyun-Kim-Memphis added upstream:open upstream PR 제출됨 (열림) store labels Sep 21, 2026
@Juhyun-Kim-Memphis Juhyun-Kim-Memphis self-assigned this Sep 21, 2026
@Juhyun-Kim-Memphis

Copy link
Copy Markdown
Collaborator Author

fork CI(ci.yml 수동 실행) 결과: https://github.com/vessl-ai/Mooncake/actions/runs/35587571670

  • CTest unit tests (Python 3.12): 성공 — 222개 중 222개 통과 (10:14Z → 11:05Z)
  • build-flags, Sphinx docs, Ruff, Typos, CI 스크립트 검사: 모두 성공
  • Check code format 실패 → CI Gate 실패: 원인은 Base branch '' not found 이다. workflow_dispatch 에는 base branch 가 없어서 매번 나는 실패이고 코드와 무관하다(Merge upstream main (7faef38b) into our_main #17 에서도 같았다). 그 때문에 wheel job 들은 skip 됐다.

@Juhyun-Kim-Memphis

Copy link
Copy Markdown
Collaborator Author

P5 판정: 병합 보류 (사람이 결정)

rig 합격 기준은 "B(sync + kvcache-ai#4180)의 모든 폭풍 실행에서 OFFLINE 0건"이었고, 이 기준을 통과하지 못했습니다. 그래서 이 PR은 draft로 두고 병합하지 않습니다. 병합 여부는 사람이 결정합니다.

  • [Store] Centralize client session lifecycle and resource ownership kvcache-ai/Mooncake#4180 head는 여전히 9a698e02입니다(2026-09-21 재확인). 이 PR의 squash 커밋 36e3cc2c를 그대로 유지합니다. upstream에서는 아직 병합되지 않았습니다(OPEN).
  • 참고: 이 PR 본문의 "#2991만 있고 #4180이 없는 커밋으로 master를 롤하지 말 것"이라는 문장은 아래 데이터와 맞지 않습니다. 이 문장을 정책으로 읽으면 안 됩니다.

대조군(A)을 3회로 늘린 결과 — 합류 폭풍(S1), 7.8M 키, 로컬 Docker(arm64, Release)

A = our_main(sync만), B = A + kvcache-ai#4180. 칸마다 3회씩 실행했고, 값은 SUSPECTED / OFFLINE 전이 수와 지워진 키 수입니다.

TTL arm SUSPECTED OFFLINE 지워진 키
(ii) 20/20 (운영 60/60과 같은 비율) A 1 / 16 / 16 0 / 1 / 1 0 / 651,680 / 649,221
(ii) 20/20 B 20 / 22 / 20 1 / 0 / 2 0 / 0 / 650,191
(i) 3/6 A 28 / 25 / 33 3 / 4 / 3 648,950 / 1,301,233 / 0
(i) 3/6 B 57 / 54 / 40 20 / 23 / 18 7,409,769 / 5,199,154 / 7,150,670
  • P4의 "(ii)에서 A는 OFFLINE 0" 결과는 1회짜리 우연이었습니다. 3회로 늘리자 A도 3회 중 2회에서 살아 있는 client를 1개씩 잃었습니다. 운영 비율인 (ii)에서는 A와 B가 거의 같습니다.
  • TTL이 scan보다 짧은 (i)에서는 B가 확실히 나쁩니다. OFFLINE은 약 6배이고, 지워진 키는 520만~740만 개입니다.
  • S1에서는 어떤 client도 멈추지 않습니다. 따라서 OFFLINE이 된 client는 모두 살아 있던 client, 즉 오판입니다. (ii)의 5건은 모두 OFFLINE 이후에도 ping을 92~120회 더 보냈습니다.

메커니즘 (로그와 코드로 확인)

  1. P4의 가설 "#4180에서는 여러 scan이 동시에 돈다"는 틀렸습니다(확신도 높음). 두 arm 모두 scan 완료 간격이 scan 한 번 길이(4.5~4.7초)와 같습니다. #4180의 ReMountSegment도 scan 내내 snapshot_mutex_를 배타적으로 잡습니다(PR head master_service.cpp L973–L1088).
  2. main의 liveness monitor는 scan이 끝날 때까지 기다립니다(확신도 높음). ClientMonitorFunc는 매 pass마다 client_mutex_를 shared로 잡는데, ReMountSegment가 이 lock을 배타적으로 쥐고 있습니다. 실제로 A의 전이 143건 중 122건(85%)이 scan 완료 후 150ms 안에 기록되었습니다. B는 296건 중 60건(20%)에 그쳤습니다. B의 ExpireSessions는 이 lock과 무관하게 돌기 때문입니다. 이것이 #4180이 의도한 분리입니다.
  3. ping이 늦게 도착하는 원인은 RPC 스레드 고갈입니다(확신도 중간, 진단 실행 3회). coro_rpc는 코루틴이 아닌 handler를 connection의 io 스레드에서 직접 실행합니다. snapshot_mutex_를 기다리는 remount 12개가 io 스레드 8개를 모두 막을 수 있습니다. --rpc_thread_num=32로 (ii)를 다시 돌리자 B는 2회 모두 SUSPECTED 0 / OFFLINE 0이었고, A는 1회에서 1 / 0이었습니다.
  4. 추론입니다. 두 arm 모두 ping은 똑같이 멈춥니다(원래 client의 최대 ping 지연 A 19.028.9초, B 19.529.9초). 이때 B의 만료 판정은 멈춘 상태를 그대로 보고, A의 monitor는 lock에 막혀 일부를 놓칩니다. 그래서 TTL이 짧을수록 B가 더 많이 오판합니다. 스레드 절반([Store] Serve Ping on a separate RPC server that clients discover on Connect kvcache-ai/Mooncake#4183)이 없으면 #4180만으로는 오판이 줄지 않습니다.
  5. P4의 가설 "30초 timeout 후 재시도가 scan을 늘린다"는 (ii)에서는 거의 해당하지 않습니다. 멈춘 시간이 A 3149초, B 4754초로 비슷합니다. (i)의 연쇄 증폭은 rig가 모든 remount에 scan을 강제하기 때문에 생긴 rig 특유의 현상입니다.

운영과의 관계

두 폭풍 경로 모두 현재 운영 형태에서는 발생하지 않습니다. S1은 HA 승격 뒤의 remount scan이고, S2는 snapshot이 켜진 unmount입니다. 또한 our_main(sync만)도 같은 조건에서 살아 있는 store를 잃는다는 점을 함께 판단해야 합니다.

@Juhyun-Kim-Memphis

Copy link
Copy Markdown
Collaborator Author

INF-522 를 종료하면서 이 PR 도 병합하지 않고 닫습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

run-ci store upstream:open upstream PR 제출됨 (열림)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant