Kafka에서 키(key) 는 단순한 “식별자”가 아니라, (1) 어떤 파티션에 저장될지와 (2) 그 파티션 내부에서 순서가 어떻게 보장될지를 결정하는 핵심 설계 포인트입니다. 같은 키는 같은 파티션으로 라우팅되므로, 키 전략을 잘못 잡으면 핫 파티션(쏠림), 처리량 병목, 확장 시 재파티셔닝 비용이 크게 발생합니다. Source
Kafka는 키를 해시해서 특정 파티션을 선택합니다. 그 결과 같은 키로 보낸 레코드들은 같은 파티션에 들어가고, 소비 시에도 그 파티션 내부 순서가 유지됩니다(단, “전체 토픽” 단위 순서는 보장되지 않음). Source
Java 클라이언트의 기본 파티셔너는 (키가 있을 때) 32-bit murmur2 해시를 만들고 파티션 수로 mod 해서 파티션을 결정합니다. Source
즉, 파티션 수가 바뀌면(파티션 추가) 키→파티션 매핑이 대거 재배치될 수 있습니다.
키를 고르기 전에 아래 3가지를 먼저 확정하는 게 안전합니다.
1) 순서 보장이 필요한 “범위”가 무엇인가?
2) 처리량/병렬성이 얼마나 필요한가?
3) “쏠림(스큐)”을 얼마나 허용할 수 있나?
userId, orderId, accountIdKafka 키가 “관련 메시지를 같은 파티션으로 모아 순서를 보장”한다는 점 때문에 가장 기본 전략입니다. Source
tenantId:userId, storeId:orderIdorderId#0..N, userId#bucket“순서”와 “처리량”을 동시에 잡을 수 없는 경우가 많아서, 이 전략은 중급 이상에서 매우 자주 씁니다.
yyyyMMddHH 같은 시간 키키가 없으면 파티션에 고르게 분산(라운드로빈/스티키 계열 동작)되어 처리량에 유리하지만, 관련 메시지 순서/그룹핑 보장이 약해집니다. Source
MSK 운영 관점에서도 “키 없이 분산되는 트래픽”은 스케일 아웃에 유리할 수 있습니다(단, 소비 로직이 순서를 요구하지 않아야). Source
기본 파티셔너가 murmur2 기반이라는 점을 이해하고도, 도메인 요구(특정 파티션 고정, 특정 라우팅 룰 등) 때문에 커스텀을 씁니다. 다만 운영 복잡도가 올라가고, producer 다양성(다른 언어/라이브러리)까지 고려해야 합니다. Source
ProducerRecord<String, String> record =
new ProducerRecord<>("orders", orderId, payloadJson);
producer.send(record);
orderId가 같으면 같은 파티션으로 라우팅됩니다. Sourceint shard = Math.floorMod(orderId.hashCode(), 16); // 16-way shard
String key = orderId + "#" + shard;
ProducerRecord<String, String> record =
new ProducerRecord<>("orders", key, payloadJson);
producer.send(record);
MSK에서 브로커/파티션을 늘려도, 특정 키가 한 파티션을 독점하면 해당 파티션의 리더 브로커 CPU가 먼저 차고 지연이 발생합니다. MSK는 CPU 60% 이하 유지 등을 권장하며, 부하 분산(파티션/브로커 밸런싱)이 운영 안정성에 중요합니다. Source
MSK 문서에서도 브로커 사이즈별 “권장 파티션 수(리더+팔로워 포함)” 가이드가 있으며, 파티션 과다 시 업데이트/메트릭 누락 등의 문제가 생길 수 있음을 명시합니다. Source
기본 파티셔닝이 hash(key) % partitionCount이기 때문에, 파티션 수 변경은 대규모 재매핑을 유발할 수 있습니다. Source
orderIdorderId#shard로 전환 고려tenantId:userId (또는 tenantId:entityId)아래 이미지는 본문 중간에 그대로 삽입해서 쓰기 좋습니다.
1) Kafka 파티션 개념(다이어그램)
Source
2) Kafka Keys/Ordering 관련 시각자료(키-파티션-순서 맥락)
Source