안녕하세요 프립 백엔드 개발자 김준성입니다.
2022년 8월 ~ 10월 프립 서비스를 운영하면서 MSK 업데이트로 인해 이벤트 유실 문제가 발생하였습니다. 문제를 해결해나갔던 과정과 개선할 점은 무엇이 있는지 정리해보려 합니다.
- 참고 : Kafka와 MSK에 대한 기술적 설명보다는 운영중 발생했던 문제를 해결해나가는 것에 대한 과정을 회고하는 내용으로 작성된 글입니다.
배경
Apache Kafka 사용
프립 서비스는 MSA 구조로 이루어져 있고, Kafka를 사용하여 각 API들이 유기적으로 동작하고 있습니다. API들은 작업을 마치고 DB에 commit이 완료되면, 필요한 data를 kafka에 전송(publish)합니다. 다른 API들은 자신에게 필요한 data가 있는 topic을 구독(subscribe)하면서 data를 consuming 합니다. data 메시지를 받게 되면 해당 이벤트 토픽에 담긴 data를 보고 API에서는 다음 필요한 기능을 진행합니다.
Amazon MSK (Amazon Managed Streaming for Apache Kafka) 사용
kafka의 대한 환경을 쉽게 구성하고 운영하는데 있어 편하게 하도록 도와주는 것이 Amzaon의 MSK입니다. 입사 후 MSK를 사용하면서 기능적으로 에러가 발생한 것은 1~2번 정도였으나, MSK 업데이트가 문제를 발생시켰습니다. 2022년 8월 12, 9월 12일, 10월 12일 MSK 브로커 업데이트가 진행되면서 운영 중이던 브로커가 강제로 재부팅되는 상황이 발생하였고 프립 서비스에서 이벤트 유실 문제가 발생하였습니다.
문제의 시작
8월 29일 월요일 고객경험팀으로부터 [판매관리]에서는 주문이 확인되나 [예약관리]에서는 확인되지 않는다는 이슈가 들어왔습니다.
8월 12일에 구매한 내역으로 데이터독 로그 저장 기간인 15일이 지난 상태였기 때문에 데이터독으로 확인이 불가능한 상태였습니다.
해당 로그를 S3에서 찾아서 봐야하는 불편한 상황이 있었으나 다행히 Datadog에서는 이전 로그를 다시 복구해서 볼 수 있는 기능이었고 해당 기능을 사용해서 로그를 볼 수 있었습니다.
Kafka 작동 문제가 8월 12일 23시 17분부터 문제가 되고 있었음을 확인할 수 있었습니다.
전반적인 오류 내용은 브로커가 사용이 불가능해지면서 몇몇 서버에서 정상적인 data pub/sub이 안되고 있는 문제로 파악되었습니다.
제보된 이슈 말고도 다른 몇개의 상품에서도 정상적인 결제 로직이 이루어져 있지 않은 것을 추가적으로 파악하고 현재 Kafka 브로커 설정을 확인한 뒤 팀원들에게 공유를 하였고 8월 12일에 MSK 업데이트가 있었다는 내용을 전달받을 수 있었습니다.
업데이트 메시지 내용
MSK will patch the underlying operating system of brokers in your MSK cluster(s) with the latest OS updates between Fri, 12 Aug 2022 14:00:00 GMT and Fri, 12 Aug 2022 18:00:00 GMT. MSK patches brokers to address security vulnerabilities and to update software supporting the brokers. MSK uses an automated rolling update to patch one broker at a time, following Kafka best practices. To ensure client I/O continuity during the rolling update that is performed as part of the patching process, we recommend you review the configuration of your clients and your Apache Kafka topics as follows:1. Ensuring the topic replication factor (RF) is at least 2 for two-AZ clusters and at least 3 for three-AZ clusters. An RF of 1 can lead to offline partitions during patching.2. Set minimum in-sync replicas (minISR) to at most RF - 1 to ensure the partition replica set can tolerate one replica being offline or under-replicated3. Ensure clients are configured to use multiple broker connection strings. Having multiple brokers in a client’s connection string allows for failover if a specific broker supporting client I/O begins to be patched. For information about how to get a connection string with multiple brokers, see Getting the Bootstrap Brokers for an Amazon MSK Cluster [1].
Log와 업데이트 메시지 내용, 현재 설정된 카프카 설정들을 종합하였을 때, MSK 업데이트에 대한 대응이 되어있지 않다는 것이 확인되었습니다.
현재 정상적으로 처리되지 않은 이벤트들은 다시 발송하여 처리를 완료시켜주었고, 9월 12일에 한번 더 있을 MSK 업데이트를 대응하기로 합니다.
1차 대응
Amazon에서 권장하는 설정으로 broker 설정 값을 바꾸기로 하기로 내부적으로 결정이 되었습니다.
잘못된 대응으로 더 큰 문제가 발생하였지만… 일단은 그렇습니다.
(잘못된 대응…🥲)
브로커의 원래 설정에서 minISR에 대한 설정을 추가
- auto.create.topics.enable = true
- delete.topic.enable = true
- default.replication.factor = 3
- min.insync.replicas=2 (추가)
Spring 서버 설정 값에 required-acks: -1
추가
9월 13일이슈 확인
9월 12일 msk 업데이트 이후 이벤트 유실이 없었는지 확인을 하는데, 설정 변경 이후 몇몇 토픽에서 NotEnoughReplicasException 에러가 발생하면서 며칠간 이벤트 전송이 안되고 있던 문제가 확인되었습니다.
원인 파악
브로커에서 변경한 설정에 따라 모든 토픽이 RF 3, minISR 2로 설정되어 운영이 될 줄 알았는데 실제로는 토픽 별로 RF의 값이 1~3으로 다양하게 설정되어 있었습니다.
auto.create.topics.enable = true 설정이 되어 있어 각 토픽을 서버에서 새로 만들때 서버에 셋팅된 값에 따라 RF가 다르게 설정되어 있었습니다.
우선 장애가 발생한 토픽들(RF가 1로 설정되어있던 토픽)과 원인은 파악되어 Spring 서버 설정 값 required-acks: -1
을 다시 제거하고 복구가 필요한 이벤트들은 다시 재발송하여 해당 문제를 일단 해결하였습니다.
팀에서 정확한 모니터링 및 테스트 부족, 부족한 기술 지식으로 문제가 발생했다는 것을 인지하고 10월에 있을 또 한번의 MSK 업데이트를 대응하기로 합니다..!
2차 대응
토픽의 RF 값을 3, minISR 설정을 2로 한다는 것은 그대로 최종 사항으로 두고 기존 토픽의 RF 값들을 3으로 변경하기로 하였습니다.
이번에는 테스트를 진행하여 문제가 발생하지 않는지 확인 후 변경을 하였습니다.
[테스트 진행]
- 테스트용 MSK 클러스터를 새롭게 구성 (브로커 3개)
- Kotlin + Spring boot 환경으로 테스트용 MSK 이벤트를 pub/sub
- Kafka의 broker, producer 설정을 변경해가며 테스트
Tip — MSK는 같은 VPC 내에서만 접근이 가능합니다. local에서 접근하기 위해서 VPN을 이용하였습니다.
주요 kafka 설정 값
- RF (Replication Factor)
- ACK
- minISR (min.insync.replicas)
- unclean.leader.election.enable
주요 확인 사항
- 서버에서 Kafka 이벤트 data pub/sub이 진행되는 중, 브로커가 하나씩 재부팅을 시켜본다. 이 때 서버에서 어떤 로그가 나타나는지 확인
- 서버에서 Kafka 이벤트 data pub/sub이 진행되는 중, 카프카 설정으로 토픽의 RF의 값을 변경하였을 때 이벤트 유실이 발생하는지 확인
- 서버 설정에서 RF를 변경했을 때 기존 토픽에 설정값이 변경되는지 확인
[장애 테스트 방법]
- 서버 3개에서 토픽 6개를 개별적으로 전송시킴 (토픽은 1s,2s,3s,4s,5s,6s의 주기로 스케줄러를 이용해 전송하게 하였습니다.)
- 서버 2개에서 토픽 6개를 동시에 consuming 하였습니다.
[결론]
- 운영 중이던 카프카에서 RF의 값을 변경하여도 이벤트 유실은 발생하지 않았습니다.
- 서버 설정에서 RF를 변경여도 기존 토픽에 설정 값이 변경되지 않았습니다.
(중요) 설정 값에 따른 브로커 재부팅 결과
- RF = 1, minISR = 2, ack = all
에러가 발생하며 메시지가 전송되지 않습니다.
org.apache.kafka.common.errors.NotEnoughReplicasException: Messages are rejected since there are fewer in-sync replicas than required.
- RF = 2, minISR = 2, ack = all
브로커 1번을 종료 시 리더 파티션이 브로커 1번에 있던 토픽들이 문제가 발생하고 이벤트 발송이 안되고 컨슈머가 리밸런싱 됩니다.
에러는 NotEnoughReplicasException으로 동일하였습니다.
- RF = 3, minISR = 2, ack = all
브로커를 하나 종료시켰을 때, 살아있는 2개의 브로커로 리더가 재설정되어 이벤트 유실이 발생하지 않았습니다. 컨슈머는 리밸런싱 됩니다.
하지만 여기서도 문제가 추가적으로 발생하게됩니다.
브로커 1번을 종료하였다고 가정을 하였을 때, 모든 토픽의 리더 파티션은 2번 3번 브로커로 재설정되게 되는데 1번 브로커가 복구되고나면 몇분 후에 카프카에서 자체적으로 리더 파티션을 1번, 2번, 3번 브로커로 재설정합니다.
이 순간에 이벤트 유실이 발생하였습니다.
카프카에서 리더 불균형 문제를 해결하기 위해 auto.leader.rebalance.enable 설정이 true로 되어있는데 이로 인해 발생하는 문제였습니다.
에러는 NotEnoughReplicasException으로 동일하였습니다.
[설정값 변경]
테스트 이후 운영 중이던 모든 토픽의 RF 값을 3으로 변경하였고 Spring 서버의 설정 값 required-acks: -1
도 복구시켰습니다.
모든 설정을 변경한 이후 진행됐던 10월 12일 MSK 업데이트에서는 NotEnoughReplicasException 검색어를 통해 손쉽게 문제 된 토픽을 확인할 수 있었으며 유실된 메시지 또한 굉장히 적은 숫자로 줄일 수 있었습니다.
보완점
- 리더 불균형 문제 해결
결론적으로 이벤트 유실이 적게나마 발생을 하기 때문에 해결할 방법을 찾아야 합니다. - 낮은 브로커 버전
현재 운영 중인 브로커의 버전은 2.2.1 버전으로 최신 카프카 버전과 차이가 큼. 가장 큰 차이점이라고 한다면 주키퍼의 존재 여부일 것 같고 버전을 언제쯤 올려야 할지, 그리고 몇 버전으로 올리는게 좋을지 파악이 필요합니다.
마무리
에러를 해결하는 과정에서 모니터링 및 테스트의 중요성을 한번 더 깨닫게 되었고, Kafka 메시지를 수신하는 정도로만 사용을 하다가 이번 기회에 주요 설정 및 기술의 이해도를 쌓을 수 있었습니다.