Kafka의 Consumer Thread 최적화하기

메모리 제약 조건 하에서 Kafka의 처리 성능을 개선한 경험을 공유하고자 한다.

기존 상황과 문제점

처음에는 단일 컨슈머 스레드를 사용했다. 이 구성으로는 초당 약 400개의 메시지밖에 처리하지 못하는 한계가 있었다. 물론 사용자가 없는 프로젝트이긴 했지만, 사용자가 있다는 가정을 한다면 실시간 로그를 많은 사용자 애플리케이션에서 수집해야 하므로 성능 향상이 필요하다.

성능 개선을 위한 분석

가용 메모리가 1GB로 제한된 상황에서, 최적의 구성을 찾기 위해 몇 가지 계산을 진행했다.

메모리 사용량 분석

최적의 구성 도출

표: 3초 간격으로 총 소비된 메시지 수(thread 1개)

Timestamp Total Messages Consumed Messages Consumed in 3 Seconds
2024-05-23 08:05:45.247421 588 -
2024-05-23 08:05:48.247421 1347 759
2024-05-23 08:05:51.247421 2441 1094
2024-05-23 08:05:54.247421 3579 1138
2024-05-23 08:05:57.247421 4806 1227
2024-05-23 08:06:00.247421 5724 918
2024-05-23 08:06:03.247421 6604 880
2024-05-23 08:06:06.247421 7598 994
2024-05-23 08:06:09.247421 8789 1191
2024-05-23 08:06:12.247421 9823 1034
2024-05-23 08:06:15.247421 10983 1160
2024-05-23 08:06:18.247421 12221 1238
2024-05-23 08:06:21.247421 13491 1270
2024-05-23 08:06:24.247421 14770 1279
2024-05-23 08:06:27.247421 16017 1247
2024-05-23 08:06:30.247421 17329 1312
2024-05-23 08:06:33.247421 18586 1257
2024-05-23 08:06:36.247421 19883 1297

1초 평균 : 383.3

표: 3초 간격으로 총 소비된 메시지 수(thread 2개)

Timestamp Total Messages Consumed Messages Consumed in 3 Seconds
2024-05-23 08:03:23.481527 891 -
2024-05-23 08:03:26.481527 1773 882
2024-05-23 08:03:29.481527 2877 1104
2024-05-23 08:03:32.481527 4472 1595
2024-05-23 08:03:35.481527 6308 1836
2024-05-23 08:03:38.481527 8348 2040
2024-05-23 08:03:41.481527 9793 1445
2024-05-23 08:03:44.481527 11250 1457
2024-05-23 08:03:47.481527 12850 1600
2024-05-23 08:03:50.481527 14429 1579
2024-05-23 08:03:53.481527 16342 1913
2024-05-23 08:03:56.481527 18360 2018
2024-05-23 08:03:59.481527 20527 2167

1초 평균 : 576

표: 3초 간격으로 총 소비된 메시지 수(thread 5개)

Timestamp Total Messages Consumed Messages Consumed in 3 Seconds
2024-05-23 07:02:21.178118 2552 -
2024-05-23 07:02:24.178118 4750 2198
2024-05-23 07:02:27.178118 6981 2231
2024-05-23 07:02:30.178118 9880 2899
2024-05-23 07:02:33.178118 13096 3216
2024-05-23 07:02:36.178118 16409 3313
2024-05-23 07:02:39.178118 18138 1729
2024-05-23 07:02:42.178118 20233 2095
2024-05-23 07:02:45.178118 22698 2465
2024-05-23 07:02:48.178118 24582 1884

1초 평균 : 927

표: 3초 간격으로 총 소비된 메시지 수(thread 10개)

Timestamp Total Messages Consumed Messages Consumed in 3 Seconds
2024-05-23 07:02:21.178118 2867 -
2024-05-23 07:02:24.178118 6353 3486
2024-05-23 07:02:27.178118 9587 3234
2024-05-23 07:02:30.178118 12700 3113
2024-05-23 07:02:33.178118 15146 2446
2024-05-23 07:02:36.178118 17630 2484
2024-05-23 07:02:39.178118 20565 2935
2024-05-23 07:02:42.178118 23887 3322
2024-05-23 07:02:45.178118 27417 3530
2024-05-23 07:02:48.178118 30987 3570
2024-05-23 07:02:51.178118 34352 3365
2024-05-23 07:02:54.178118 37950 3598
2024-05-23 07:02:57.178118 41499 3549
2024-05-23 07:03:00.178118 45007 3508
2024-05-23 07:03:03.178118 48560 4553
2024-05-23 07:03:06.178118 52065 3705
2024-05-23 07:03:09.178118 55547 4482
2024-05-23 07:03:12.178118 59054 3507

1초 평균 : 1104

이 데이터를 분석해보면 스레드 개수 증가에 따른 처리량이 다음과 같다:

스레드 수를 늘릴 때마다 성능 향상폭이 감소하는 것을 볼 수 있다.

특히 5개 -> 10개 구간은 성능 향상이 이전에 비해 굉장히 완만해진다.

5개 스레드와 10개 스레드를 구체적으로 비교해보자.

스레드 5개:

스레드 10개:

따라서 10개 스레드는 5개 대비 메모리를 2배 사용하지만, 성능은 19% 정도만 향상되고, 처리량이 불안정하다. 그래서 5개의 스레드를 두기로 결정했다.

물론 사용량이 많아 5개의 스레드로 처리를 감당할 수 없다면 또 다른 고민이 필요할 것이다.

성능 지표(5개 스레드 기준)

352MB를 할당해 처리 성능을 약 2.4배 향상시킬 수 있었다.
실제 운영 환경에서는 항상 리소스 제약이 있는데, 여러 제약 조건 내에서 최적의 성능을 끌어내는 것이 중요하다고 생각한다.