Cruise Control

Strimzi는 LinkedIn에서 개발한 Cruise Control을 지원합니다. Cruise Control은 Kafka 클러스터의 성능 모니터링, 로드 밸런싱, 스케일링 및 장애 복구 등을 자동화하는 도구로, Kafka 클러스터의 운영을 크게 단순화하고 최적화합니다. Strimzi를 사용하면 Cruise Control을 Kafka 클러스터와 쉽게 통합하여 다음과 같은 기능을 활용할 수 있습니다.

로드 밸런싱
Cruise Control은 클러스터 전체의 워크로드 분포를 지속적으로 모니터링하고, 필요에 따라 파티션을 다시 분배하여 로드 밸런싱을 수행합니다. 이를 통해 리소스 사용률을 최적화하고, 클러스터의 처리량과 성능을 극대화할 수 있습니다.

Broker 추가 및 제거
클러스터의 워크로드 요구사항이 변경될 때, Cruise Control을 사용하면 Kafka 브로커를 자동으로 추가하거나 제거할 수 있습니다.

장애 복구
브로커 장애가 발생할 경우, Cruise Control은 자동으로 장애 복구 프로세스를 수행하여, 영향을 받은 파티션을 다른 브로커로 재할당합니다. 이는 클러스터의 가용성과 내구성을 유지하는 데 중요합니다.

 

위와 같이 Cruise Control에서는 여러가지 기능을 제공하지만 이번 문서 실습에서는 Broker의 추가 및 제거에 중점으로 실습을 진행하였습니다.

Cruise Control Goal

Cruise Control은 Kafka 클러스터의 최적화와 관리를 위해 다양한 목표(Goals)를 사용합니다. 목표는 goals, default.goals, hard.goals로 구분되어 있습니다. goals에서는 default.goals에서 사용할 목표를 정의합니다. default.goals은 Cruise Control의 작업 중에 기본적으로 사용되는 목표들의 집합을 정의하며 반드시 goals에 정의된 목표만 사용할 수 있습니다. hard.goals 설정은 반드시 만족해야 하는 목표들의 집합을 정의합니다. 이 목표들은 Cruise Control이 어떤 상황에서도 위반해서는 안 되는 필수 조건으로 작용합니다.

goals, default.goals, hard.goals 기본값

# goal 기본값
com.linkedin.kafka.cruisecontrol.analyzer.goals.RackAwareGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.RackAwareDistributionGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.MinTopicLeadersPerBrokerGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.ReplicaCapacityGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.DiskCapacityGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.NetworkInboundCapacityGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.NetworkOutboundCapacityGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.CpuCapacityGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.ReplicaDistributionGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.PotentialNwOutGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.DiskUsageDistributionGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.NetworkInboundUsageDistributionGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.NetworkOutboundUsageDistributionGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.CpuUsageDistributionGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.TopicReplicaDistributionGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.LeaderReplicaDistributionGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.LeaderBytesInDistributionGoal
com.linkedin.kafka.cruisecontrol.analyzer.kafkaassigner.KafkaAssignerDiskUsageDistributionGoal
com.linkedin.kafka.cruisecontrol.analyzer.kafkaassigner.KafkaAssignerEvenRackAwareGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.PreferredLeaderElectionGoal

# default.goal 기본값
com.linkedin.kafka.cruisecontrol.analyzer.goals.RackAwareGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.MinTopicLeadersPerBrokerGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.ReplicaCapacityGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.DiskCapacityGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.NetworkInboundCapacityGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.NetworkOutboundCapacityGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.CpuCapacityGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.ReplicaDistributionGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.PotentialNwOutGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.DiskUsageDistributionGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.NetworkInboundUsageDistributionGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.NetworkOutboundUsageDistributionGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.CpuUsageDistributionGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.TopicReplicaDistributionGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.LeaderReplicaDistributionGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.LeaderBytesInDistributionGoal

