Kafka 토픽 구성 마스터하기: 종합 가이드

Kafka 토픽 파티션, 복제, 보존, 압축 및 안전한 구성 변경에 대한 실용적인 가이드입니다.

Kafka 토픽 구성 마스터하기: 종합 가이드

Kafka 토픽 구성은 데이터가 저장, 복사, 만료, 압축 및 소비되는 방식을 결정합니다. 특히 개발 클러스터에서는 잠시 동안 기본값으로 Kafka를 실행할 수 있지만, 프로덕션 토픽은 더 많은 주의가 필요합니다. 잘못된 파티션 수는 과중한 워크로드를 가둘 수 있습니다. 약한 복제는 브로커 장애를 데이터 손실로 바꿀 수 있습니다. 느슨한 보존은 디스크를 가득 채울 수 있습니다. 키가 없거나 일관되지 않으면 압축이 예상치 못한 결과를 초래할 수 있습니다.

Kafka 토픽 구성에 접근하는 유용한 방법은 모든 설정을 암기하는 것이 아닙니다. 실제 시스템이 묻는 질문부터 시작하세요: 얼마나 많은 병렬 처리가 필요한가, 데이터를 얼마나 오래 사용 가능하게 해야 하는가, 저장할 수 있는 데이터의 양은 얼마인가, 브로커 장애 시 어떤 일이 발생하는가, 소비자가 전체 이벤트 기록이 필요한가 아니면 키당 최신 값만 필요한가?

토픽은 파티션으로 분할됩니다. 각 파티션은 정렬된 로그입니다. Kafka는 전체 토픽이 아닌 파티션 내에서 순서를 유지합니다. 고객의 모든 이벤트가 순서대로 처리되어야 하는 경우 customer_id와 같은 안정적인 키를 사용하여 해당 이벤트가 동일한 파티션에 배치되도록 합니다. 무작위로 키를 지정하면 더 나은 분산을 얻을 수 있지만 엔터티별 순서는 손실됩니다.

파티션 수는 사람들이 가장 먼저 후회하는 선택 중 하나입니다. 더 많은 파티션은 더 많은 소비자 병렬 처리를 허용합니다. 하나의 소비자 그룹 내에서 파티션은 한 번에 하나의 그룹 구성원만 소비하기 때문입니다. 토픽에 6개의 파티션이 있는 경우 소비자 그룹은 해당 토픽에 대해 최대 6개의 소비자를 활성화할 수 있습니다. 다른 할당된 파티션이 없는 한 일곱 번째 소비자를 추가해도 해당 토픽의 소비량이 증가하지 않습니다.

더 많은 파티션은 비용도 발생시킵니다. 메타데이터, 열린 파일, 복제 작업, 리더 선출 작업, 브로커 장애 후 복구 시간이 증가합니다. 각 파티션의 트래픽이 적더라도 매우 많은 파티션 수는 클러스터 작업을 느리게 만들 수 있습니다. 보편적인 최적의 수는 없습니다. 작은 내부 토픽은 3개의 파티션으로 충분할 수 있습니다. 트래픽이 많은 이벤트 스트림은 수십 개가 필요할 수 있습니다. 매우 큰 Kafka 설치에서는 훨씬 더 많은 파티션을 사용할 수 있지만, 이는 측정된 처리량과 운영 용량에 기반해야 하며 습관에 의한 것이 아닙니다.

명시적 설정으로 토픽 생성:

kafka-topics.sh --create   --bootstrap-server broker1:9092   --topic user-events.v1   --partitions 12   --replication-factor 3   --config min.insync.replicas=2

토픽 이름에도 의도가 담겨 있어야 합니다. eventsdata와 같은 이름은 클러스터가 성장하면 쓸모없어집니다. user-events.v1, billing-invoices.v1, 또는 inventory-adjustments.v1은 미래의 운영자에게 스트림이 무엇인지 알려주고 나중에 스키마를 변경할 여지를 줍니다.

복제 팩터는 Kafka가 각 파티션에 대해 유지하는 복사본 수를 제어합니다. 프로덕션에서는 3이 일반적인 기본값입니다. 하나의 브로커가 실패해도 다른 복제본을 사용할 수 있기 때문입니다. 이것이 프로듀서 설정을 무시할 수 있다는 의미는 아닙니다. 프로듀서가 acks=1을 사용하면 Kafka는 팔로워가 복사하기 전에 레코드를 승인할 수 있습니다. 중요한 토픽의 경우 복제 팩터 3을 토픽 수준의 min.insync.replicas=2 및 프로듀서 acks=all과 함께 사용하세요.

