개발놀이터
아파치 카프카 (응용) 본문
카프카에 대한 이론적인 내용은 아마 이게 끝일 것 같습니다. 아파치 카프카 카테고리는 개념, 심화, 응용을 마지막으로 이제 실습을 해볼 예정입니다.
이번 응용편에선 이렇게 진행됩니다.
- Unclean Leader Election의 위험성과 사용 여부 판단
- Offset 관리 전략
- 성능 최적화 및 튜닝
- 카프카 스토리지와 OS 레벨 연계
이렇게 네가지 섹션으로 이루어집니다. 한번 천천히 정리해보겠습니다.
Unclean Leader Election
카프카는 장애시 ISR에서 리더 파티션을 새로 뽑아 장애 상황에 최적화된 움직임을 보여줍니다. 그런데 만약 ISR에 뽑을만한 리더 파티션이 없으면 어떻게 될까요?
이럴 때 개발자는 Unclean Leader 즉, ISR에 없는 파티션 중 리더로 선출할 수 있도록합니다. 이렇게 ISR에 없는데 리더 파티션으로 선출되면 메세지가 잘못 전달될 가능성이 생깁니다.
이런 가능성이 존재함에도 개발자는 이 메세지가 전달되도록할 수 있는데 일관성 (Consistency), 가용성 (Availability) 중 하나를 선택할 수 있습니다.
C를 선택하게 된다면 (false로 설정한다면) unavailability 에러가 발생하긴 하지만 메세지가 안정적으로 유지됩니다. 반대로 만약 A를 선택하게 된다면 (true로 설정한다면) ISR에 존재하지 않는 파티션을 리더로 선출해 가용성을 높일 수 있습니다.
이런 점 때문에 카프카는 CAP정리를 완벽하게 따르게 되었습니다. 메세지를 stateful하게 관리하는 점이나 브로커가 물리적으로 독립적인 환경이라는 것 때문에 카프카 또한 NoSQL의 반열에 오르게 되는건가..? 싶었습니다.
일단 기본적으로 카프카를 사용한다는 것은 마이크로서비스일 확률이 높고 그렇다면 메세지가 일관되게 처리하는 것이 일반적이기에 false로 설정하는 것이 올바른 방법입니다. 하지만 로그나 모니터링에 카프카를 이용하는 것이라면 true로 놓고 사용해도 상관 없겠습니다.
Offset 관리 전략
카프카의 컨슈머는 본인이 어떤 메세지를 처리하고 있었는지에 대한 정보인 Offset을 알고 있어야 다음 메세지를 처리해도 되는지, 현재 메세지를 재처리해야하는지에 대한 정보를 알 수 있습니다.
Offset은 컨슈머 쪽에서 제어권을 가지고 있고 기본적으로 자동 커밋과 수동 커밋을 지원합니다.
자동 커밋 vs 수동 커밋
자동 커밋은 컨슈머가 메세지를 받자마자 바로 커밋하는 것이고 이것이 카프카의 기본 설정입니다. 하지만 이렇게 하게 되면 컨슈머에 장애가 발생했을 때 메세지를 재처리할 수 없어서 메세지가 유실되는 상황이 발생합니다.
수동 커밋은 컨슈머가 자동으로 커밋을 처리하는게 아니고 개발자가 직접 커밋 시점을 정해주는 것으로써 메세지가 유실되지 않게 관리할 수 있습니다.
하지만 수동 커밋의 경우 메세지를 재처리하는 과정에서 데이터베이스 연산이 메세지 처리와 묶여있는 경우 중복처리가 일어날 수 있습니다. 예를 들어서 INSERT문을 처리해야하는데 두 번 INSERT문이 실행될 수 있다는 뜻이죠.
EOS vs Outbox 패턴
이런 문제를 해결하기 위해서 보통 EOS라고 불리는 카프카 트랜잭션을 사용하거나 Outbox 패턴을 사용합니다. EOS는 카프카 메세지를 트랜잭션 처리해 원자성을 보장하는 것입니다.
하지만 EOS의 경우 굉장히 쌈뽕한 로직으로 깔끔하게 처리할 수 있지만 데이터베이스 연산에 대한 트랜잭션까지 묶어서 처리할 수 없기에 Outbox 패턴을 주로 사용하게 됩니다.
Outbox 패턴에 대한 자세한 내용은 아래의 링크에 설명되어있습니다.
https://coding-review.tistory.com/566
메세지 브로커의 근심과 걱정
마이크로 서비스와 메세지 브로커는 뗄 수 없는 사이입니다. 서로 다른 도메인이 여러개의 서버로 나눠져 있는 상황에서 모든 서버에 동일하게 데이터를 전달해야 하는 경우에 메세지 브로커만
coding-review.tistory.com
요약하자면, 데이터베이스 연산이 완료되고 Offset을 커밋한다는 개념입니다.
결론은?
결론은 수동 커밋에 Outbox 패턴을 잘 버무려서 사용하면 될 것 같습니다.
성능 최적화 및 튜닝
카프카의 성능을 최적화하는 방법에는 Producer 최적화, Consumer 최적화, 마지막으로 Broker 최적화가 있습니다.
Producer 최적화
Producer를 최적화하는 방법에는 Batching, Compression 이렇게 두 가지가 있습니다. Batching 처리를 하는 것은 높은 처리량이 요구되는 서비스인 경우 필수적으로 사용하게됩니다.
한 번 메세지가 도착하면 한 번 처리하는게 아닌 배치처리를 하는 것인데 이렇게 하면 네트워크 비용도 아끼고 처리량도 올라가게됩니다. 기본적으로 메세지가 도착하자마자 처리하는게 디폴트 값인데 이 값을 설정해주면 배치처리에 용이해지고 처리량이 올라가게됩니다.
또한, 메세지를 한번에 처리할 때 압축해서 처리하는 것을 Compression이라고 부르고 이렇게 처리해주면 또 한 번의 네트워크 비용이 감소되고 처리량도 더 올라가게 됩니다.
GPT피셜이긴 하지만 참고할만한 사진을 가져왔습니다.