# hard.goal 기본값
com.linkedin.kafka.cruisecontrol.analyzer.goals.RackAwareGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.MinTopicLeadersPerBrokerGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.ReplicaCapacityGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.DiskCapacityGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.NetworkInboundCapacityGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.NetworkOutboundCapacityGoal
com.linkedin.kafka.cruisecontrol.analyzer.goals.CpuCapacityGoal

goal 목표의 의미

# 클러스터의 복제본이 랙 고장에 대해 내성을 가지도록 보장합니다.
com.linkedin.kafka.cruisecontrol.analyzer.goals.RackAwareGoal

# 랙을 고려하여 파티션의 복제본이 분산되도록 합니다.
com.linkedin.kafka.cruisecontrol.analyzer.goals.RackAwareDistributionGoal

# 브로커 당 최소한의 토픽 리더를 유지하여 리더 분포의 균형을 맞춥니다.
com.linkedin.kafka.cruisecontrol.analyzer.goals.MinTopicLeadersPerBrokerGoal

# 모든 브로커가 설정된 복제본 용량을 초과하지 않도록 합니다.
com.linkedin.kafka.cruisecontrol.analyzer.goals.ReplicaCapacityGoal

# 모든 브로커의 디스크 사용량이 설정된 임계값을 넘지 않도록 합니다.
com.linkedin.kafka.cruisecontrol.analyzer.goals.DiskCapacityGoal

# 네트워크 입력 용량의 임계값을 넘지 않도록 합니다.
com.linkedin.kafka.cruisecontrol.analyzer.goals.NetworkInboundCapacityGoal

# 네트워크 출력 용량의 임계값을 넘지 않도록 합니다.
com.linkedin.kafka.cruisecontrol.analyzer.goals.NetworkOutboundCapacityGoal

# CPU 사용량이 설정된 임계값을 넘지 않도록 합니다.
com.linkedin.kafka.cruisecontrol.analyzer.goals.CpuCapacityGoal

# 전체 클러스터에 걸쳐 복제본이 고르게 분포되도록 합니다.
com.linkedin.kafka.cruisecontrol.analyzer.goals.ReplicaDistributionGoal

# 네트워크 출력 잠재력을 기준으로 최적화를 수행합니다.
com.linkedin.kafka.cruisecontrol.analyzer.goals.PotentialNwOutGoal

# 디스크 사용량이 브로커 간에 균일하게 분포되도록 합니다.
com.linkedin.kafka.cruisecontrol.analyzer.goals.DiskUsageDistributionGoal

# 네트워크 입력 사용량이 브로커 간에 균일하게 분포되도록 합니다.
com.linkedin.kafka.cruisecontrol.analyzer.goals.NetworkInboundUsageDistributionGoal

# 네트워크 출력 사용량이 브로커 간에 균일하게 분포되도록 합니다.
com.linkedin.kafka.cruisecontrol.analyzer.goals.NetworkOutboundUsageDistributionGoal

# CPU 사용량이 브로커 간에 균일하게 분포되도록 합니다.
com.linkedin.kafka.cruisecontrol.analyzer.goals.CpuUsageDistributionGoal

# 특정 토픽의 복제본이 클러스터에 걸쳐 고르게 분포되도록 합니다.
com.linkedin.kafka.cruisecontrol.analyzer.goals.TopicReplicaDistributionGoal

# 리더 복제본이 브로커 간에 고르게 분포되도록 합니다.
com.linkedin.kafka.cruisecontrol.analyzer.goals.LeaderReplicaDistributionGoal

# 리더 복제본의 입력 데이터가 브로커 간에 고르게 분포되도록 합니다.
com.linkedin.kafka.cruisecontrol.analyzer.goals.LeaderBytesInDistributionGoal

# Kafka Assigner 도구와 유사한 방식으로 디스크 사용량을 최적화합니다.
com.linkedin.kafka.cruisecontrol.analyzer.kafkaassigner.KafkaAssignerDiskUsageDistributionGoal