min.insync.replicas는 종종 오해받습니다. 복제본을 생성하지 않습니다. acks=all 쓰기가 성공하려면 사용 가능한 동기화된 복제본의 수를 지정합니다. 복제 팩터 3과 min.insync.replicas=2를 사용하면 토픽은 하나의 브로커를 사용할 수 없는 상황을 견딜 수 있습니다. 동기화된 복제본이 하나만 남으면 Kafka는 안전한 복사본이 너무 적은 데이터를 수락하는 대신 강력한 쓰기를 거부해야 합니다.

보존 설정은 Kafka가 오래된 로그 세그먼트를 삭제할 시기를 결정합니다. 시간 기반 보존은 토픽 수준에서 retention.ms로 제어됩니다. 크기 기반 보존은 retention.bytes로 제어됩니다. log.retention.ms와 같은 이전 브로커 수준 이름은 브로커 기본값입니다. 토픽 구성은 일반적으로 retention.ms를 사용합니다.

예를 들어, 토픽을 7일 동안 보존하려면:

kafka-configs.sh --alter   --bootstrap-server broker1:9092   --entity-type topics   --entity-name user-events.v1   --add-config retention.ms=604800000

파티션당 저장 공간을 제한하려면 retention.bytes를 사용하세요:

kafka-configs.sh --alter   --bootstrap-server broker1:9092   --entity-type topics   --entity-name user-events.v1   --add-config retention.bytes=10737418240

retention.bytes는 일반적으로 전체 토픽 크기가 아닌 파티션당임을 기억하세요. 12개의 파티션과 retention.bytes=10GB를 가진 토픽은 복제 전 약 120GB, 복제 팩터 3으로 약 360GB를 사용할 수 있습니다. 이것이 예상치 못한 디스크 알람을 유발하는 세부 사항입니다.

Kafka는 레코드별이 아닌 로그 세그먼트 단위로 데이터를 삭제합니다. 짧은 보존 기간을 설정했지만 세그먼트가 큰 경우 예상한 정확한 시간에 삭제가 발생하지 않을 수 있습니다. segment.bytessegment.ms와 같은 세그먼트 설정은 Kafka가 새 세그먼트로 전환하는 시점에 영향을 미치며, 닫힌 세그먼트만 삭제 또는 압축 대상이 됩니다. 더 작은 세그먼트는 정리를 더 빠르게 반응하게 할 수 있지만 오버헤드가 추가됩니다.

cleanup.policy는 Kafka가 오래된 데이터로 무엇을 할지 결정합니다. 기본값은 delete로, 보존에 따라 오래된 세그먼트를 제거합니다. compact는 각 키에 대한 최신 레코드를 유지하고 동일한 키를 가진 오래된 레코드를 결국 제거합니다. 압축과 보존 기간이 모두 필요한 토픽에는 delete,compact를 사용할 수도 있습니다.

압축은 상태와 같은 스트림에 유용합니다: 사용자 프로필 업데이트, 기능 플래그 값, 계정 설정, 또는 기본 키로 키가 지정된 데이터베이스 변경 이벤트. 모든 이벤트가 중요한 이벤트 기록에는 적합하지 않습니다. 감사 로그를 압축하면 동일한 키에 대한 오래된 이벤트가 결국 사라질 수 있습니다. 이는 규정 준수나 디버깅에 정확히 잘못된 것일 수 있습니다.

압축은 키에 따라 달라집니다. null이거나 일관되지 않은 키가 있는 압축된 토픽은 깔끔한 키-값 변경 로그처럼 작동하지 않습니다. 프로듀서가 때로는 user_id로, 때로는 이메일로 사용자 업데이트를 보내면 Kafka는 다른 키로 인식합니다. 동일한 사용자를 나타낸다는 것을 추론할 수 없습니다.

압축은 프로듀서에 의해 설정될 수 있으며, 토픽은 브로커 동작을 제어하기 위해 compression.type을 정의할 수 있습니다. 일반적인 값에는 Kafka 버전에 따라 producer, gzip, snappy, lz4, zstd가 포함됩니다. 많은 팀이 토픽을 producer로 두고 프로듀서 압축을 표준화합니다. lz4zstd는 일반적인 선택이지만, 올바른 답은 CPU 예산, 메시지 형태 및 네트워크 압력에 따라 달라집니다.

