🤨 문제상황  

  1. Spring Boot 3.x 와 MSK t3.small 사용중
  2. 개발하던 모듈에서 일괄 등록 기능이 있었고, 최대 몇 건까지 가능하냐는 기획자분이 문의 주셨다
  3. 1만건, 2만건 씩 대량 생성 요청을 보내면서 테스트하고 있었다. 물론 개발서버에서!
  4. 1건당 최소 10개의 kafka 메세지를 발송하는 서비스였다. (entity 변경 내역도 쌓고, 로그도 쌓고 하느라 이것저것 많이 날림),
    한번에 메세지를 발송하는 것은 아니고, 몇 초에서 몇 분 안에 총 10개 이상의 메세지를 발송함
  5. 요청 직후는 큰 문제는 없었지만, 30분에서 1시간 뒤 부터 TopicAuthorizationException 이 발생했다
  6. kafka-ui 를 구축하여 kafka 상태를 모니터링 하고 있었고, 에러가 발생한 후 부터는 브로커에 상태를 보기 어려웠다.

    실제 상황에서는 브로커 정보도 보이지 않았고, Topic을 비롯한 거의 모든 정보가 보이지 않았다. 간헐적으로 몇 개의 브로커의 정보가 보였다가 다시 안보이는 것을 반복했다.

    kafka-ui 에서 확인한 장애 상황
  7. 가끔 연결되는 브로커 정보를 확인했을 때, Disk usage 가 51GB 까지 올라가는 것을 확인했다. msk 설정에서 브로커당 메모리를 100GB로 잡아놨는데... 가까워지는 게 실시간으로 보였다... 

⛏️ 삽질 시작…  

1. 인증 문제인가?

TopicAuthorization 이라는 exception 이름으로 유추해 봤을 때, IAM Role에 권한이 빠진건 아닌가 생각해봤다.
→ 보안팀에게 문의 결과 변경점 없다고 답변 받았다.


2. 모를땐 재부팅이지!

 

AWS MSK 콘솔에 들어가면 브로커 재부팅 버튼이 있다. 이 기능을 사용하여 존재하는 모든 브로커를 재부팅 해봤다.

→ 재부팅 직후에는 kafka-ui 연결도 잘 되는듯 싶다가 몇 분 지나면 동일한 증상을 보인다.

 

3. 브로커 로그를 켜보자

kafka-ui에서 브로커 상태를 볼 수 없는 것으로 보아, 브로커에 이슈가 있어서 연결이 안되는 것이라고 판단하였다.

그러나 connection 이슈 및 broker endpoint는 외부에서 접근이 어려웠다.

그래서 브로커 로그를 확인할 수 있도록 S3에 브로커 로그를 쌓는 설정을 추가하였다.

AWS 콘솔에서 MSK 설정을 확인해보면, 로그전송 설정이 있다. 여기서 원하는 S3 버킷을 골라 로그전송 설정을 ON하면 설정 끝이다.

그럼 다음과 같이 S3에서 로그를 확인할 수 있다.

 

4. 메세지 쏠림 현상인가?

문제 발생 시점이 대량 bulk 등록으로 인해 엄청나게 많은 메세지가 발행되고 난 후이다. 그럼 대량 메세지를 의심할 수 밖에 없다.

브로커가 현재 2개인데, 너무 적은 브로커에 부하가 많이 몰려서 죽는것인가?

 

예상 이유

  1. 브로커 디스크 사용량이 꾸준하게 증가하고 있었고, CPU 사용률과 네트워크 패킷수가 하나의 브로커만 튀고 급격하게 감소하는 모습을 보인다. 하나의 브로커에 요청이 몰려서 죽는것처럼 보인다.
  2. Pod에서 BufferExhaustedException 이 발생했다

주황색 브로커만 지표가 튄 다음 급격하게 감소하는 모습을 보인다.

 

이를 해결하기 위해 브로커의 개수를 늘리고, 가장 많은 메모리를 차지하는 topic을 제거하였다.

브로커 개수는 가용영역당 브로커 1개로 총 2개 -> 가용영역당 브로커 2개로 총 4개로 2배 증가하였다.

위 지표처럼 네트워크와 CPU 사용률은 줄어들었지만, 브로커가 연결이 안되는 문제는 동일했다.

 

5. SASL 설정 문제인가?

정상 동작하는 팀의 MSK 인증방식은 SASL/SCRAM, IAM 을 사용하고 있었다.

우리팀의 인증방식은 IAM 으로 설정되어 있었다.

그리고 최근에 인증 방식을 SASL로 변경했기 때문에 의심하던 와중에 다음과 같은 로그가 발생했다.

 

그래서 보안설정을 변경해보았다

