CS 공부/기타

[ETC] 두 PC에 Kafka 브로커 분리 설치 및 클러스터 검증 실습

강_토발즈 2025. 8. 24. 20:30

1. 브로커와 컨트롤러의 개념

  • 브로커(Broker)
    • Kafka에서 데이터를 실제로 저장하고 서비스하는 주체
    • 프로듀서(Producer)가 보낸 메시지를 저장하고, 컨슈머(Consumer)가 가져가도록 제공
    • 브로커 여러 개가 있으면 파티션 단위로 데이터를 분산 저장하고 복제
  • 컨트롤러(Controller)
    • 클러스터의 두뇌 역할
    • 브로커들의 상태를 관리, 리더 선출, 토픽 메타데이터 관리
    • Kafka KRaft 모드에서는 컨트롤러끼리 Raft 합의를 통해 과반수 투표로 리더를 선출

즉, 브로커 = 데이터 저장소, 컨트롤러 = 클러스터 관리자 이다. 여기서 중요한건, 컨트롤러들은 대표를 선출해야하기 때문에 서로간 통신이 필요하고, 만약 컨트롤러가 분리되어 설치되어 있다면, 각 포트를 양방향 TCP 로 개방해주어야 한다는 것이다. 브로커 역시 각 브로커간 데이터를 송수신 하려면 포트를 개방해줘야 하지만, 브로커 포트는 단방향으로만 열어주면 된다.

 

즉 1번 PC 에 node.1 과 node.2 가 설치되어 있다면 9093, 9094 포트를, 2번 PC 의 node.3 의 9095 포트를 (양방향 TCP) 개방 해주어야 각 브로커들이 통신을 통해 리더를 선출할 수 있다. 

 

 

2. 두 PC에서 브로커 설치를 위한 properties 설정법

1번 PC = 192.168.0.98 , 2번 PC 192.168.0.99 로 예를 들면 

 

- 1번 PC 의 node.1

process.roles=broker,controller
node.id=1
controller.quorum.voters=1@192.168.0.98:9093,2@192.168.0.98:9094,3@192.168.0.99:9095

listeners=PLAINTEXT://0.0.0.0:9096,CONTROLLER://0.0.0.0:9093
advertised.listeners=PLAINTEXT://192.168.0.98:9096

inter.broker.listener.name=PLAINTEXT
listener.security.protocol.map=PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT
controller.listener.names=CONTROLLER

log.dirs=~/kafka/logs/kraft-combined-logs-1

 

- 1번 PC 의 node.2

process.roles=broker,controller
node.id=2
controller.quorum.voters=1@192.168.0.98:9093,2@192.168.0.98:9094,3@192.168.0.99:9095

listeners=PLAINTEXT://0.0.0.0:9097,CONTROLLER://0.0.0.0:9094
advertised.listeners=PLAINTEXT://192.168.0.98:9097

inter.broker.listener.name=PLAINTEXT
listener.security.protocol.map=PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT
controller.listener.names=CONTROLLER

log.dirs=~/kafka/logs/kraft-combined-logs-2

 

- 2번 PC 의 node.3

process.roles=broker,controller
node.id=3
controller.quorum.voters=1@192.168.0.98:9093,2@192.168.0.98:9094,3@192.168.0.99:9095

listeners=PLAINTEXT://0.0.0.0:9098,CONTROLLER://0.0.0.0:9095
advertised.listeners=PLAINTEXT://192.168.0.99:9098

inter.broker.listener.name=PLAINTEXT
listener.security.protocol.map=PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT
controller.listener.names=CONTROLLER

log.dirs=~/kafka/logs/kraft-combined-logs-3

 

 

3. 실행 후 포트 확인

Kafka 실행 후 아래 명령어로 포트가 열렸는지 확인한다

ss -lntp | grep :90

 

1번 PC 

 

2번 PC 

 

 

4. 클러스터 검증 방법

- 컨트롤러 합의 확인

cd kafka/bin

./kafka-metadata-quorum.sh --bootstrap-server 192.168.0.98:9096 describe --status

 

 

  • CurrentVoters: [1,2,3] → 세 노드가 모두 합의에 참여 했다는 것을 알 수 있다.
  • LeaderId: X → 현재 컨트롤러 리더 노드이다.

 

- 토픽 생성 후 리더/복제 상태 확인

cd kafka/bin

./kafka-topics.sh --bootstrap-server 192.168.0.98:9096 --create --topic test-topic --partitions 3 --replication-factor 3
./kafka-topics.sh --bootstrap-server 192.168.0.98:9096 --describe --topic test-topic

 

 

 

 

  • 파티션 리더가 1,2,3에 골고루 분산 되어있음을 볼 수 있다.
  • Replicas, ISR에 [1,2,3] 모두 포함되어 있다.

 

5. 방화벽으로 포트를 차단한다면?

 

  • 컨트롤러 포트(9093/9094/9095) 차단 시
    • 컨트롤러 간 Raft 합의 불가
    • 로그에 Controller connection failed, Quorum not achieved 등이 출력되며 클러스터가 비정상 종료
    • 단방향으로 막을 경우, 프로세스가 살아있을 수 있고, 양방향 (in / out ) 으로 포트를 닫을경우 localhost 안에서도 통신이 불가하므로, kafka 가 실행되지 않는다.
# 1번 PC

sudo ufw deny 9093/tcp
sudo ufw status numbered

sudo ufw deny 9094/tcp
sudo ufw status numbered


# 2번 PC

sudo ufw deny 9095/tcp
sudo ufw status numbered

 

 

 

-> 단방향 차단시 3번 브로커(노드) 만 연결하지 못단다는 로그가 생성되고 과반 (1,2) 의 노드는 서로 통신 가능하기 때문에 프로세스가 죽지 않는다.

 