토픽 구성을 다음과 같이 검사할 수 있습니다:

kafka-configs.sh --describe   --bootstrap-server broker1:9092   --entity-type topics   --entity-name user-events.v1

그리고 파티션 배치를 다음과 같이 검사합니다:

kafka-topics.sh --describe   --bootstrap-server broker1:9092   --topic user-events.v1

두 명령을 모두 사용하세요. 토픽 구성은 보존, 압축 및 ISR 규칙을 알려줍니다. 토픽 설명은 리더, 복제본 및 ISR 상태를 알려줍니다. 토픽이 완벽한 구성을 가지고 있어도 복제본이 동기화되지 않으면 비정상일 수 있습니다.

일부 변경은 쉽습니다. 보존, 압축 정책, min.insync.replicas 및 기타 여러 토픽 구성을 동적으로 변경할 수 있습니다. 일부 변경은 더 많은 주의가 필요합니다. 파티션 수를 늘릴 수 있지만 간단한 명령으로 안전하게 줄일 수는 없습니다. 파티션을 늘리면 파티셔닝 계산에 더 많은 대상 파티션이 있기 때문에 향후 레코드의 키 분포도 변경됩니다. 기존 레코드는 그대로 유지됩니다. 동일한 키에 대한 새 레코드는 파티셔너에 따라 증가 후 다른 파티션으로 이동할 수 있습니다. 변경 전후에 엄격한 키별 순서가 중요한 경우 신중하게 계획하세요.

복제 팩터 변경은 운영 작업입니다. 기존 토픽의 복제본을 늘리면 Kafka가 기존 데이터를 새 브로커에 복사해야 합니다. 이는 많은 I/O를 발생시킬 수 있습니다. 재할당 도구를 사용하고 진행 상황을 모니터링하며 필요한 경우 제한하세요. 클러스터에 충분한 여유 용량이 있다는 것을 이미 알지 않는 한 피크 트래픽 중에 대규모 재할당을 시작하지 마세요.

일반적인 프로덕션 이벤트 토픽의 경우 실용적인 시작점은 다음과 같을 수 있습니다:

kafka-topics.sh --create   --bootstrap-server broker1:9092   --topic payments-authorized.v1   --partitions 24   --replication-factor 3   --config min.insync.replicas=2   --config retention.ms=1209600000   --config cleanup.policy=delete

이는 다음을 의미합니다: 병렬 처리를 위한 충분한 파티션, 가용성을 위한 세 개의 복사본, 강력한 쓰기를 위해 필요한 두 개의 동기화된 복제본, 14일의 보존, 그리고 모든 결제 승인 이벤트가 중요하므로 압축 없음.

상태 토픽의 경우 형태가 다릅니다:

kafka-topics.sh --create   --bootstrap-server broker1:9092   --topic user-preferences.v1   --partitions 12   --replication-factor 3   --config min.insync.replicas=2   --config cleanup.policy=compact

해당 토픽은 사용자 ID로 키가 지정되어야 합니다. 상태를 재구축하는 소비자는 압축된 로그를 읽고 결국 각 사용자에 대한 최신 값을 볼 수 있습니다. 모든 과거 기본 설정 변경이 영원히 유지되기를 기대해서는 안 됩니다.

최고의 토픽 구성은 운영하기에 지루합니다. 충분한 파티션이 있지만 이유 없이 수천 개는 아닙니다. 데이터의 가치에 맞는 복제가 있습니다. 복구 및 규정 준수 요구 사항에 맞는 보존이 있습니다. 키가 의미 있는 경우에만 압축을 사용합니다. 코드나 문서에 설명되어 있어 다른 엔지니어가 추측 없이 재생성할 수 있습니다.

유용한 검토 습관은 토픽 설정을 선택하기 전에 소비자 스토리를 기록하는 것입니다. 누가 이 토픽을 읽습니까? 처음부터 다시 재생해야 합니까? 전체 재구축에 얼마나 걸립니까? 소스 시스템이 오래된 데이터를 다시 게시할 수 있습니까? 소비자가 3일 동안 다운되면 Kafka가 여전히 놓친 레코드를 보유해야 합니까? 이러한 답변은 기본 7일 설정보다 더 정직하게 보존을 결정합니다.