AWS MSK 보안설정 편집에서 확인할 수 있다.

그러나 이 방법도 실패하였다.

 

💪🏻 드디어 해결!  

AWS MSK 공식 페이지에 게시된 문의 내용 중, SaslAuthenticationException 관련 내용이 있었다. [바로가기] 

 

별 생각 없이 문서를 보다가 해당 내용이 눈에 들어왔다. 음? 초당 하나의 TCP 연결? 냄새가 났다. 관련해서 더 찾아보니 다른 문의글도 있었다. [바로가기]

이 글에는 다음과 같은 내용이 있었다.

MSK Connect에서 IAM 인증을 사용하여 t3 인스턴스를 사용하지 않는 것이 좋습니다. 이는 현재 t3 인스턴스에 적용된 연결 제한 때문입니다.

 

우리는 MSK Connect를 사용하지 않고, IAM도 사용하고 있지 않지만 t3를 사용하고 있으니 connection 문제는 동일할 것으로 쉽게 유추할 수 있다.

그래서 MSK broker의 스펙을 t3.small -> m5.large 로 변경해보았다. (15분 걸린다고 했는데 1시간이나 걸렸다... 😡)

 

당연하겠지만, CPU 사용률이 급격하게 줄어들었다. connection 이슈로 인한 CPU 부하가 줄어든 것으로 예상된다.

 

그리고 같은 에러는 더이상 발생하지 않았다!

👼🏻 무엇이 문제인가  

1. consumer/producer 는 왜 broker에 못 붙었을까?

요청하려는 broker에 connection을 얻지 못해 발생하는 이슈이다. t3.small은 초당 1개의 connection만 허용하기 때문에 동시에 많은 요청이 들어올 경우 처리가 connection을 얻지 못한다.

실제 pod의 에러 로그를 보면, DisconnectException 이 발생한다.

초당 1개는 가능하기 때문에 간헐적으로 메세지 produce는 성공했던 것이다.

 

2. kafka-ui 에서는 왜 broker 상태를 볼 수 없었을까?

kafka-ui는 AdminClient 에 요청해서 kafka 정보를 받아오는데, 이 때 브로커가 connection 문제로 응답을 늦게 전달한다. 그래서 kafka-ui pod의 에러로그에는 TimeOutException이 발생하는데, 도착까지 걸린 시간을 보면, timeout 시간인 30000ms 보다 늦은 30903ms 가 소요된다. 아슬아슬한 timeout이기 때문에 간헐적으로 kafka-ui가 정상동작한 것 처럼 보였던 것이다.

 

3. 카프카는 대용량 처리를 위한 서비스라면서 이정도로 뻗어도 되나?

이 이슈의 원인은 카프카라기 보다는 AWS MSK의 이슈이다.

AWS MSK에서는 TCP Connection 제한이 존재하고, 클러스터 유형에 따라 다르다.

AWS MSK serverless의 connection quota는 [여기서] 확인 가능하다.

참고로 t3.small 은 브로커마다 초당 1개의 TCP 연결이 가능하고, burst enable시 4개까지 가능하다.

 

4. 그럼 왜 여태까지 문제가 없었을까?

지금까지는 대량의 요청이 없었기 때문에, 브로커가 초당 1개의 TCP Connection으로도 처리가 가능했다. 많은 메세지가 발행되지도 않았고, 잠깐 요청이 몰리더라도 connection 획득을 기다리면 해결됐기 때문에 문제가 없었다.

브로커 로그를 보면, disconnected 혹은 closing connection 과 같은 connection 이슈들만 발생한다.

 

😱 또다른 문제...  

문제를 해결했다고 판단하여 MSK의 broker 스펙을 t3.small로 낮추었다. 개발서버 비용을 아끼자는 의견이 있었기 때문에 m5.large는 필요할 때 다시 올리기로 하였다.

그래서 대용량 요청은 최대한 지양하고 있었는데 문제가 발생했다.

실제로 요청한 메세지 건수는 몇천건(대략 2000건)에 불과했지만, 새로만든 msk에서 1주일만에 offset이 227,148,710 건까지 늘어났다. 2000건의 메세지로 발생하는 다른 메세지가 있다고 생각하더라도 너무 많은 데이터가 들어오고 있었다.

브로커 디스크 사용량을 확인해보니 linear하게 증가하고 있었고, 중간에 튀는 것 없이 꾸준하게 증가하는 것이 매우 이상했다.

 

그래서 메세지가 재발행되고 있다고 판단하였고, 그에 따른 문제상황을 살펴보았다.

 

🔎 문제 파악  

producer에서 발생하는 재발행 이슈면, pod의 리소스가 늘어나거나 kafka로의 요청 건수가 늘어나야 한다. 그러나 pod는 모두 정상상태였다.