# Kafka Assigner 도구와 유사한 방식으로 랙 인식 복제본 배치를 최적화합니다.
com.linkedin.kafka.cruisecontrol.analyzer.kafkaassigner.KafkaAssignerEvenRackAwareGoal

# 리더 복제본의 선출을 최적화하여 특정 조건에서 리더의 선출을 선호합니다.
com.linkedin.kafka.cruisecontrol.analyzer.goals.PreferredLeaderElectionGoal

Strimzi를 이용한 Cruise Control 배포

Strimzi에서는 Cruise Control를 배포하는 방법으로는 별도의 리소스를 정의하는 것이 아닌 kafkas.kafka.strimzi.io 리소스에 cruiseControl: {}를 정의하면 카프카 클러스터와 함께 Deployment 형식으로 배포됩니다.

---
apiVersion: kafka.strimzi.io/v1beta2
kind: Kafka
metadata:
  name: my-cluster
  namespace: kafka
  annotations:
    strimzi.io/node-pools: enabled
spec:
  kafka:
    version: 3.6.1
    listeners:
      - name: plain
        port: 9092
        type: internal
        tls: false
      - name: tls
        port: 9093
        type: internal
        tls: false
    readinessProbe:
      initialDelaySeconds: 15
      timeoutSeconds: 5
    livenessProbe:
      initialDelaySeconds: 15
      timeoutSeconds: 5
    config:
      default.replication.factor: 2
      min.insync.replicas: 1
      inter.broker.protocol.version: "3.6"
      num.partitions: 3
    resources:
      limits:
        cpu: 1
        memory: 1Gi
      requests:
        cpu: 500m
        memory: 1Gi
    logging:
      type: inline
      loggers:
        kafka.root.logger.level: INFO
        kafka.request.logger.level: INFO
  zookeeper:
    replicas: 3
    storage:
      type: persistent-claim
      size: 1Gi
      deleteClaim: true
  entityOperator:
    topicOperator: {}
    userOperator: {}
  cruiseControl:
    config:
      default.goals: >
        com.linkedin.kafka.cruisecontrol.analyzer.goals.MinTopicLeadersPerBrokerGoal,
        com.linkedin.kafka.cruisecontrol.analyzer.goals.TopicReplicaDistributionGoal,
        com.linkedin.kafka.cruisecontrol.analyzer.goals.LeaderReplicaDistributionGoal,
        com.linkedin.kafka.cruisecontrol.analyzer.goals.LeaderBytesInDistributionGoal
      hard.goals: >
        com.linkedin.kafka.cruisecontrol.analyzer.goals.MinTopicLeadersPerBrokerGoal

Kafka 리소스를 생성하게 되면 zookeeper, kafka와는 다르게 Cruise Control은 Deployment 리소스로 배포됩니다.

KafkaRebalance

Strimzi에서 최적화 작업을 제안하기 위해서는 KafkaRebalance라는 리소스를 생성하는 것으로 제안을 할 수 있습니다. kafkaRebalance는 Cruise Control에 의해 제안을 확인하고 해당 제안을 적용하게 됩니다. KafkaRebalance로 제안할 수 있는 종류는 다음과 같습니다.

full 기본값

Cruise Control에 정의된 goal을 기반으로 클러스터의 모든 브로커에 rebalance를 수행합니다. KafkaRebalance의 기본값으로 KafkaRebalance에 아무런 정보를 기입하지 않으면 full 모드로 동작하지만 사용자는 KafkaRebalance 리소스를 생성할 때 mode 필드를 통해 리밸런싱의 모드를 직접 지정할 수 있습니다. full 모드를 명시적으로 지정하면, Cruise Control은 클러스터 전체에 대한 종합적인 리밸런싱 작업을 수행할 수 있습니다.

apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaRebalance
metadata:
  name: my-rebalance
  namespace: kafka
  labels:
    strimzi.io/cluster: my-cluster
spec:
  mode: full

 