결제 이벤트를 읽는 사기 탐지 소비자를 고려하세요. 6시간 동안 다운되면 Kafka에서 따라잡기를 원할 것입니다. 30일 동안 다운되면 결제 데이터베이스에서 별도의 백필 프로세스를 기대할 수 있습니다. 해당 토픽은 영원히가 아니라 2주의 보존이 필요할 수 있습니다. 보안 감사 토픽은 다른 요구 사항이 있을 수 있으며, Kafka가 핫 재생 창만 유지하는 동안 장기 보존을 위해 객체 스토리지로 전송할 수 있습니다.

메시지 크기도 토픽 논의에 포함되어야 합니다. Kafka는 구성 시 더 큰 레코드를 처리할 수 있지만, 큰 메시지는 프로듀서, 브로커, 소비자, 복제 및 가져오기 메모리에 영향을 미칩니다. 팀이 멀티 메가바이트 JSON 블롭이나 인코딩된 파일을 토픽에 넣기 시작하면 max.message.bytes만 높이고 넘어가지 마세요. 페이로드가 Kafka의 참조와 함께 객체 스토리지에 속하는지 물어보세요. Kafka는 일반적으로 이벤트를 이동하는 데 가장 적합하며, 블롭 저장소 역할을 하는 데는 적합하지 않습니다.

스키마 진화는 토픽 구성 설정이 아니지만 토픽 디자인을 형성합니다. orders.v1과 같은 버전 접미사가 있는 토픽 이름은 중대한 변경이 불가피할 때 탈출구를 제공합니다. 호환 가능한 변경은 소비자와 프로듀서가 스키마 정책을 따르는 경우 동일한 토픽에 유지될 수 있습니다. 중대한 변경은 한 팀이 프로듀서를 제어하기 때문에 동일한 토픽에 몰래 넣어서는 안 됩니다. Kafka는 시스템을 분리하지만 계약이 존중되는 경우에만 가능합니다.

마지막으로, 토픽 소유권을 문서화하세요. 모든 프로덕션 토픽에는 소유 팀, 예상 프로듀서, 예상 소비자, 보존 이유 및 데이터 민감도 메모가 있어야 합니다. 이는 행정적으로 들리지만 디스크가 오전 2시에 가득 차고 아무도 토픽을 단축, 삭제, 압축 또는 제한할 수 있는지 모를 때까지입니다. 좋은 토픽 구성은 부분적으로 기술적이고 부분적으로 운영적 기억입니다.

토픽을 게시하기 전 최종 확인은 장애 시나리오를 실행하는 것입니다. 하나의 브로커가 사라지면 프로듀서가 여전히 쓸 수 있습니까? 소비자 그룹이 주말 동안 다운되면 보존이 그 격차를 커버합니까? 프로듀서가 잘못된 데이터를 보내면 소비자가 안전하게 건너뛰거나, 격리하거나, 재생할 수 있습니까? 토픽이 예상보다 두 배 빠르게 성장하면 어떤 제한이 클러스터를 보호합니까: 보존 시간, 보존 바이트, 할당량 또는 알람?

할당량은 언급할 가치가 있습니다. 토픽 구성만으로는 공유 클러스터를 시끄러운 프로듀서로부터 보호하지 못하기 때문입니다. Kafka는 프로듀스 및 가져오기 속도를 제한할 수 있는 클라이언트 할당량을 지원합니다. 여러 팀이 하나의 클러스터를 공유하는 경우 할당량은 우발적인 재생이나 통제 불능 프로듀서가 브로커를 압도하는 것을 방지할 수 있습니다. 팀이 Kafka를 비난하는 대신 제한되고 있음을 알 수 있도록 알람과 함께 사용해야 합니다.

삭제 정책을 잊지 마세요. 일부 클러스터는 사고를 방지하기 위해 브로커 수준에서 토픽 삭제를 비활성화합니다. 이는 합리적일 수 있지만, 버려진 토픽은 통제된 정리 프로세스를 통해 처리되어야 함을 의미합니다. 매월 또는 분기마다 토픽 인벤토리 검토를 수행하면 특히 실험으로 인해 오래된 토픽이 남겨지는 개발 및 스테이징 클러스터에서 놀라운 양의 디스크를 회수할 수 있습니다.