msk 지표를 확인해보니, 네트워크 패킷수에는 증가가 없었다. 패킷 수가 피크칠 때는 2000건의 요청을 보낸 것이고, 그 이후에는 안정된 모습을 보인다.

 

지표를 확인하던 중 브로커별 CPU 크레딧 잔액 이라는 지표 눈에 띄었다. 뭔가 냄새가 난다.

 

CPU 크레딧 잔액은 1번 브로커(파란색) 만 남아있는데, 패킷수와 디스크 사용량을 확인해보면 1번 브로커가 제일 낮다. 1번 브로커가 제일 일을 안해서 잔액이 남는건가? 그럼 잔액이 없으면 어떻게 되는거지?

 

관련해서 찾아보니 T2/T3에서는 크레딧 잔액이 0에 가까우면 CPU 사용이 제한될 가능성이 있다고 한다. [관련 AWS 문의]

크레딧이 없어서 CPU에 문제가 발생하는거였구나! 관련해서 공식문서를 더 찾아보았다.

T 유형 인스턴스를 사용하고 있습니다.
참고로 T 유형 인스턴스에는 기준 성능과 함께 버스트 가능한 몇 가지 기능이 있습니다. 이 인스턴스는 기준 성능으로 CPU 사용률 20%를 사용할 수 있습니다. 이 값을 초과하면 인스턴스 유형이 CPU 크레딧을 사용하기 시작합니다. 사용률이 20% 미만이면 CPU 크레딧이 누적됩니다.

CPUCreditBalance 지표 에 표시된 CPU 크레딧은 인스턴스가 기준 CPU 사용률을 초과하여 버스트하는 데 사용할 수 있습니다.

T 유형 인스턴스에서 실행 중인 모든 클러스터의 기준 CPU 사용량과 크레딧 잔액을 모니터링해야 합니다. CPU 사용량이 기준보다 많고 더는 사용할 크레딧이 없으면 클러스터에 성능 문제가 발생합니다.
[AWS 공식문서]

 

한번에 많은 요청으로 CPU가 부하를 받게 되었고, 이로 인해 메세지 발송 및 처리가 제대로 이루어지지 않아서, 에러 메세지가 계속 쌓이는 것으로 보인다.

 

😢 운영은 괜찮나...?  

멀쩡하다. 왜일까?

운영은 T 유형의 인스턴스가 아니기 때문이다. 개발은 t3.small이고 운영은 m5.large 라서 크레딧 잔액에 따른 이슈는 없다.

운영 msk 지표를 확인해보니 크레딧 관련 지표는 존재하지도 않는다!

 

👊 앞으로 어떻게 해야할까  

1. 테스트 서버 MSK에 IAM Role 적용 여부

물론 우리팀은 SASL로 인증하기 때문에 문제는 없지만, IAM Role로 인증하는 팀에서는 논의가 필요하다. IAM Role로 인해 TCP Connection을 사용하기 때문에 msk에 문제가 발생할 확률이 굉장히 높아진다.

AWS에서도 t3 MSk에서는 IAM Role을 사용하지 말라고 권장한다.

2. 스펙 논의 (t3.small VS m5.large)

t3.small 과 m5.large 의 요금차이는 약 5배 정도 난다.

그래서 과금 관련하여 devops 팀과 논의가 필요하다!

3. 브로커 개수 논의

AWS에서 제공하는 자료에서는, t3.small 에 추천하는 브로커 개수는 30개이다.

따라서 브로커 개수를 늘리는 것이 도움이 될 수 있어 보인다. (브로커 개수 30개 할거면... m5.large 가 낫지 않나?)

 

MSK 설정 하나로 너무 많은 시간을 사용했기 때문에... 다른 분들은 이 글을 통해 소중한 시간을 아끼길 바라며... 끝...!

 

📚 참고자료  

[Amazon MSK Quota]

[can AWS remove the connection limit?]

[Troubleshoot connect to MSK cluster]

[MSK pricing]

[BestPractice - Broker per cluster]

[MSK Sizing Pricing]

[Troubleshoot high CPU usage in MSK]

'AWS' 카테고리의 다른 글

AWS S3에 soft delete를 적용해보자  (1) 2024.06.25

배경

AWS S3 bucket에 파일을 클렌징하는 작업이 들어왔다. 구체적으로는 S3 버킷에 존재하는 고아 데이터를 제거해달라는 요청이다.
기존에 운영되고 있던 서비스에 ISMS 심사 대응으로 추가된 작업이라, S3 객체를 잘 못 지웠을 때 복원할 수 있는 수단이 필요하다고 판단했다. (mysql에서 작업했다면 테이블을 clone 따 두고 작업했을 것이다.) 그래서 S3에는 soft delete 기능이 없는지 찾아보았고, 아니나 다를까 당연히 있었다. 나처럼 S3 객체 삭제가 두려운 사람들을 위해 내가 설정한 방법을 공유하도록 하겠다 😄