add-brokers

add-brokers 옵션은 Kafka 클러스터에 브로커를 추가할 때 사용되며, Cruise Control을 통해 이러한 작업을 자동화하고 최적화할 수 있습니다. Kafka 클러스터의 확장 과정에서 단순히 새로운 브로커를 추가하는 것만으로는 기존에 생성된 토픽의 파티션 복제본이 자동으로 새 브로커로 재할당되지 않습니다. 이 경우, 새 브로커는 앞으로 생성될 토픽의 파티션에만 사용될 수 있습니다.

add-brokers 옵션을 사용하여 Kafka 클러스터에 새로 추가된 브로커들에게 기존 토픽의 파티션 복제본을 자동으로 할당할 수 있습니다. 이는 클러스터의 리소스 사용을 최적화하고, 전체적인 부하 분산을 개선하는 데 도움이 됩니다. add-brokers 작업을 통해 새 브로커는 기존 토픽의 파티션 복제본을 할당받게 되며, 이는 클러스터의 부하를 보다 균등하게 분산시키고, 특정 브로커에 과부하가 집중되는 것을 방지합니다. 

파티션 복제본의 재할당 과정은 클러스터의 크기와 상태, 네트워크 속도 등에 따라 시간이 다소 소요될 수 있습니다.
apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaRebalance
metadata:
  name: my-rebalance
  namespace: kafka
  labels:
    strimzi.io/cluster: my-cluster
spec:
  mode: add-brokers
  brokers: [2, 3]

remove-brokers

Kafka Cluster를 축소학 위해 Broker를 제거할 때 사용됩니다. KafkaRebalance를 사용하지 않고 브로커를 제거할 경우 파티션의 메시지가 정상적으로 Replication 되지 않고 Broker가 드랍되어 메시지 손실이 발생할 수 있습니다. 이러한 문제를 방지하기 위해 remove-broker를 사용하여 파티션을 이동하고 안전하게 Broker를 제거할 수 있습니다. remove-brokers 명령을 실행할 때, 제거하려는 브로커의 ID를 지정합니다. Cruise Control은 이 정보를 바탕으로 해당 브로커에 할당된 파티션 복제본을 다른 브로커로 이동시키는 최적의 계획을 생성하고 실행합니다.

브로커를 제거하는 과정에서 파티션의 리밸런싱이 발생합니다. 이 과정은 네트워크 트래픽과 I/O 부하를 증가시킬 수 있으므로, 클러스터의 성능에 일시적인 영향을 줄 수 있습니다.
apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaRebalance
metadata:
  name: my-rebalance
  namespace: kafka
  labels:
    strimzi.io/cluster: my-cluster
spec:
  mode: remove-brokers
  brokers: [2, 3]

KafkaRebalance 수락하기

KafkaRebalance 리소스를 통해 Cruise Control을 사용하여 Kafka 클러스터의 리밸런싱을 관리할 때, 작업의 상태는 여러 단계를 거칩니다. 이 과정은 사용자가 제안된 리밸런싱 계획을 검토하고 사용자가 승인하는 방식으로 리밸런싱을 수행하는 방식으로 클러스터의 변경 사항을 보다 안전하게 관리할 수 있습니다.

# 리소스 상태 확인
> kubectl get kafkarebalances.kafka.strimzi.io -n kafka
NAME           CLUSTER    PENDINGPROPOSAL  PROPOSALREADY   REBALANCING   READY   NOTREADY
my-rebalance   my-cluster                                  true

 

KafkaRebalance 리소스 상태

PENDINGPROPOSAL
KafkaRebalance 리소스가 생성된 직후, Cruise Control이 리밸런싱 작업의 계획을 작성하고 있는 단계를 나타냅니다.

PROPOSALREADY
작업 계획이 완료되었고 사용자의 검토를 기다리고 있는 상태입니다.

REBALANCING
사용자가 리밸런싱 계획을 승인한 후, Cruise Control이 실제로 리밸런싱 작업을 수행하고 있는 상태입니다.

