6K msg/s 고정률 부하에서 Valkey 단일 노드 EngineCPU가 99.9%에 묶여 ACK p95 767.6ms, WAL 적체 80,000건 발생. 싱글스레드라 코어를 늘려도 쓰기 병목은 풀리지 않는 구조였습니다.
논리 채널 ID의 안정 해시로 샤드를 고르고, WAL 스트림과 채널별 seq·dedupe 키에 같은 hash tag를 붙여 4-shard cluster에서도 한 채널의 multi-key append가 한 슬롯에서 원자적으로 끝나게 했습니다. 샤드 수 1은 기존 키 형태와 호환됩니다.
→ ACK p95 767.6ms→6.6ms, 수용률 99.39%→99.994%(4,787→5,912 msg/s), WAL 적체 80,000→2,838건, 가장 바쁜 샤드 EngineCPU 74.7%
outbox 후속 처리 Lambda가 Throttle 0인데도 동시 실행 2(예약 100의 2%)에 머물고 IteratorAge가 11분에 고착됐습니다. batching window 조정으로는 풀리지 않았습니다.
파티션 키가 tenant#날짜라 하루치 쓰기가 한 파티션, 곧 스트림 샤드 하나에 몰리는 설계를 원인으로 추적하고 키에 0~9 shard suffix를 붙여 10개 파티션으로 분산했습니다.
→ sandbox 부하에서 IteratorAge 658s→35s(-95%), Lambda 동시 실행 2→8. 이후 4K CCU 부하에서 outbox 테이블 쓰기 throttle(37K건)이 확인되자 outbox를 없애고 메시지 테이블 Stream CDC로 전환했습니다.
hot-channel 부하에서 ordering accept가 느려졌지만 Valkey Lua, gateway event loop, command queue, topology 중 어디가 병목인지 분리되지 않았습니다.
변경 전에 attribution 계측부터 넣고 고정 채널 500 CCU와 단계별 부하로 ECPU/msg·command queue·event-loop delay를 교차 검증해 단일 연결과 0.5 vCPU event loop 포화로 원인을 좁힌 뒤 연결 pool을 나눴습니다.
→ pool 4개에서 command queue 5,940→716, 878,205건 처리 중 유실 0, sandbox 검증 19/0/0
성능 개선 뒤 gateway task가 OOM kill을 반복했고, 처음 세운 outbound queue 누적 가설은 검증 run에서 발동 0회로 기각됐습니다.
가설을 먼저 등록하고 heap snapshot·진단 로그·비교 측정으로 관측 스택(statsd DNS lookup, hot-path 계측)의 retained heap 누적과 V8 heap 한도·컨테이너 메모리 1GiB 불일치를 분리했습니다.
→ 수정 적용 후 OOM 0건
6,000 CCU 목표를 넘는 부하에서도 연결이 유지되는지, 캐시 노드를 확장하는 동안 연결이 끊기지 않는지 근거가 필요했습니다.
dev 환경에서 20K CCU 부하 시험과, 별도 시험으로 Valkey 노드 온라인 스케일업을 측정했습니다.
→ 20,002 CCU 900초 유지. 별도 확장 시험에서는 16분 39초 동안 연결 손실 0이었고, send 23건이 backpressure로 거부돼 클라이언트 재시도로 복구됐습니다.