즉 in / out / 루프백 까지 포트를 차단하면 kafka 프로세스는 실행 후 얼마뒤에 종료된다.

 

 

  • 브로커 포트(9096/9097/9098) 차단 시
    • 클러스터 자체는 살아있지만 일부 파티션 리더/팔로워 간 복제가 안 됨
    • 로그에 Under-replicated partitions 경고 발생

 이 실험을 통해 왜 컨트롤러 포트는 양방향 열어야 하고, 브로커 포트는 Inbound만 열어주면 되는지 명확히 알 수 있다.

 

 

 

6. 헤어핀 현상

- 같은 서브넷 환경에서는 각 PC가 서로의 REAL IP를 직접 바라볼 수 있으므로, 설정 파일(listeners, advertised.listeners, controller.quorum.voters)에 해당 상대의 REAL IP만 정확히 적어주면 된다

 

-하지만 망연계(NAT) 인프라 환경에서는 상황이 달라진다.

 

  • 내 PC가 가진 REAL IP와, 상대방이 나를 바라볼 때 사용하는 NAT 변환된 외부 IP가 다르다.
  • 이 때문에 내가 내 설정에 localhost(혹은 REAL IP)를 그대로 쓰면, 상대는 NAT IP로만 접근할 수 있기 때문에 서로 인식이 어긋난다.
  • 특히 같은 머신 안에서 자기 자신을 NAT IP로 호출하려 하면, 헤어핀 NAT(Loopback NAT) 기능이 필요하다.
  • 장비나 방화벽이 이를 지원하지 않으면 **자기 자신을 인식하지 못하는 문제(헤어핀 현상)**가 발생한다.

 

- 두 PC 모두 broker+controller 로 운영(PC1: broker1/2, PC2: broker3) 하면서 이 구조에서 헤어핀 회피 + NAT 통과를 동시에 만족하려면

 

  • controller.quorum.voters 는 모든 노드에서 동일한 문자열을 쓰고,
  • 그 안의 호스트명을 /etc/hosts 로 각 PC에서 다르게 해석시키며,
  • 브로커의 advertised.listeners 에도 호스트명을 쓰고 split-horizon(PC1과 PC2에서 다르게 해석)을 적용해야 한다.

 

node.1 설정 (PC1)

process.roles=broker,controller
node.id=1

# 모든 노드에서 "문자열 동일" (호스트명 사용)
controller.listener.names=CONTROLLER
controller.quorum.voters=1@ctrl-n1:9093,2@ctrl-n2:9094,3@ctrl-n3:9095

# 바인딩은 로컬 존재 주소(0.0.0.0 권장)
listeners=PLAINTEXT://0.0.0.0:9096,CONTROLLER://0.0.0.0:9093

# 광고는 호스트명(브로커용) 사용
advertised.listeners=PLAINTEXT://broker-n1:9096

inter.broker.listener.name=PLAINTEXT
listener.security.protocol.map=PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT

log.dirs=/data/kafka/node1

 

 

 

node.2 설정(PC1)

process.roles=broker,controller
node.id=2

controller.listener.names=CONTROLLER
controller.quorum.voters=1@ctrl-n1:9093,2@ctrl-n2:9094,3@ctrl-n3:9095

listeners=PLAINTEXT://0.0.0.0:9097,CONTROLLER://0.0.0.0:9094
advertised.listeners=PLAINTEXT://broker-n2:9097

inter.broker.listener.name=PLAINTEXT
listener.security.protocol.map=PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT

log.dirs=/data/kafka/node2

 

 

node.3 설정 (PC2)

process.roles=broker,controller
node.id=3

controller.listener.names=CONTROLLER
controller.quorum.voters=1@ctrl-n1:9093,2@ctrl-n2:9094,3@ctrl-n3:9095

listeners=PLAINTEXT://0.0.0.0:9098,CONTROLLER://0.0.0.0:9095
advertised.listeners=PLAINTEXT://broker-n3:9098

inter.broker.listener.name=PLAINTEXT
listener.security.protocol.map=PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT

log.dirs=/data/kafka/node3

 

 

- /etc/hosts 파일 설정

 

PC 1 

# 컨트롤러 이름 → 자기 자신은 REAL, 상대는 NAT
192.168.0.98      ctrl-n1
192.168.0.98      ctrl-n2
200.200.200.200   ctrl-n3

# 브로커 광고 이름 → 자기 자신(두 개)은 loopback/REAL, 상대는 NAT
127.0.0.1         broker-n1
127.0.0.1         broker-n2
200.200.200.200   broker-n3

 

PC2

# 컨트롤러 이름 → 상대는 NAT, 자기 자신은 REAL
100.100.100.100   ctrl-n1
100.100.100.100   ctrl-n2
192.168.0.99      ctrl-n3

# 브로커 광고 이름 → 상대는 NAT, 자기 자신은 loopback/REAL
100.100.100.100   broker-n1
100.100.100.100   broker-n2
127.0.0.1         broker-n3

 

 

- 기존 노드 구성이 같고, 데이터를 유지한다면 아래 진행 절차를 따르지 않아도 되지만, 새로 설정을 적용하여 재시작 하려 한다면

새로운 uuid 를 발급하고 세 브로커를 묶어주는 설정을 해야 한다.

 

CLUSTER_ID=$(bin/kafka-storage.sh random-uuid)

bin/kafka-storage.sh format -t $CLUSTER_ID -c server-1.properties
bin/kafka-storage.sh format -t $CLUSTER_ID -c server-2.properties
bin/kafka-storage.sh format -t $CLUSTER_ID -c server-3.properties

bin/kafka-storage.sh info   -c server-1.properties  # node.id=1 / 같은 cluster.id 확인