READY
리밸런싱 작업이 성공적으로 완료되어, KafkaRebalance 리소스가 최종 상태에 도달한 것입니다.

NOTREADY
리밸런싱 작업에 문제가 발생하여 계획이 성공적으로 수행되지 않았음을 나타내는 상태입니다. 이 경우, 문제의 원인을 분석하고 해결한 후 리밸런싱을 다시 시도해야 할 수 있습니다.

 

KafkaRebalance 리소스가 정상적으로 생성되었다면 describe를 이용하여 작업의 계획을 확인할 수 있습니다.

# 작업 계획 확인
> kubectl describe kafkarebalances.kafka.strimzi.io -n kafka my-rebalance
Name:         my-rebalance
Namespace:    kafka
Labels:       strimzi.io/cluster=my-cluster
Annotations:  <none>
API Version:  kafka.strimzi.io/v1beta2
Kind:         KafkaRebalance
Metadata:
  Creation Timestamp:  2024-03-17T06:48:41Z
  Generation:          3
  Resource Version:    179034
  UID:                 00ff25be-fb27-4f99-a9bb-2722560dfddd
Spec:
  Goals:
    LeaderReplicaDistributionGoal
    TopicReplicaDistributionGoal
  Skip Hard Goal Check:  true
Status:
  Conditions:
    Last Transition Time:  2024-03-17T07:01:35.511905341Z
    Status:                True
    Type:                  ProposalReady
  Observed Generation:     3
  Optimization Result:
    After Before Load Config Map:  my-rebalance
    Data To Move MB:               0
    Excluded Brokers For Leadership:
    Excluded Brokers For Replica Move:
    Excluded Topics:
    Intra Broker Data To Move MB:         0
    Monitored Partitions Percentage:      100
    Num Intra Broker Replica Movements:   0
    Num Leader Movements:                 0
    Num Replica Movements:                0
    On Demand Balancedness Score After:   100
    On Demand Balancedness Score Before:  100
    Provision Recommendation:
    Provision Status:                     UNDECIDED
    Recent Windows:                       1
  Session Id:                             b31d2057-273f-4666-9565-51ce304e95db
Events:                                   <none>

 

작업의 계획을 확인하고 annotate 주석을 이용하여 작업을 승인합니다.

# 작업 승인
> kubectl annotate kafkarebalance -n kafka my-rebalance strimzi.io/rebalance="approve"

# 작업을 중지할 때 stop 수행
# kubectl annotate kafkarebalance -n kafka --overwrite my-rebalance strimzi.io/rebalance="stop"

# 완료된 작업을 나중에 재사용할 때 refresh 수행 후 approve
# kubectl annotate kafkarebalance -n kafka --overwrite my-rebalance strimzi.io/rebalance="refresh"
# kubectl annotate kafkarebalance -n kafka --overwrite my-rebalance strimzi.io/rebalance="approve"

 

 


Cruise Control과 KafkaRebalance 실습

지금까지 Cruise Control과 KafkaRebalance에 대해서 알아봤습니다. 이제는 Broker 추가 및 제거하는 방법으로 직접 실습을 진행하겠습니다.

 

Cluster 구성

실습 진행을 위해 테스트용 클러스터를 구축합니다. 이번 실습에서는 별다른 설정 없이 cruiseControl 기본 값 만으로 테스트를 진행하였습니다.

---
apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaNodePool
metadata:
  name: pool-a
  namespace: kafka
  labels:
    strimzi.io/cluster: my-cluster
spec:
  replicas: 2
  roles:
    - broker
  storage:
    type: jbod
    volumes:
      - id: 0
        type: persistent-claim
        size: 5Gi
        deleteClaim: true
        
---
apiVersion: kafka.strimzi.io/v1beta2
kind: Kafka
metadata:
  name: my-cluster
  namespace: kafka
  annotations:
    strimzi.io/node-pools: enabled
