들어가기
최근 모놀리식 아키텍처와 MSA( MircroService Architecture)에 대해 공부를 하였다. 모놀리식 아키텍처는 하나의 애플리케이션 안에 서비스의 모든 부분을 담아서 개발을 하는 것이고, MSA는 서비스의 기능별로 다른 서버를 두어 각각의 애플리케이션으로 개발하는 것이다.
이러한 MSA는 기능별로 독립된 서버이기에 서로의 의존성을 낮추고 나눠서 개발할 수 있으며, 단위테스트가 용이하다는 장점이 있다. 단점으로는 모놀리식 아키텍처보다 훨씬 복잡하다는 점이 있다.
그렇다면 MSA 방식으로 기능을 구현한 애플리케이션들 간에는 어떻게 소통이 이루어질 수 있을까?
gateway를 통해 서로 간의 api를 호출하는 방식이 있고 메시지를 주고받아 소통을 하는 방식이 있다고 한다.
메시지 처리 방식으로는 '카프카(kafka)'가 있는데, 이 글에선 카프카가 어떻게 동작하는지에 대해 간단하게 작성할 것이다.
카프카(Kafka)는 무엇인가?
카프카는 정확히 어떤 것일까?
카프카는 분산환경에서 대규모 데이터를 처리하기 위한 이벤트 스트리밍 플랫폼으로, 메시지를 송신하는 측과 수신하는 측이 비동기적으로 메시지를 주고받을 수 있도록 한다.
아래의 사진을 봐보자.
여러 송·수신 측이 매우 복잡하게 연결되어 있다.
카프카를 적용한다면 아래와 같이 생각할 수 있다.
깔끔해지지 않았나?
카프카가 도입됨으로써 송신 측과 수신 측의 의존성이 낮아지고, 장애 문제 또한 완화된다.
그리고 동기 방식에서 비동기 방식의 프로세스로 변화되었다. 이건 무슨 의미일까?
카프카를 적용하기 전에는 송신 측에서 수신 측으로 메시지를 보냈을 때, 수신 측으로부터 응답을 받을 때까지 송신 측에서는 대기하였다. 이러한 방식이 동기 방식이다.
그런데 카프카를 적용함으로써 비동기 방식으로 바뀌었다. 송신 측에서 메시지를 보내기만 할 뿐 굳이 수신 측의 응답을 받지 않고도 다음 행동을 이어가고, 수신 측에게는 카프카가 메시지를 전달해 준다.
이러한 변환으로 인해 송신 측과 수신 측의 의존성이 낮아졌다고 할 수 있는 것이다.
카프카의 장애 복구는 카프카 클러스터에 서로 다른 포트 번호를 가진 '브로커(Broker)'가 여러 개 있음으로써 가능하게 한다. 송신 측과 수신 측은 '토픽(topic)'이라는 공통된 주제를 가지고 메시지를 주고받는다. 토픽은 메시지 종류를 구분하기 위한 카프카의 기본적인 단위로, 데이터베이스의 테이블 같은 것으로 이해하면 된다. 토픽을 생성 시 지정한 브로커들이 토픽을 공유할 수 있기에 특정 브로커에 장애가 발생한다 해도 다른 브로커에 의해 정상적으로 실행이 된다.
브로커를 통해 동일한 토픽으로 송신, 수신하는 측을 각각 'Producer', 'Consumer'라고 한다.
'주키퍼(Zookeeper)'는 분산된 브로커들을 관리하고 조정하는 용도로 클러스터의 상태를 유지하고 브로커의 메타데이터를 저장하는데 사용된다.
카프카 클러스터 내 브로커를 실행하기 위해선 항상 주키퍼를 실행해야 한다.
그런데, 주키퍼는 카프카 클러스터 외부에서 실행되는 것이 문제가 되어 최근 주키퍼를 제거하고 카프카를 실행시킬 수 있도록 'kafka KRaft' 모드가 추가되었다. 이에 대한 자세한 설명은 아래의 링크들을 확인하길 바란다.
https://medium.com/spitha-techblog/kafka-kraft-435fe2bab1de
https://velog.io/@joyfulbean/Apache-Kafka-Zookeeper-%EC%A0%9C%EA%B1%B0-%EC%9D%B4%EC%9C%A0
Producer가 토픽을 지정하여 메시지를 발행하면 브로커는 해당 토픽의 하위 저장소인 '파티션(Partition)'에 저장한다.
토픽을 생성할 때 그 하위 요소인 파티션에 '레플리케이션 펙터(Replication Factor)'를 설정이 가능한다. 최소 3이 바람직한데, 이는 하나의 파티션을 3개로 복제하고, 이 3개를 브로커들이 나눠서 가지는 것이다.
만약 브로커가 3개가 있고 Partition0라는 파티션의 레플리케이션 펙터가 3개 있다면 브로커마다 Partition0를 한 개씩 가지는 것이다. 레플리케이션 펙터가 4개라면 특정 브로커가 2개를 가지고, 2개라면 특정 브로커가 Partition0를 가지지 못하는 것이다. 이러한 파티션은 '리더 파티션'과 '팔로워 파티션'으로 구분이 되는데, 리더 파티션에서 읽기와 쓰기가 실행된다. 팔로워 파티션은 읽고 쓰지 않고 그저 대기 상태이며, 리더 파티션이 장애가 있을 경우 카프카 클러스터 내에 컨트롤러 모듈이 이를 탐지하여 팔로워 파티션 중 하나를 리더 파티션으로 하여 서비스를 지속시킨다. 새로운 리더를 지정하는 동안 Producer는 계속 재전송을 한다.
하지만 위와 같은 구조에선 리더 파티션으로만 메시지 처리가 이루어지므로 데이터의 분산이 효과적으로 이뤄지지 않는다.
이를 위해 아래와 같이 여러 파티션을 운용하여 트래픽을 분산시켜 동시 처리 능력을 향상할 수 있다.
리눅스에서 카프카(Kafka) 실행
1. 한 개의 브로커
자 이제 실제로 카프카를 실행시켜 보자.
이 글에선 AWS EC2를 사용하여 진행하였다. 주키퍼, 브로커 서버의 포트를 미리 열어두자.(2181과 9092, 9093, 9094. 혹은 개인의 설정에 따라 열면 된다.)
우선 기본적으로 카프카를 실행하기 위해선 jdk를 설치해야 한다. 아래의 명령어들을 순차적으로 입력하자.
sudo apt-get update
sudo apt-get -y upgrade
sudo apt-get install openjdk-11-jdk
이후카프카를 설치하는데 wget를 통해 원하는 버전을 설치하자. 이 글에선 2.8.2 버전을 사용하였다.
wget https://archive.apache.org/dist/kafka/2.8.2/kafka_2.13-2.8.2.tgz
압축을 풀어야 하기에 아래와 같은 명령어를 입력한다.
tar xvf kafka_2.13-2.8.2.tgz
설치가 완료되면 kafka_2.13-2.8.2라는 폴더가 생긴다.
이제 본격적으로 카프카를 실행해 보자.
먼저 주키퍼 서버를 실행해야 한다.
아래의 명령어를 입력하자.
/home/ubuntu/kafka_2.13-2.8.2/bin/zookeeper-server-start.sh -daemon /home/ubuntu/kafka_2.13-2.8.2/config/zookeeper.properties
-daemon 옵션을 통해 백그라운드로 실행할 수 있다. 실행 중인 주키퍼 서버를 닫으려면 아래와 같은 명령어를 입력한다.
/home/ubuntu/kafka_2.13-2.8.2/bin/zookeeper-server-stop.sh
주키퍼 서버를 실행했으면 브로커를 실행하자. 우선 한 개의 브로커만을 생성할 것이다. 아래의 명령어를 입력하자.
/home/ubuntu/kafka_2.13-2.8.2/bin/kafka-server-start.sh -daemon /home/ubuntu/kafka_2.13-2.8.2/config/server.properties
브로커를 생성했으면 이제 토픽을 생성해 보자. 토픽생성은 아래의 명령어를 통해 생성할 수 있다.
/home/ubuntu/kafka_2.13-2.8.2/bin/kafka-topics.sh --create --bootstrap-server 3.39.228.124:9092 --topic test-topic
--bootstrap-server 옵션으로는 브로커 서버가 실행 중인 주소와 포트를 적는데 위에선 EC2의 서버와 9092 포트를 지정해 주었다. --create 옵션으로 생성할 수 있고, --describe 옵션으로 생성된 토픽을 조회할 수 있다. 아래의 사진을 봐보자.
따로 파티션 및 레플리케이션 펙터를 지정하지 않았기에 전부 0인 것을 알 수 있다.
이제 생성한 토픽을 가지는 Producer과 Consumer를 생성해 보자. 아래는 Producer로 실행하는 명령어이다.
/home/ubuntu/kafka_2.13-2.8.2/bin/kafka-console-producer.sh --bootstrap-server 3.39.228.124:9092 --topic topic-test
위 명령어를 입력하면 입력 프롬프트가 뜨고, 메시지를 입력하면 브로커를 통해 Consumer로 전해진다. 아래의 명령어를 통해 Consumer로 실행시켜 보자.
/home/ubuntu/kafka_2.13-2.8.2/bin/kafka-console-consumer.sh --bootstrap-server 3.39.228.124:9092 --topic topic-test --from-beginning
--from-beginning 옵션을 통해 해당 토픽의 가장 첫 메시지부터 조회할 수 있다. 이 옵션을 적용하지 않으면 Consumer가 실행된 이후의 메시지만 수신할 수 있다.
아래는 메시지가 수신되고 있는 사진이다.
주의 사항을 하나 말하자면 만약 Producer와 Consumer가 Broker와 같은 서버에서 실행하는 것이 아니라면 server.properties 파일을 수정해야 한다. 파일을 열면 아래와 같이 adversised.listeners가 있는데 외부에서 브로커로 접근할 때 접근을 허용할 주소를 적어주는 것으로 브로커 서버의 IP 주로 와 포트번호를 적어주면 된다.
2. 여러 개의 브로커
한 개의 브로커로 있을 때는 본격적인 트래픽 분산의 효과를 발휘하지 못하였다. 이제는 여러 브로커를 운용하여 파티션과 레플리케이션 펙터를 통해 트래픽이 분산되는 형태로 실행할 것이다.
이 글에선 브로커를 3개를 실행할 것이다.
어떻게 브로커를 여러 개 생성할 수 있을까?
바로 server.properties 파일마다 브로커를 생성할 수 있다. 브로커를 실행할 때 kafka-server-start.sh 파일을 server.properties 파일을 기반으로 실행을 하였다. 이 때 server.properties를 일부 수정해서 server1.properties, server2.properties 등 다른 파일로 추가하면 해당 properties 파일만큼 브로커를 생성할 수 있다.
수정할 부분은 브로커 고유 아이디, 주소 및 포트, 로그 파일 저장 경로이다. 아래의 사진을 봐보자.
붉은색 원을 칠한 부분이 수정하는 부분이다. 각각의 properties 만큼 실행을 한 후 jps -m 명령어를 통해 브로커 실행 여부를 확인할 수 있다.
이제 토픽을 생성해 보자. 토픽을 생성 시 브로커를 지정하는데 9092, 9093, 9094 포트로 3개의 브로커가 실행 중이다. 브로커들은 주키퍼에 의해 클러스터로 관리되고 있기 때문에 --bootstram-server 옵션에 3개의 브로커를 전부 지정해도 되고 3개 중 한 개만 지정을 해도 3개의 브로커가 전부 연결된다. 아래의 명령어를 통해 새로운 토픽을 생성해 보자.
/home/ubuntu/kafka_2.13-2.8.2/bin/kafka-topics.sh --create --bootstrap-server 3.39.228.124:9092 --partitions 3 --replication-factor 2 --topic test-topic2
이번에는 파티션을 3, 레플리케이션 펙터를 2로 지정하였다. 어떻게 됐을까?
아래는 --describe 옵션을 지정하여 토픽을 조회한 사진이다.
위 결과는 아래와 같이 배치가 돼있다.
이렇게 트래픽을 분산시킬 수가 있다.
이제 Producer, Consumer로 실행해 보자. 토픽과 마찬가지로 어느 브로커 주소를 지정하든 상관없다.
아래는 Consumer로 수신된 메시지들이다.
참고로 아래와 같이 topic.sh 실행 시 --list 옵션을 통해 해당 브로커에 생성된 토픽 목록을 확인할 수 있다.
결론
이렇게 간단하게 카프카에 대해 알아보았고 리눅스 서버에 직접 실행을 해보았다.
카프카는 MSA 방식의 서비스에서 애플리케이션 간 메시지 처리를 위한 방식 중 하나로 종종 사용되고 있다고 한다.
본격적으로 MSA 프로젝트를 진행하기 전 카프카에 대해 공부하는 것이 좋다고 생각한다.
다음 글에는 이제 Springboot 상에서 브로커를 통해 메시지를 주고받는 것을 실습하는 과정을 담을 것이다.
참고
https://medium.com/spitha-techblog/kafka-kraft-435fe2bab1de
https://velog.io/@joyfulbean/Apache-Kafka-Zookeeper-%EC%A0%9C%EA%B1%B0-%EC%9D%B4%EC%9C%A0
https://velog.io/@hyun6ik/Apache-Kafka-Broker-Zookeeper
https://xangmin.tistory.com/169
https://okky.kr/questions/762929
'kafka' 카테고리의 다른 글
다중 서버일 경우 Kafka를 통한 채팅 서버 중계(with stomp, spring boot) (0) | 2024.06.17 |
---|---|
Kafka - Producer 메시지 분배 전략(파티셔닝 전략)과 배치(feat. 하나의 파티션으로만 메시지가 전송된다?) (0) | 2024.06.06 |
카프카(Kafka)를 스프링부트와 함께 사용해보자! (1) | 2023.12.14 |