버킷 버전 관리

이 설정은 s3 객체 삭제 시, 같은 파일이름(key)으로 삭제 마커 를 붙여서 새로운 버전으로 객체를 생성한다. 이 설정을 on 하고 SDK로 객체를 삭제하면 삭제 마커가 붙은 새로운 객체가 생성되고, SDK로 getObject를 하게 되면 KeyNotFound 가 발생한다.

여기서 의문점은 결국 새로운 버전의 객체가 만들어지는 것이고, SDK에서도 조회가 안되는거면 삭제된거 아닌가? 라는 것이다.

 

당연히 아니다(AWS 선생님을 무시하지 말도록).

 

객체의 삭제마커 이전 버전을 조회할 수도 있고, 복원할수도 있다. 버전 관리라서 조금 더 복잡한 기능으로 사용할 수 있어 보이지만, 나는 이 설정을 soft delete로 사용하였다.

 

그럼 삭제마커가 붙은 애들은 어떻게 영구삭제 할 수 있는가?

 

수명 주기 규칙 생성하기

버킷 설정에서 수명주기 규칙을 추가함으로써 삭제 마커가 붙은 객체들을 자동으로 삭제할 수 있다. 하나씩 설정 값을 확인해보자.

 

접두사

접두사에 맞는 key를 찾아 해당 규칙을 적용한다. 만약 directory로 경로를 구분하고 있다면 / 구분자까지 넣는걸 추천한다.

 

수명 주기 규칙 작업

  • 객체의 이전 버전 영구 삭제
    최신이 아닌 객체, 즉 최신 버전이 아닌 파일을 제거하는 설정이다. 객체를 삭제하면 원본 객체가 최신이 아닌 객체가 되기 때문에, 이에 해당한다.
  • 객체가 최신이 아닌 상태로 전환된 후 경과 일수
    객체의 버전이 바뀐 뒤 만료(삭제) 까지의 기간이다. soft delete 되고 난 후 며칠동안 보관할 것인지에 대한 설정이다.
  • 보관할 새 버전 수
    최신 몇 개의 버전까지 삭제하지 않을 것인지에 대한 설정이다. 0으로 설정하면 삭제 마커만 남게 되고, 1개로 설정하면 삭제마커와 객체 1개를 유지하게 된다. 우리는 자동으로 soft delete 된 객체를 지우는 것을 원하기 때문에 0으로 설정하면 된다.

예를 들어 위와 같이 설정하면, 객체를 삭제했을 때 soft delete가 되어 언제든 복원할 수 있는 상태가 되고, 1일 뒤 실제 객체가 삭제되는 것이다.

  • 만료된 객체 삭제마커 또는 완료되지 않은 멀티파트 업로드 삭제
    만료된 삭제 마커란, 모든 객체 버전이 삭제되고 삭제 마커만 남아있는 객체를 뜻한다. 이 설정을 활성화하면 soft delete된 객체(이전 버전으로 원본이 살아있는 객체)는 삭제되지 않고, 원본이 삭제된 객체만 제거된다. 이 설정은 꼭 필요하진 않지만 굳이 불필요한 삭제 마커를 남길 필요는 없고, s3 설정에서도 제거하여 성능을 개선할 수 있다고 하니 활성화하는 것을 추천한다.

그럼 설정한 S3 객체의 수명주기를 다이어그램으로 간략화하면 다음과 같다.

주의할 점

S3의 lifecycle 적용 시간은 UTC 기준 00:00이다. 객체마다 별도로 관리하는 것이 아닌, UTC 기준 00:00에 일괄 적용이라는 의미이다.

S3는 해당 규칙의 일수(days)를 객체 생성시간에 더하고 결과값을 다음날 자정(UTC 기준)으로 반올림하여 시간을 계산한다. 예를 들어 객체가 2014년 1월 15일 오전 10시 30분(UTC)에 생성되고, 수명주기 설정에 3일을 지정하면, 객체의 전환 날짜는 2014년 1월 19일 00:00 UTC로 계산된다.

 

객체 삭제 시점이 예상과 다를 수 있으니, 확인하면 좋을듯 하다.

참고 문서

삭제 마커 관리 AWS 공식 문서
Lifecycle Rules AWS 공식 문서

'AWS' 카테고리의 다른 글

말썽꾸러기 Kafka  (1) 2024.06.26

+ Recent posts