spec:
  kafka:
    version: 3.6.1
    listeners:
      - name: plain
        port: 9092
        type: internal
        tls: false
      - name: tls
        port: 9093
        type: internal
        tls: false
    readinessProbe:
      initialDelaySeconds: 15
      timeoutSeconds: 5
    livenessProbe:
      initialDelaySeconds: 15
      timeoutSeconds: 5
    config:
      default.replication.factor: 2
      min.insync.replicas: 1
      inter.broker.protocol.version: "3.6"
      num.partitions: 3
    resources:
      limits:
        cpu: 1
        memory: 1Gi
      requests:
        cpu: 500m
        memory: 1Gi
    logging:
      type: inline
      loggers:
        kafka.root.logger.level: INFO
        kafka.request.logger.level: INFO
  zookeeper:
    replicas: 3
    storage:
      type: persistent-claim
      size: 1Gi
      deleteClaim: true
  entityOperator:
    topicOperator: {}
    userOperator: {}
  cruiseControl:
    {}

 

Topic 생성

토픽 a-topic, b-topic을 생성하고 나서 토픽 파티션의 할당된 브로커를 확인하면 0, 1번 브로커에 배포된 것을 확인할 수 있습니다.

apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaTopic
metadata:
  name: a-topic
  namespace: kafka
  labels:
    strimzi.io/cluster: my-cluster
spec:
  partitions: 4
  replicas: 2
  config:
    retention.ms: 7200000
    segment.bytes: 1073741824
---
apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaTopic
metadata:
  name: b-topic
  namespace: kafka
  labels:
    strimzi.io/cluster: my-cluster
spec:
  partitions: 4
  replicas: 2
  config:
    retention.ms: 7200000
    segment.bytes: 1073741824

 

kcat 파드를 이용하여 토픽 생성 결과 확인

> ❯ kubectl exec -it -n kafka kcat -- kcat -L -b my-cluster-kafka-bootstrap:9092
Metadata for all topics (from broker -1: my-cluster-kafka-bootstrap:9092/bootstrap):
 2 brokers:
  broker 0 at my-cluster-pool-a-0.my-cluster-kafka-brokers.kafka.svc:9092
  broker 1 at my-cluster-pool-a-1.my-cluster-kafka-brokers.kafka.svc:9092 (controller)
 5 topics:
  ( ... 생략 ... )
  topic "a-topic" with 4 partitions:
    partition 0, leader 0, replicas: 0,1, isrs: 0,1
    partition 1, leader 1, replicas: 1,0, isrs: 1,0
    partition 2, leader 0, replicas: 0,1, isrs: 0,1
    partition 3, leader 1, replicas: 1,0, isrs: 1,0
  topic "b-topic" with 4 partitions:
    partition 0, leader 1, replicas: 1,0, isrs: 1,0
    partition 1, leader 0, replicas: 0,1, isrs: 0,1
    partition 2, leader 1, replicas: 1,0, isrs: 1,0
    partition 3, leader 0, replicas: 0,1, isrs: 0,1

 

Broker 확장

KafkaNodePool의 개수를 증가 시켜 브로커를 추가합니다.

apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaNodePool
metadata:
  name: pool-a
  namespace: kafka
  labels:
    strimzi.io/cluster: my-cluster
spec:
  replicas: 4
  roles:
    - broker
  storage:
    type: jbod
    volumes:
      - id: 0
        type: persistent-claim
        size: 5Gi
        deleteClaim: true

 

브로커를 추가하여 파드가 생성되었지만 카프카 클러스터를 확인하면 추가된 브로커는 클러스터에 합류하지 못한 것을 알 수 있습니다.

 

kcat을 이용하여 확인하면 클러스터에 변화가 없는 것을 알 수 있습니다.

