1. Message Broker
vs Event Broker
1) Message Broker
메시지 브로커
는 일반적으로 대기업들에서 대규모 메시지 기반 미들웨어 아키텍쳐에서 사용되어 왔다.미들웨어
는 서비스하는 애플리케이션들을 보다 효율적으로 아키텍처들을 연결하는 요소들로 작동하는 소프트웨어이다.
- 예를 들어, 메시징 플랫폼, 인증 플랫폼, 데이터베이스 등이 있다.
- 또한,
메시지 브로커
는 메시지 브로커에 있는 큐에 데이터를 보내고 받는프로듀서
와컨슈머
를 통해 메시지를 통신하고 네트워크를 맺는 용도로 사용해왔다.
메시지 브로커
는 메시지를 받아서 적절히 처리하고나서즉시
또는짧은 시간 내
에삭제되는 구조
이다.
2) Event Broker
이벤트 브로커
는 ‘메시지 브로커’의 구조와 다른 구조로 만들어져 있다.
- a. 이벤트 또는 메시지라고도 불리는
레코드
인 이 장부를 딱 하나만 보관하고인덱스
를 통해개별 액세스
를 관리한다.
- b. 업무상 필요한 시간 동안, 이벤트를 보존할 수 있다. 이것이 메시지 브로커와 가장 큰 차이점이다.
3) 최종 정리
메시지 브로커
는 데이터를 보내고, 처리하고 삭제한다. 하지만, 이벤트 브로커는 데이터를 삭제하지 않는다.
이벤트 브로커
가 데이터를 삭제하지 않는 이유?이벤트 브로커
에서 ‘이벤트’라는 의미 때문이다. 이벤트 브로커는 서비스에서 나오는 이벤트를 마치 데이터베이스에 저장하듯이 이벤트 브로커의 큐에 저장한다.- 이렇게 저장함으로써 얻는 명확한 이점이 있다.
4) 이벤트 브로커 이점
- 첫번째 이점은 딱 한번 일어난 이벤트 데이터를 브로커에 저장함으로서 단일 진실 공급원으로 상요할 수 있다.
- 두번째는 장애가 발생했을 때, 장애가 일어난 지점부터 재처리할 수 있다.
- 세번째는 많은 양의 실시간 스트림 데이터를 효과적으로 처리할 수 있다는 특징이 있다. 그외에는 MSA에서 중요한 역할을 맡을 수 있다.
- 종류** : 메시지 브로커는 보통
Redis
,RabbitMQ
를 이용한다. 이벤트 브로커는카프카
나 AWS의키네시스
가 대표적이다.
2. Kafka
1) Kafka 구조
- 먼저, Kafka는 Producer, Kafka, Consumer, ZooKeeper 이렇게 총 네 가지로 분리를 할 수가 있다.
- Producer는 카프카로 메시지를 보내는 역할을 한다. 그리고 그 카프카는 Producer가 보낸 메시지를 저장하는 역할을 한다.
- Consumer는 카프카에 저장되어 있는 메시지를 가져오는 역할을 한다. 그리고 그 카프카는 Producer가 보낸 메시지를 저장하는 역할을 한다.
- 그리고 이 카프카는 분산 코디네이터 시스템인 ZooKeeper와 연결을 하면서 메타데이터 관리라든지 아니면 클러스터의 노드 관리라든지 이런 것들을 ZooKeeper를 통해서 하고 있다.
2) 카프카 클러스터 설계 스펙 및 과정
- 그래서, 만약에 카프카 클러스터를 처음 구성한다고 하면 주키퍼 같은 경우에는 Replication 방식, 커런 방식이기 때문에 홀수를 유지시켜줘야 된다.
- 그래서, 최소 수량인 3대로 구성하는 것이다. 3대로 구성을 해줘야 된다. 그리고, 카프카 같은 경우에는 Replication 방식이 커런 방식이 아니다.
- 그래서 홀수든 짝수든 전혀 상관이 없지만 Replication-Factor를 최소 3으로 유지를 하는 경우가 많기 때문에 최소 브로커 수를, 카프카 수를 3대로 하는게 좋다.
- 그래서, 총 최소 6대의 서버가 필요하게 된다. 이 카프카 같은 경우에는 만약에 사용량이 몰려서 서버를 증설하거나 이런 경우가 발생을 하면 주키퍼 같은 경우에는 3대로 구성을 해줘야 된다.
- 그래서 총 최소 6대의 서버가 필요하게 된다. 주키퍼는 그대로 내버려 둔 채 카프카만 서버를 추가해서 이렇게 스케일아웃하는 형식으로 5대, 10대 이런 식으로 스케일아웃 할 수가 있다.
- 카카오에서는 전사 공용 카프카를 운영을 하고 있다. 처음에 오픈했을 때 당시에는 2개의 클러스터로 약 서버는 10대 정도로 시작을 했었다.
- 그런데 지금 오늘날에 이르러서는 7개의 클러스터로 약 130여 대 정도의 서버를 운영하고 있다. 그리고 이 130여 대의 서버는 카카오에서 IDC를 여러 군데를 사용하고 있다.
- 메인으로 사용하고 있는 IDC 두 곳에 집중을 해서 각 IDC마다 주키퍼 세트를 하나씩 두고 있다. 그 주키퍼 세트와 카프카 클러스터를 연결해서 총 7개의 클러스터를 운영을 하고 있다.
- 그리고 이 서비스들은 카카오에서 많은 분들이 알고 있는 다음 거래가 될 수 있는 서비스이다.
- 이런 서비스들이 공용 카프카 클러스터 130여 대의 클러스터를 거의 모두 이용하고 있다고 보시면 된다. 그래서 이러한 카카오 서비스들이 하루에 이 카프카를 통해서 처리하고 있는 메시지 건수는 약 한 2600억 개의 메시지를 하루에 처리하고 있다.
- 이게 이 카프카를 통해서 처리하고 있는 메시지 건수는 초당 한 300만 건의 메시지를 쉬지 않고 계속 처리하고 있다고 보시면 된다. 그리고 카프카로 들어오는 데이터 사이즈를 보게 되면 하루에 240테라바이트 정도의 데이터가 카프카를 통해서 데이터가 들어오게 된다.
- 그리고 반대로 하루에 370테라바이트 정도의 사이즈가 하루에 370테라바이트 정도의 데이터가 들어오게 되고요 카프카를 통해서 바깥으로 나가게 된다. 카프카 같은 경우에는 하나의 토픽을 기준으로 프로듀서가 메시지를 보내고 여러 컨슈머들이 붙어서 가져가는 구조가 일반적인데 이렇게 인보다 아웃이 1.3배, 4배, 5배 많은 수치를 보면 카프카를 잘 활용하고 있다는 것을 알 수가 있다.
- 그리고 가동률이라는 것을 한번 계산을 해보자. 카프카를 운영한 지는 한 2년 정도 운영을 하게 되었는데 크게 클러스터 전체가 이슈가 생겼던 것은 두 건 정도가 있었다. 그래서, 그거를 약간 시간을 따져보니까 한 시간이 채 되지 않았지만 대략적인 시간으로 계산을 해봤을 때 가동률이 약 99.99% 정도 나왔다.
- 사실, 이렇게 99.99%가 나온 것은 거의 잠들지 않은 서비스이다. 그래서 이 정도만으로도 이 정도만으로도 기술이 가능한 서비스를 하고 있었다고 볼 수가 있을 것 같다.
3) 카프카 사용기 이슈
a. 첫 번째 이슈 : Shrinking ISR
a) ISR**
ISR
은In-Sync Replica
라는 첫 글자를 따서ISR
이라고 부르게 된다.
- ISR이 다른 어플리케이션에서 많이 쓰이는 용어는 아니다.
- 카프카에서 특화돼서 사용하는 용어 중의 하나이다. 그리고, 이게
Replication
이 되어 있고 똑같은 구성원이 있기 때문에 이 구성원을 분류를 해줘야 된다.
b) Replication** : Leader, Follower
- 카프카에서는 이
Replication
분류를 위해서Leader
와Follower
로 분류를 하고 있다. 이렇게, 분류된 만큼 각각의 역할이 다르게 된다.
- 그래서,
Leader
는 읽고 쓰기를 주로 하고 있고 그리고Follower
들은 그Leader
랑 주기적으로 동기화하는 작업을 하게 된다.
- 그리고 ISR이 생겨난 이유 자체가 이게 가장 중요한 이유인데 ISR의 구성원만이
Leader
의 자격을 가질 수 있기 때문이다.
- 이렇게 카프카 클러스터가 있다고 가정을 하고 거기에 브로커 3대가 있다고 가정을 하자.
- 그리고
Replication-Factor
는 ‘3’이라고 가정을 하면, 이 카프카에는Topic
이 3개가 있다.
- 그리고 이
Topic
은partition
이라는 단위로 쪼개질 수가 있다. 그래서 1개서부터 10개, 20개, 20개 이런 식으로 쪼개질 수가 있는데 여기서는 예제를 위해서partition
하나로만 표시하면,partition 1
은 여기 보는 것처럼 0번부터 시작하게 된다. 그래서 이거는Topic
하나에partition
하나를 나타내고 있는 것이다. 그리고Leader
와Follower
가 있기 때문에Leader
는 별도로 표시했다.
- 그리고 이 리더와
Follower
들을 이렇게 그룹핑하고 있는 이것이 바로ISR
이라고 하는 것이다. 그래서 브로커 1번이 예를 들어서 장애가 발생을 하게 되면Leader
에 문제가 생긴 것이다.
- 그렇게 되면 이런 식으로
Follower
중에 하나가 새로운Leader
로 넘어가게 된다.
- 그리고 ISR이 축소가 되었다. 이렇게 ISR이 축소되는 것을 카프카에서는
Shrinking ISR
이라고 한다.
c) 실무** : 이상 감지 예시
- 실무* : 실무에서 카프카를 운영하고 있었는데 어느 날 갑자기 브로커 서버에 문제가 있냐 아니면 이런 식의 문의가 왔었다. 이벤트로 메시지를 보내는데 메시지가 잘 안 간다 아니면 메시지를 가져오는데 잘 못 받는다 등의 이런 식으로 문의가 왔었다.
- 그래서 한 번 서버 전체적으로 상태를 봤는데 알람은 전혀 안 왔기 때문에 서버 전체적으로 봤는데 서버 다운된 것도 하나도 없이 모두 잘 동작을 하고 있었다.
- 그런데 보통 그래프, 그래프 하나를 이용해서 이렇게 그래프를 보는데 ‘인’이랑 ‘아웃’ 쪽에 데이터가 그래프가 약간 좀 이상한 현상이 보이기 시작했다.
- 그래서 뭔가 이상을 감지하고 브로커 서버에 전체 로그인을 해서 로그를 보기 시작했지만 여기서 보시면 여기 로그 레벨이 INFO라고 찍혀 있는 부분을 보면 다음에도 주의해야 한다.
- 카프카에서는 로그 레벨이 총 3단계로 나눠져 있다.
INFO
,WARNING
,ERROR
이렇게 나눠져 있는데INFO
는 정말 말 그대로INFO
레벨이다.INFO
성 로그다.WARNING
은 경고성 그리고ERROR
는 정말 카프카에 문제가 생겼을 때 발생한 로그다.
- 처음에는 이
INFO
성 로그는 제외하고WARNING
또는ERROR
메세지가 브로커 로그에 한 줄 기록되자마자 바로 알림을 받을 수 있도록 알람 설정을 해 놨었는데 지금 보는 것처럼 INFO성 로그였기 때문에 알람을 미리 받지 못했다.
- 그리고 이 문제성 로그를 보면, 여기 브로커 5번에서
Shrinking ISR
이 발생을 했고 이 토픽에 대해서 이렇게 축소되는 이런 이슈가 발생을 했던 것이다. 그래서, 이거를 약간 시각화해서 보면은 클러스터 내에 브로커들이 여러 대가 있었는데 브로커 5번이 오동작으로 인해서 모든ISR
자기가 가지고 있던 파티션에 대해서 모든ISR
을 축소하는 현상이 발생했다.
- 그리고 이 브로커 5번이 모든
ISR
을 축소하는 현상이 발생했다. 이 브로커 5번이 자기가 가지고 있던 파티션에 대해서 리더를 다 가져가 버렸기 때문에 다른 브로커들은 이 브로커 5번과 리플리케이션을 해야 되는데 이 리플리케이션이 안 되는 이런 에러가 발생을 하고 있었 것이다.
- 그래서 이 증상은 그 당시에 사용하고 있었던 0.10.1.0의 버그였다. 그리고 이 내용을 확인했을 때 이미 상위 버전이 릴리즈되어서 이 버그에 대해서는 픽스가 되었던 상황이었다.
- 그래서, 이 버그에 대해서는 픽스가 되었던 상황이었다.
- 여기서 한 가지 말하고 싶은 것은 브로커에서 로그가
WARNING
또는ERROR
로그만 이렇게 감지를 한다고 하더라도 이렇게INFO
로그가 왜 발생했는지에 대해서 조금 더 한번 고민을 해 보시면 나중에 이슈가 생기더라도 트러블 슈팅하는데 도움될 것이다.
d) 카프카 버전 업그레이드 방식**
- 그래서, 결국에 이 버전을 버리고 상위 버전으로 업그레이드를 해야 되는데 이 카프카에서 버전 업그레이드를 하는 방식은 두 가지가 있다.
A. 업그레이드 방식 : 다운타임 유무**
- 첫 번째로는 다운타임을 가질 수 있는 환경이랑 그리고 다운타임을 가질 수 없는 환경 이렇게 크게 두 가지로 나눌 수가 있는데 다운타임을 가질 수 있는 환경은 정말 심플하게 작업을 할 수가 있다.
- 모든 브로커를 다 내려버리고 최신 버전으로 업그레이드 한 다음에 브로커를 그냥 실행해 주면 업그레이드가 끝나게 된다.
- 하지만, 아마 일반적인 보통의 상황들이 다운타임을 가질 수 없는 환경일 것이다. 이런 상황에서는 클러스터 내 브로커를 한 대씩 내렸다가 버전 업그레이드하고 올리고 내렸다가 버전 업그레이드하고 올리고 이런 식으로 작업을 진행해야 한다.
- 그래서, 전체 클러스터는 다운되지 않은 상태에서 한 대씩 한 대씩 버전 업그레이드를 진행해야 된다.
- 그래서, 카카오에서는 크리티컬한 이슈가 방금 아까 그런 버그같은 이런 일들이 발생을 하거나 아니면 카프카의 새로운 신규 기능이 추가되어서 그 기능을 써야만 하는 경우, 그럴 때를 다운타임 없이 버전 업그레이드를 진행을 하고 있다.
b. 두번째 이슈 : 전원 이슈
- 그리고 두 번째 이슈는 전원 이슈였다. 일반적으로 서버들을 IDC에 두게 된다.
- 그리고 그 IDC에는 랙이라고 불리우는 공간에다가 서버를 두게 되는데 랙은 뭐 이런 선반 같은 개념이다.
- 좀 더 자세히 보면 이런 식으로 이렇게 랙 1, 2, 3이 있다. 그리고, 이 랙 1, 2, 3에다가 이제 원하는 서버들을 자유롭게 꽂게 된다.
- 브로커 서버, DB 서버, 웹 서버 뭐 이런 식으로 랙에다가 서버를 꽂게 됩니다. 근데 카프카 같은 경우에는 이제 클러스터 개념이기 때문에 3대가 있다고 가정을 해보고 그 브로커 1, 2, 3을 랙 1번에다가만 몰아놨다고 가정하자.
- 사실 이렇게 구성을 하게 되면은 랙 1번이 문제가 생기게 되면 클러스터 전체가 다운되는 문제가 생기게 된다.
- 그렇기 때문에 각 랙마다 브로커 서버를 분산해서 한 대씩 한 대씩 배치하는 것이 효율적인 배치이다.
- 근데 그 랙 전원장애가 발생을 했다고 앞서 말했었는데 IDC의 랙 전원장애가 발생했을 때 랙 한 열이, 그러니까 약 한 15개 정도의 렉의 전원이 한 번에 다다다닥 전원이 나간 상황이다.
- 그러니까, 랙 15개 내에 클러스터가 한 10개 이렇게 구성이 되어 있었는데 거기에 랙 전원이 전부 다 나가면서 모든 브로커가 다운되는 상황을 겪게 된 것이다.
- 그래서 이렇게 모든 브로커가 다운되는 경우가 흔하진 않지만 이런 경우에 대해서도 한 번쯤은 고민을 해야 한다.
a) 다운타임이 없는 경우의 전원 이슈 해결 예시
- 예를 들어, 이렇게 랙 1, 2, 3이 있고 거기에 브로커 1, 2, 3이 있다고 가정을 해보자.
- 그리고 거기에 ‘peter-topic’이라는 게 있고 메시지 ‘a’를 가지고 있다고 가정을 해보자. 그리고 노란색은 리더고 팔로워 두 개가 있다고 가정을 하자.
- 그런데 여기서 랙 1번에 전원장애가 발생을 한 것이다. 이렇게 전원장애가 발생을 하게 되면 팔로워에게 새로운 리더가 넘어가게 되고 다음 메시지인 ‘b’라는 메시지를 받게 된다.
- 그리고 렉 2번도 전원장애가 발생을 했고 다음 리더인 마지막 브로커로 리더가 넘어가게 된다. 그리고 마지막 브로커는 다음 메시지인 ‘c’라는 메시지를 받게 된다.
- 그런데 하나 남은 브로커도 역시 전원장애를 피해갈 수는 없다.
- 렉 3번에 전원장애가 발생을 하게 된다. 그럼 전원장애가 발생한 이후에 렉 3번이 가장 먼저 복구가 되게 되면 마지막 리더가 그냥 바로 새로운 리더가 되는 것이다.
- 계속 이어지는 리더가 되는 것이다. 그러고 나서 다음 메시지인 ‘d’라는 메시지를 받게 되고 나머지 장애에 빠져 있었던 브로커 2번과 1번이 복구가 됐을 때, 렉 3번이 전원장애가 발생을 하게 된다.
- 이미 리더가 있기 때문에 그 리더로부터 모든 메시지를 동기화하게 된다. 결국에는 전원장애로 인해서 모든 브로커가 다운됐음에도 불구하고 메시지 손실은 하나도 없게 되는 현상이 있다. 하지만 가장 먼저 다운됐었던 브로커 1번이 가장 먼저 복구가 됐다고 가정을 해보자.
- 그리고 이 브로커 1번이 바로 리더가 아무도 없기 때문에 즉시 리더의 역할을 하게 된다. 그러고 나서 메시지 d를 받게 되는 거죠. 다음에 랙 2번과 3번의 문제가 해결돼서 브로커가 올라왔을 때 이미 브로커 1번이 리더 역할을 하고 있기 때문에 모든 메시지를 리플리케이션 하게 된다. 결국 메시지 ‘b’와 ‘c’는 손실되게 된다.
b) 결론
- 사실 여기에서는 서비스의 영속성을 우선시 할 건지 아니면 데이터의 정합성을 우선시 할 건지 선택의 문제지 정답이 있는 것은 아니다.
- 근데 마지막 리더를 기다리는 옵션으로 설정을 해서 사용할 경우에 이렇게 모든 클러스터가 다운됐음에도 불구하고 메시지 손실을 없게 할 수가 있다.
- 하지만 우리는 최악의 시나리오도 고려를 해야 됩니다. 만약에 마지막 리더였던 서버가 전원장애 이후에 올라오지 않는 상황도 고려를 해야 되는 거죠.
- 뭔가 메인보드가 문제가 있다든지 아니면 뭔가 파워 서플라이가 문제가 있다든지 그래서 만약에 올라오지 않게 되면 다른 팔로우들은 이미 올라와 있는데도 마지막 리더가 올라오지 않기 때문에 장애 시간이 계속해서 길어질 수가 있다.
- 카카오에서는 전사 공용으로 사용하고 있기 때문에 장애가 발생을 했을 때, 최대한 장애 타임을 줄이고 빠르게 서비스에 투입되는 것이 최우선이었다.
- 그래서 이런 랙 전원장애가 발생을 했을 때, 서비스의 영속성을 우선시 했기 때문에 일부 메시지는 손실이 되었고 대신에 빠른 서비스 투입이 가능했었다.
- 그래서, 이런 사항을 잘 고려해서 용도에 맞게 카프카를 운영하면 사용하는데 도움이 될 것 같다.
4) Producer
a. Producer 개념
- 먼저,
Producer
에 대해서 알아보면 다음과 같다.Producer
는partition
의 리더로 메시지를 전달하는 역할을 하게 된다. 그리고 메시지를 전달할 때 특정partition
또는 랜덤partition
으로 전송을 하게 된다.
- 그리고 빠른 전송 속도가 보장이 되어야 효율성이 좋은 배치 처리가 가능하다. 그리고 설정을 통해서 배치 크기나 지연 시간 이런 것들이 조정이 가능하다.
- 배치나 지연 시간을 조정하는 방법을 다음과 같다.
a) ACK 개념
- 이
ACK
도Producer
가 할 수 있는 설정 중의 하나이다. 근데ACK
같은 경우에는 메시지 손실과 직접적인 관련이 있는 옵션 중의 하나이다. 그래서, 이Producer
에서ACK 옵션
이 가장 중요하다.
ACK
의 값은0
,1
,All
총 세 가지가 있다.
ACK 0
은 매우 빠르게 전송할 수 있지만partition
의Leader
로는 많은 상황이 있다.partition
의Leader
가 받았는지 확인하지 않는다. 즉, 내가 메시지를 보내고 난 다음에 상대방이 받았는지 확인을 하지 않고 바로 보내고 나의 역할은 끝난 것이다. 바로 다음 메시지를 보내게 된다. 그래서, 이런 경우에는 메시지 손실 위험이 되게 높다. 그런데, 이게 비율로 따지게 되면 사실 브로커도 아까 보신 것처럼 99.99% 거의 다운타임에서 다운되는 현상 없이 운영되고 있다.Producer
도 거의 다운되는 현상 없이 계속 메시지를 쏘기 때문에 퍼센테이지로 따지면 그렇게 큰 수치가 나는 것은 아니다.
- 다음은
ACK 1
이다. 메시지 전송도 빠른 편이고 그리고partition
의Leader
가 받았는지 메시지 내가 보낸 메시지를 받았는지 확인을 한다. 가장 많이 사용되는 옵션 중에 하나다. 그리고 최근에 사용되는Log Stash
,File Beat
이런 어플리케이션(ELK
에서 많이 사용됨)의 대부분의 기본값이 이ACK 1
이다.
- 그리고, 마지막으로
ACK ALL
은 메시지 전송은 가장 느리지만 이 메시지 전송이 가장 느린 이유는 팔로워도 메시지를 받았는지 확인을 하기 때문이다. 하지만, 그렇게 느린 상태지만 손실 없는 메시지 전송이 가능하다.
b) ACK 특징
- 그런데, 여기서 한 가지 좀 약간 의아한 궁금증이 있을 수 있다.
ACK 1
이 분명히Leader
가 받았는지 확인을 했는데 왜ACK ALL
이라는 옵션이 있어서 손실 없는 메시지 전송이 가능한지 이거에 대해서 좀 자세히 보면 다음과 같다.
- 예를 들어,
Producer
가ACK 1
이라는 값으로 메시지를 보낸다고 가정을 해보자. 그리고 이렇게 브로커가 3대가 있고 거기에는Peter-Topic
이라고 똑같은Topic
이 3개가 있다. 그리고, 마찬가지로Leader
와Follower
가 있게 된다. 그리고Producer
는Leader
에게 메시지를 받았는지 확인을 하게 된다.
- 그리고
Leader
는 메시지 A라는 메시지를 전달하게 된다.Leader
는 메시지를 저장하게 된다. 그리고 저장한 상태에서 내가 메시지를 잘 받았다고Producer
에게 알려준다.ACK
를 보내주게 되죠. 그리고 이Producer
동작과 달리브로커 내부 동작
에 의해서Follower
들과Replication
이 일어나게 된다.
- 그리고
Producer
는 다음 메시지인 B라는 메시지를 전송하게 된다. 그리고Leader
는 그 메시지를 전달하게 된다. 그리고Leader
는 그 메시지를 받고 난 다음에ACK
를 날려주게 된다. 그리고 나서 내부적으로Replication
이 일어나려고 하려는 찰나 그러니까Producer
한테ACK
는 보내줬고 내부적으로Replication
이 일어나려는 찰나 사실 이거는 0.00밀리세컨드 단위에 일어날 수 있는 일이긴 하다. 이 찰나에 브로커 1번이 다운되어 버리는 것이다. 다운 현상이 발생하게 되면 리더가 없어졌기 때문에Follower
중에 하나가 새로운Leader
역할을 하게 된다.
- 그리고
Producer
는Leader
에게 다음 메시지인 C라는 메시지를 보낸다. 내가 B라는 메시지까지 보내고ACK
를 받았기 때문에 C라는 메시지를 전송하게 되는 거죠. 프로듀서는 C라는 메시지를 저장하게 되고ACK
를 보내게 된다. 그리고 D라는 메시지 받게 되고 그리고 나서 브로커 1번이 원래Leader
였던 브로커 1번이 장애가 복구돼서 올라왔을 때, 자기가 올라오고 나니까 이미Leader
가 있다. 그러니까 그Leader
로부터Replication
이 일어나게 된다.
- 결과적으로
Producer
가Leader
가 받았는지 매번 체크를 하고ACK
를 받았지만 결과적으로 이렇게 메시지 손실이 발생을 하게 된다. 사실 이거 비율로 따지면 99.몇 퍼센트 이렇게 나올 것 같긴 한데 만약에 정말 중요한 이런 0.몇 퍼센트의 오차도 허용하고 싶지 않다고 한다면,Producer
를 사용할 때,ACK
를All
이라는 값을 사용하게 되면 손실 없는 메시지 전송이 가능하다.
b. 운영 단계 : Key 옵션 이슈
- 다음으로 운영하다 보니까 특정 부서에서 특정
partition
이 이상하다는 메시지가 왔었다.
브로커에 문제가 있습니까?
이런 식으로 얘기가 왔는데 상태를 보니까 모든 상태는 이상한 것들이 전혀 없었다. 브로커도 이상이 없었고 다른Topic
들도 이상이 전혀 없었다.
- 그런데 그
Topic
이 이상하다는 그Topic
만 그래프를 보니까partition
별로 균등하게 분배가 안 되는 것을 확인을 할 수가 있었다. 지금 이렇게 특정 일정 시간 동안 한쪽partition
으로 이렇게 메시지들이 몰리는 상황을 볼 수가 있다. 그래서, 확인하다 보니까 해당 부서에서는Producer
에Key
라는 옵션을 넣어서 사용하고 있었던 것이었다.
Key
라는 옵션이 뭔지 간단하게 알아보면 다음과 같다. 이Producer
가 그Topic
의partition
으로 메시지를 보내게 될 때,Key
라는 옵션을 사용할 수가 있다.
- 예를 들어서,
Key
에 ‘a’라는 옵션을 사용할 수 있게 되고 ‘a’라는 옵션을 줬는데 이 ‘a’라는 옵션을 줘서 메시지를 쏘게 되면 이partition
이 두 개가 있음에도 불구하고 ‘a’에 해당하는 하나의partition
으로만 메시지를 보내게 된다.
- 그래서 그 메시지 내용 자체는 중요하지 않다. 대신, 그
Key
값이 ‘a’라고 시작되는Key
값만 정해주게 되면 ‘a’라는Key
값은특정 partition
의 하나의partition
으로만 메시지를 전송하게 된다.
- 그런데 이
Key
값 자체가 그 필수 값이 아니라 만약에Key
값을 주지 않게 되면Key
값에none
이라고 표시가 된다. 그래서Key
값을 빼버리면 그Topic
의partition
으로 랜덤하게Round Robin
형태로 균등하게 분배해서 보내게 된다. 그래서 여기처럼Key
값이none
이라고 나오게 되고, 메시지를 균등하게 보내게 된다. 그래서 아까 같은 이슈 때, 그Key
값을 굳이 필요하지 않았기 때문에Key
값을 제거하고 나서는 이 뒤에 빨간 테두리에 보시는 것처럼 그Topic partition
별로 이렇게 균등하게 분산이 되는 것을 알 수가 있다.
- 그래서
Producer
옵션을 사용하실 때, 그Key
값을 필요로 하면특정 partition
으로만 보내야 된다라는 뭐 그런 게 필요하면Key
값을 넣어서 사용면 되고 그렇지 않으면 대부분 그냥 빼버리고 사용하면 이렇게 균등하게 분산시켜서 메시지를 보낼 수가 있다.
5) Consumer
Consumer
는 그partition
의Leader
에게Fetch
요청하는 역할을 한다.
a) Offset
A. Offset 개념
- 그리고
Consumer
는 위치를 기록하고 있는Offset
으로부터 메시지를 가져오는 역할을 하게 된다. 이Offset
은 쉽게 얘기하면위치 정보
라고 보면 된다. 그숫자 정보
라고 보면 된다.Kafka
로 모두 표시되어 있다. 그래서Consumer
는 메시지 내용을 보고 가져오는 게 아니라Offset
이라고 불리는자리 번호
를 보고 메시지를 가져오게 된다.
B. Consumer의 목적 및 메시지 전송 방식**
Consumer
가 가능한 최대 속도로 가져올 수 있도록 하는 것이다. 즉,Producer
는 그Producer
가Kafka
로 메시지를 보낼 때는Push
방식이다. 그래서Producer
가 자기가 쏘는 속도에 따라서Kafka
가 받아주는 방식이다.- 그리고
Kafka
는Kafka
에서Consumer
구간은 사실Kafka
가 이걸Push
방식으로 할지Pull
방식으로 할지 고민을 했는데 카프카가Push
방식으로 하게 되면Consumer
가 메시지를 가져가는 거를Kafka
가 속도를 제어하게 된다. 그래서 이거는 약간 불합리하다고 생각을 해서Kafka
에서 메시지를 가져가는Consumer
는Pull
방식으로 가져가게 된다. 그래서,Consumer
리소스가 최대한 자기가 허용하는 범위 내에서 최대한 빠른 속도로Kafka
로부터 메시지를 가져갈 수 있는 구조이다.
- 그리고
C. Offset 특징 및 특이점
- 예시 : 그래서 메시지를 가져가는
Offset
과 관련된 내용을 잠시 살펴보면 그Topic
의partition
에 하나의partion
이라고 가정을 해보고 그 안에 메시지가 ‘A, B, C, D, E’가 들어있다. 그리고 이 ‘A, B, C, D, E’는 오프셋 0, 1, 2, 3, 4 이런 식으로 위치가 기록이 되어 있다.
- 순서 보장이 가능한 경우? : 그리고 이
Consumer
는 메시지A
,B
,C
,D
,E
메시지를 보고 가져오는 게 아니라오프셋 0번
,오프셋 1번
,오프셋 2번
,오프셋 3번
이 순서대로 메시지를 가져오게 된다. 그래서partition
이 하나인 경우에는Consumer
가 메시지를 가져올 때, 정확하게 순서가 보장된다.
- 근데,
Kafka
같은 경우에는 하나의Topic
을 여러 개의partition
으로 나눠서 사용하는 게 일반적인데 두 개 또는 세 개 뭐 이런 식으로 나눠서 사용을 하게 된다.
- 일반적으로 처음에 좀 약간 혼돈스러웠던 개념인데
Consumer
가partition 0번
에0번 Offset
메시지를 가져오고partition 1번
에0번 Offset
메시지를 가져오고 이런 식으로 순서대로 하나하나 가져오기를 원했는데Consumer
는partition
의 번호는 전혀 관여하지 않고 단지 그partition
의 오프셋 순서만 보장하게 돼 있다.
- 그 B라는 B와 C라는 메시지를 가져왔는데 그
partition
1번에 대해서Offset
순서대로 가져왔던 경우에 A랑 D라는 메시지를 가져왔는데partition 0번
에 대해서Offset
순서대로 가져왔다. 그partition
에 대해서는Offset
순서대로 가져오지만partition
순서는 전혀 관여를 하지 않는다.
D. Offset 순서 보장 방법
- 순서가
partition
을 여러 개 사용하게 되면 메시지 순서가 약간 꼬일 수가 있게 되는데 이러한 경우는 만약에 이러한 게 싫다면 그 메시지에다가 특정 필드에 ‘타임 스탬프’라던지 이런 것들을 넣어서 저장하면서 저장할 때, 순서를 정렬해서 저장을 하게 되면 메시지 순서대로 저장할 수가 있게 된다.
b) Consumer Group
A. Consumer Group 개념
- 하나의 Top으로 여러
Consumer
들이 구독을 할 수가 있게 해준다. 그래서,Consumer Group
을 만듦으로 인해서 그룹핑이 가능하고Consumer
를 확장할 수가 있게 된다.
B. 문제 상황
Producer
가 그Topic
으로 보내는 메시지 비율이 갑자기 높아진다면Consumer
는Producer
의 속도를 따라가지 못하게 된다.
- 예를 들어,
Producer
가 초당 10개의 메시지를 보낸다고 가정하고Consumer
는 초당 10개의 메시지를 가져오게 구성이 돼있다고 가정하자. 근데 뭔가 이벤트나 갑작스런 스팟성으로Producer
가 초당 한 천 개의 메시지를 막 보내게 되면Consumer
는 초당 10개만 가져오게 설계가 되었기 때문에Producer
가 보내는 메시지의 속도를 따라갈 수가 없게 된다.
C. 해결 방법
Consumer Group
안에Consumer Instance
만 추가를 해줌으로써Consumer 확장
이 가능하게 된다.
- 그래서 이
partition
이 예를 들어서 이렇게 3개가 있을 때,Consumer
가 이컨슈머 그룹 01
이라는Consumer Group
에Consumer
가 하나가 있게 되면 각각의 파티션은 하나의Consumer
가 전부다 메시지를 가져오는 구조가 된다.
- 하지만,
partition
3개에Consumer
3개를 이렇게 놓게 되면 하나의partition
에 하나의Consumer
가 1:1로 맵핑이 돼서 각자 메시지를partition
마다 가져올 수가 있게 된다.
D. 추가적인 상황
- 예를 들어서, ‘좀 더 빠른 속도로
Consuming
하고 싶다’ 라고 해서 여기컨슈머 그룹 01
에컨슈머 04
를 이렇게 추가를 하게 되더라도partition
하나에 하나의Consumer
만 연결되기 때문에 이렇게 추가된Consumer
는 일하지 않고 놀고 있게 된다. 만약에 그런 상황이 발생하게 되면partition
을 하나를 더 늘려 주셔서 동일하게 4개씩 맞춰 주시게 되면 빠른Consuming
이 가능하게 된다.
- 그리고
Consumer Group
을 사용하기 때문에Multi Consumer
라는 개념이 가능하게 된다. 예를 들어,피터 01
이라는 하나의 토픽에컨슈머 그룹
,컨슈머-하드업
,컨슈머-ES
각각의Consumer Group
이 하나의 토픽에 대해서 메시지를 가져올 수가 있게 된다.
- 그런데
Consumer Group
마다Offset
을 별도로 관리하고 있기 때문에 서로 전혀 다른 영향을 받게 된다. 즉, 서로의 영향을 받지 않고 각자의 역할을 할 수가 있게 된다.
c) Lag(랙)
A. Lag(랙) 사용 예시
- 예를 들어,
Producer
는Kafka
로 10개의 메시지를 보내게 된다. 그리고 10개의 메시지를 보내고Consumer
가 10개의 메시지를 가져오게 되면 이럴 때는 랙을 0이라고 표현한다. 그리고Producer
가 10개의 메시지를 보내고Consumer
가 5개의 메시지 밖에 못 가져갔다.
- 그러면 이런 거를
랙 5
라고 표현을 하게 된다.
B. Lag(랙) 개념
- 결국,
랙
이라는 지표는Producer
가 메시지를 보냈고Consumer
가 얼마나 밀리지 않고 메시지를 가져가고 있느냐를 볼 수 있는 중요한 지표 중에 하나이다.
C. Lag(랙) 모니터링 도구 : Burrow
- 그래서 이 랙이라는 것을 꼭 반드시 모니터링을 해야 되는데 카프카에서 제공해주는 커맨드로 이 랙이란 지표를 모니터링 할 수도 있는데 오늘 같은 경우도 있지만 카프카를 탄생시킨 링크드인에서 오픈 소스로
Burrow
라는 것을 공개했다. 그래서 이 버로우는HTTP
형식으로 내가 요청을 날리고 응답은JSON
형태로 이런 식으로 받을 수가 있게 된다.
- 그리고
Consumer Group
의 state 정보, 상태 정보라든지 아니면 현재 랙이 얼마나 있는지 이런 정보들을 볼 수가 있다. 랙에 대한 모니터링이 꼭 필요하다고 하면 이런 툴을 이용해서 사용을 하면 도움이 될 것 같다.
6) 운영 관점 팁
A. 문제 상황 : 미사용 토픽 처리
- 카프카 클러스터를 만들어 놓고 이제 서비스 각각의 서비스 부서별로 ‘토픽만 만들어주세요’라고 해서 토픽만 만들어주고 그 클러스터를 이제 전체적으로 공통으로 사용을 하고 있는데 이게 추가해달라는 요청은 자주 오는데 이게 뭔가 바뀌거나 뭐 토픽 이름을 다른 걸 또 바꾸거나 뭐 이러면은 이 삭제에 대한 요청은 거의 오지 않는다.
- 그렇다고 해서 그때그때마다 개발 부서에 요청을 해서 이 토픽 사용하지 않는 것 같은데 재차 확인하기가 어렵다.
B. 해결 방법 : JMX 매트릭값 이용
- 그래서 좀 좋은 방법이 없을까 라고 고민을 좀 했었다. 그래서, 그런 고민을 하던 찰나에 그 카프카 모니터링을 위해서 JMX 값을 수집을 하고 있었던 게 있었는데 그 JMX 값 중에 토픽의 상태 값을 상태 값과 관련된 그 매트릭 값들이 있었다.
- 그래서 그 매트릭 값을 이용해서 저장을 추가적으로 했고 그리고 그 저장된 데이터를 스토리지에 저장해놓고 그 저장된 데이터를 저장해놓고 1배치를 통해서 특정 조건에 맞는 토픽들. 예를 들어, 미사용한 걸로 보이는 ‘토픽 10일 동안 미사용한 토픽들’, ‘15일 동안 미사용한 토픽들’ 이런 조건을 만들어서 그 조건에 맞는 토픽들은 일괄적으로 삭제하도록 설계를 했다.
- 근데 이렇게 하더라도 실수로 중요한 토픽을 삭제할 수도 있게 된다. 그래서, 특정 토픽들에 대해서
삭제되기 3일 전입니다.
삭제하기 이틀 전입니다.
삭제되기 1일 전입니다.
이런 식으로 알람을 추가적으로 보내서 중요한 토픽들은 삭제되지 않도록 시스템을 만들어서 운영을 하고 있다.
C. 카프카 사용기 최종 정리**
브로커
에 특정한 이슈들이 생겼을 때, 물론 여러가지 옵션인매트릭 값
이라던지 이런 것들을 확인을 해야 되는데로그
를 보는게 가장 중요하다고 생각한다.
WARINING
이나ERROR
로그들도 물론 중요하지만 이INFO
로그가 왜 남았는지 이런 것들도 한번 다시 되새겨보면 이슈를 해결하는데 큰 도움이 되지 않을까 생각한다.
운영하는 환경
에 따라서서비스의 영속성
과데이터의 정합성
이런 것들을 잘 판단해서 사용하면 좋을 것 같다.
7) 추가 질문
a. 첫 번째 질문
- 간단하게 그 첫 번째는 클러스터를 지금 두 개에서 일곱 개로 늘렸는데 굳이 나누는 이유가 있는지랑 그리고 그 클러스터를 나눈 기준이 궁금하고요. 그리고 메이저 버전 업데이트 할 때 다운타임 어쩔 수 없이 가질 수 있는 그런 경우는 없었는지랑 그리고 세 번째 질문은 지금 카카오에 적용하면서 베스트 프랙틱스가 있는지 가장 효과적으로 적용하는 사례가 있으면 소개 좀 해주셨으면 좋겠습니다.
- 클러스터 나누는 거는 일단은 저희는 개발 클러스터랑 그리고 약간 센터별로 크게 좀 나눠놨고요. 근데 클러스터 나누는 목적 자체는 사실은 저도 이제 웹서핑을 하다 보니까 뭐 링크드인 같은 경우에는 하나의 클러스터에 60개의 브로커를 둔다고 하더라고요. 근데 제가 한 30개 정도까지 클러스터 하나의 클러스터에 30개 정도로 운영을 하다 보니까 이게 뭔가 버전 업그레이드라든지 또는 기타 컨피그를 바꿔야 될 경우가 있어요.
- 그러면은 그 클러스터 내에 모든 브로커들을 한 번씩 다 롤링 리스타트를 해줘야 돼요. 그러다 보니까 만약에 60 되면은 컨피가 한 번 바꿨는데 60대를 롤링 리스타트 한 다음에 바꿨는데 아 뭔가 잘못됐어요. 그럼 또 다시 바꿔야 되잖아요. 그럼 또 다시 60대를 롤링 리스타트를 해줘야 되는 거예요. 그러니까 이게 너무 번거롭다 보니까 저는 그냥 저 개인적으로 하나의 클러스터에 너무 많은 서버가 있기보다는 하나의 클러스터 내에 20대 또는 30대 정도를 맥스로 놓고 그 클러스터가 꽉 차면 별도의 클러스터를 만들어서 운영하는 방식으로 운영을 하고 있습니다.
- 그리고 롤링 업그레이드 같은 경우에는 저희가 이미 아까 제가 말씀드린 것처럼 카카오와 관련된 거의 모든 서비스들이 전부 다 이 카프카를 쓰고 있는 환경이에요. 그렇기 때문에 그렇게 다운타임을 가질 수가 없어요. 그래서 뭐 약간 좀 힘들긴 하지만 테스트 환경을 만들어 놓고 거기서 충분한 테스트를 해 놓은 다음에 그 다음에 버전 업그레이드를 하는 방식으로 활용을 하고 있습니다.
- 다른 게 아니고 한 Cluster 내에서 토픽이 적정한 수가 좀 궁금한데 예를 들면 토픽의 수가 어느 정도 적정한 제한이 있는 건지 아니면 장비의 Network BandWidth가 병목인 건지 좀 한 클러스터에 가질 수 있는 적정한 토픽 수나 그런 것들이 좀 궁금하거든요.
- 이거는 이제 Cluster에 서버 갯수나 뭐 서버 스펙에 따라서 조금씩 다를 수는 있는데요. 저희 같은 경우에는 지금 한 뭐 한 Cluster에 만 있는 토픽이 있다고 하더라도 50개 미만이에요. 그런데 뭐 제가 저희 서비스 부서에서 또 이제 별도로 운영하시는 분들도 계시고 하는데 그때 2000개인가 3000개가 있었다고 하는데 그러니까 부하 같은 게 있었다고 하더라고요. 그런데 사실은 그 부하 같은 게 escuched out fast noises. 사실은 그 토픽이 있음으로 인해서 리플리케이션이나 이런 세팅을 다 할 거잖아요. 그렇기 때문에 크게 자원을 소비하지 않더라도 그 브로커 내부적으로는 그 토픽을 계속 바라보고 있는 거죠.
- 메시지 언제 들어오나 요청과 이런 것들이 반복이 되기 때문에 불필요한 토픽들은 제가 마지막에 보여드린 것처럼 최대한 삭제해 주시고 너무 많은 토픽은 지향해 주시는 게 좋을 것 같습니다.
b. 두 번째 질문
- 개인적으로 저는 RabbitMQ를 RPC 용도로 사용 중인데 카프카의 경우는 제가 알기로 순서 보장이 아까 말씀하신 것처럼 파티션 하나의 컨슈머였나요? 순서 보장이 그런 식으로 되는 걸로 알고 있어서 카프카 도입이나 이런 걸 고민 중인데 혹시 개인적으로 카프카를 순서가 보장이 되어야 되는 순서가 보장이 되어야 되는? RPC 패턴에서 사용할 때 이거를 추천하는지 안 하시는지 그게 좀 궁금합니다. 혹시 주위에 사례나 이런 것들이 있으면 제가 사실 내부에서 회사 내부에서
- Kafka뿐만 아니라 RabbitMQ도 같이 운영을 하고 있어요. 그래서 많은 비교들을 하게 되고 이렇게 하는데 만약에 카프카를 사용하시고 싶으시면 아까 말씀드린 것처럼 하나의 partition으로 사용을 하시면 순서 보장도 정확하게 되고 원하시는 기능들을 사용하실 수가 있어요.
- 그리고 RabbitMQ를 사용하시는 것보다 카프카의 토픽을 파티션을 하나로만 사용하시면 Throughput(최대 메시지 처리량 제한(초당 몇개의 메시지 처리하는지))도 더 높이 더 많이 나와요. 그렇기 때문에 Throughput이 높거나 이런 상황이시라면 Kafka를 partition 1개로 사용하시면 좋을 것 같고요.
- 그리고 굳이 RabbitMQ에 문제가 없는 상황이라면 제가 볼 때는 RabbitMQ가 기능들은 더 많이 가지고 있거든요. 그렇기 때문에 RabbitMQ 사용하시는 게 좋을 것 같습니다.