Consumer 최적화
Consumer를 최적화하는 방법은 polling 시간을 짧게 설정해주어 리밸런싱을 최소한으로 일어나게 하거나 메세지를 묶음으로 처리해서 처리량을 높이는 방법이 있습니다.

이것도 GPT피셜이긴 하지만 참고가 될 것 같아서 가져왔습니다.
카프카 스토리지와 OS 레벨 연계
카프카는 단순한 메세지 큐잉 서비스가 아니라 디스크 기반의 로그 시스템에 가깝습니다. 심지어 JVM 기반인데 어떻게 속도가 그렇게 빠르게 나올까요?
해답은 Off-Heap 메모리에 있습니다. Off-Heap은 JVM에서 사용하는 Heap 메모리 외부의 메모리 즉, OS에 할당된 메모리입니다.
카프카는 JVM기반이기에 GC를 최소화시키고 싶은 욕구가 있었습니다. 실제로 Elasticsearch의 경우 JVM 기반이기에 대용량 로그를 처리할 때에는 반드시 JVM 튜닝이 필요합니다. 제가 알기로 디스코드였나 트위터였나 초반엔 Elasticsearch를 쓰다가 너무 크기가 커지고 성능을 최적화하기에 JVM이 거슬려서 다른걸로 갈아 탔다고 들었습니다.
카프카는 JVM에서 사용하는 Heap 메모리를 이외의 외부 메모리를 적극 활용하는데 mmap, DirectByteBuffer, sendFile()과 같은 시스템 콜을 적극 활용합니다.
mmap
mmap은 디스크에 있는 데이터를 메모리로 올리는 역할을 하고 이를 통해 메모리에서 직접 데이터를 가져오는 효과가 생겨 속도가 빨라집니다.
DirectByteBuffer
DirectByteBuffer는 네트워크와 메모리 사이에서 처리해주는 버퍼 메모리로 JVM에선 ByteBuffer라는 것이 있어서 내부의 Heap 메모리에 접근하기 용이하게 설계되어있습니다.
JVM기반 애플리케이션에서 직접 외부 메모리에 접근하고싶은 요구가 생겨 DirectByteBuffer라는 외부 메모리에 접근할 수 있는 기능을 추가했는데 직접 메모리에 붙어서 작업할 수 있어서 속도가 굉장히 빠르지만 GC같은 cleaner가 없어서 메모리 누수가 발생할 수 있다는 단점이 있습니다.
때문에 JVM기반 애플리케이션에서 지속적으로 cleaner를 호출해서 메모리를 정리해줘야합니다.
zero copy
zero copy란 데이터를 유저모드로 가져오지 않고 직접 메모리에서 컨슈머에게 전송하는 방법으로 주로 sendFile() 시스템 콜을 사용합니다.
zero copy에 대한 내용은 아래의 링크에 자세하게 설명이 되어있습니다.
https://coding-review.tistory.com/585
카프카는 어떻게 수십만 TPS에 도달할 수 있었을까?
요즘은 카프카와 NoSQL을 공부하고 있는데 카프카는 특히 공부하면 공부할수록 왜 개발자들이 많이 사용하는지 알 것 같습니다. 공부하면 공부할수록 왜 쓰는지 이해가 된달까요.. 이번 포스팅
coding-review.tistory.com
즉, 카프카는 실상 메모리와 Page Cache의 hit 비율이 카프카 전체 성능에 큰 영향을 준다고 볼 수 있습니다.
때문에, dirty page의 크기를 관리한다거나 메모리를 관리하는 것이 카프카의 성능을 튜닝하는 방법이라고 볼 수 있습니다..만!
운영체제는 웬만하면 건드리지 않는게 좋겠죠..? ㅎㅎ..
마치며
이번 포스팅을 끝으로 카프카에 대한 이론 정리를 마쳤습니다. 이제 직접 카프카 클러스터를 구축해보면서 실제로 독립적인 (도커로 독립시키면 그게 독립이죠 ㅎㅎ.. 절대 클라우드 비용 내기 싫어서 그런거 아닙니다.) 애플리케이션에서 카프카에 메세지를 Producing해보고 Consuming해보겠습니다.
이번 포스팅은 여기서 마치도록 하겠습니다. 오늘도 즐거운 하루 되세요!
'배포 > Apache Kafka' 카테고리의 다른 글
카프카는 어떻게 수십만 TPS에 도달할 수 있었을까? (0) | 2025.03.27 |
---|---|
아파치 카프카 (심화) (0) | 2025.03.18 |
메세지 브로커의 근심과 걱정 (0) | 2024.11.07 |
아파치 카프카 (개념) (0) | 2024.05.18 |