> kubectl exec -it -n kafka kcat -- kcat -L -b my-cluster-kafka-bootstrap:9092
Metadata for all topics (from broker -1: my-cluster-kafka-bootstrap:9092/bootstrap):
 2 brokers:
  broker 0 at my-cluster-pool-a-0.my-cluster-kafka-brokers.kafka.svc:9092
  broker 1 at my-cluster-pool-a-1.my-cluster-kafka-brokers.kafka.svc:9092 (controller)
 5 topics:
  ( ... 생략 ... )
  topic "a-topic" with 4 partitions:
    partition 0, leader 0, replicas: 0,1, isrs: 0,1
    partition 1, leader 1, replicas: 1,0, isrs: 1,0
    partition 2, leader 0, replicas: 0,1, isrs: 0,1
    partition 3, leader 1, replicas: 1,0, isrs: 1,0
  topic "b-topic" with 4 partitions:
    partition 0, leader 1, replicas: 1,0, isrs: 1,0
    partition 1, leader 0, replicas: 0,1, isrs: 0,1
    partition 2, leader 1, replicas: 1,0, isrs: 1,0
    partition 3, leader 0, replicas: 0,1, isrs: 0,1

 

KafkaRebalance add-brokers

2, 3번 브로커를 추가합니다.

apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaRebalance
metadata:
  name: rebalance-add
  namespace: kafka
  labels:
    strimzi.io/cluster: my-cluster
spec:
  mode: add-brokers
  brokers: [2, 3]

 

KafkaRebalance 리소스 상태 확인

 

작업 계획 확인

 

작업 승인

 

결과 확인

> kubectl exec -it -n kafka kcat -- kcat -L -b my-cluster-kafka-bootstrap:9092
Metadata for all topics (from broker -1: my-cluster-kafka-bootstrap:9092/bootstrap):
 4 brokers:
  broker 0 at my-cluster-pool-a-0.my-cluster-kafka-brokers.kafka.svc:9092
  broker 2 at my-cluster-pool-a-2.my-cluster-kafka-brokers.kafka.svc:9092
  broker 3 at my-cluster-pool-a-3.my-cluster-kafka-brokers.kafka.svc:9092
  broker 1 at my-cluster-pool-a-1.my-cluster-kafka-brokers.kafka.svc:9092 (controller)
 5 topics:
 (... 생략 ...)
  topic "a-topic" with 4 partitions:
    partition 0, leader 3, replicas: 3,2, isrs: 2,3
    partition 1, leader 3, replicas: 3,2, isrs: 2,3
    partition 2, leader 3, replicas: 3,2, isrs: 2,3
    partition 3, leader 2, replicas: 2,3, isrs: 3,2
  topic "b-topic" with 4 partitions:
    partition 0, leader 1, replicas: 1,0, isrs: 1,0
    partition 1, leader 3, replicas: 3,2, isrs: 2,3
    partition 2, leader 3, replicas: 3,2, isrs: 2,3
    partition 3, leader 0, replicas: 0,1, isrs: 0,1

결과를 확인하면 기존 토픽의 파티션이 새롭게 추가된 브로커에도 할당된 것을 확인할 수 있습니다.

 

KafkaRebalance remove-brokers 생성

이제는 반대로 추가한 브로커를 제거하는 방법을 수행합니다.

apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaRebalance
metadata:
  name: rebalance-remove
  namespace: kafka
  labels:
    strimzi.io/cluster: my-cluster
spec:
  mode: remove-brokers
  brokers: [2, 3]

 

remove-brokers 작업 수행

 

KafkaNodePool의 개수를 줄여 자원 반납

apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaNodePool
metadata:
  name: pool-a
  namespace: kafka
  labels:
    strimzi.io/cluster: my-cluster
spec:
  replicas: 2
  roles:
    - broker
  storage:
    type: jbod
    volumes:
      - id: 0
        type: persistent-claim
        size: 5Gi
        deleteClaim: true

 

참고문서

https://strimzi.io/docs/operators/latest/deploying#cruise-control-concepts-str

+ Recent posts