ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Slack에서 Kafka 운영/관리 하는 방법
    개발하면서/타인글보면서 2023. 6. 4. 11:41
    반응형

    트위터에서 Slack uses Kafka at Scale라는 제목을 시작으로
    Slack에서 카프카를 왜 썼고 어느정도 규모인지 얘기하는 thread가 있어 정리해 봤다.

     

    https://twitter.com/BdKozlovski/status/1661700334157430784

     

    트위터에서 즐기는 Stanislav Kozlovski

    “Slack uses Apache Kafka at scale: - 6.5Gbps - 700TB of data - 100s of nodes Here's their story 👇”

    twitter.com


    네트워크 망은 6.5 Gbps를 사용하고 700TB 데이터, 100개 이상의 서버 노드가 존재한다.

     

    1.  2016년에 큐 시스템으로 Redis를 사용

    서비스 Web App들이 Redis에 Job을 추가(enqueue)하면
    Worker들이 Redis에서 Job을 빼고(dequeue) 처리하는 방식이었다.

     

    실시간 응답 해야 하는 웹 요청을 제외한 모든 작업은 큐를 사용했다.
    여기서 말하는 웹 요청 제외한 작업이란

    알림, 검색 색인, 업데이트, 보안 검사, 메시지에 있는 링크 발라내기 등이 있다.

     

    작업 처리에 사용되는 DB 속도가 저하되면서 Redis에 작업들이 쌓여갔고 Redis memory limit에 도달했다.

    새로운 작업을 Redis에 넣을 수도 없었고,
    추가했던 기존 작업들을 삭제하려면(dequeue) 약간의 메모리가 필요해서 제거할 수도 없었다.

    Redis는 아무것도 할수 없었다.

     

    피크시간 때 1초에 33,000개의 작업이 추가되는데

    . Redis는 기존 작업을 삭제하는데(dequeue) O(N) 시간 복잡도다. 큐 사이즈가 커지면 삭제시간은 비례

    . 작업을 처리하는 woker가 스케일 아웃 하기 어려운 구조다. Slack은 Redis의 데이터를 poll 하는 별도의 서비스를 구축

    . 모든 Web App은 Redis와 커넥션을 맺어야 하는 구조

    . 큐에 추가되는 속도가 삭제되는 속도보다 빠른 경우 OOM이 발생하고 복잡한 수작업 없이는 복구 어려움

     

    2.  그래서 솔루션은? Kafka

    솔루션 선택에 고려한 것은?

    . 메모리 OOM과 작업 유실을 방지하기 위한 내구성(durable)이 뛰어난 스토리지

    . 속도조절(rate limit)과 우선순위(prioritization) 기능을 제공하는 잡 스케줄러

    . 스케일 아웃을 쉽게 하기 위해 Redis와 Worker의 디커플링

     

    i3.2xlarge(61 GiB, 8 vCPU, 1.9TB NVMe SSD) 타입의 16개 브로커이고

    각 토픽은 32개 파티션이고 retention은 2일(주말포함하면 3일이 좋지 않나...)

    Replication Factor 3, Kafka version 0.10.1.2

    rack-aware 옵션 키고, unclean leader election enabled (뭔지 공부해야겠다.) 

     

    3.  Redis에서 Kafka로 이관하는 과정

    1. Redis 앞에 Kafka를 두고 Go로 Http Proxy 역할을 하는 kafkagate가 있어서
      PHP WebApp이 작업을 Http로 kafkagate에 보내면 kafkagate는 Kafka에 전송했다.

    2. 앞에서 말한 kafkagate는 Go sarama library를 사용했고 지연시간과 데이터 유실을 고려해서 ack=1로 설정했다.

    3. Web App은 동일한 AWS AZ에 있는 kafkagate에 전송하도록 했다.
    4. Go로 만든 JQRelay는 Kafka에서 메시지를 가져와 decode 및 encode 해서 Redis에 저장한다.

    4-1. JQRelay가 시작하면 Consul Lock을 획득한 뒤에 특정 토픽 데이터를 가져올 수 있었다.

     

    Head-Of-Line(HOL)란? 특정 처리가 밀리면 이어서 뒤에 계속 밀리는 현상

    JQRelay에서 Redis에 쓰는 작업이 밀릴 경우 DLQ 같은 특정 카프카 토픽에 쓴 뒤 버린다.

     

    4. Kafka Queue sytem 적용

    부하 테스트 진행

    - 클러스터 재시작

    - 같은 AZ에 있는 카프카 Broker를 1개 또는 2개 강제 종료 / Graceful 종료해서

      3개 브로커가 강제로 unclean leader election 상태로 가게 한다.

    Unclean leader election?

     

    실제 배포 순서

    1. 두벌 쓰기

    - (아마도 kafkagate가 했을 듯?) 하나의 작업에 대해 Kafka와 Redis 두 곳에 쓰기 작업을 한다.

    - JQRelay는 shadow 모드로 Redis에 쓰지 않고 버린다.

    2. 지표를 비교하고 모니터링해서 정확성을 보장한다.

    3. 1분에 한번 모든 파티션에 canary-message를 보낸다.

    4. 사용자의 작업 유형별로 하나씩 roll-out 합니다.

     

    5. Kafka 클러스터가 여러개 생기면서 발생하는 파편화

    2017년, Slack에서는 S3를 데이터 웨어하우스로 쓰고 있었고

    Hive, Presto, Spark로 저장된 데이터에 쿼리를 날렸다.

     

    Kafka 메시지를 S3에 업로드하는 Pinterest의 Sector라는 라이브러리를 사용하고 있었다.

    2018년, 별도의 카프카 클러스터가 필요해서 셋업 했는데

    기존 클러스터와 버전이 달라 카프카 배포와 운영/관리에서 중복의 노력이 들었다.

     

    또한 시각화를 위해 분산 trace event를 적절한 저장소로 안내하는 중간 역할도 한다.

    하루에 310M trace event, 8.5B span이 발생한다.

    ※ Trace와 Span의 차이가 궁금해서 찾아봄

    https://ccambo.tistory.com/entry/Opencensus-Trace-Opencesus%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-Trace-%EC%A0%95%EB%A6%AC

     

    2021년에는 하나의 카프카 클러스터가 90개 브로커로 구성되어 있었는데
    하루에도 여러 번 Consumer lag이 발생했다.

    어떻게 고쳤냐면 자동화 도구를 이용하여 클러스터를 분리했다. ㅎㅎ 쉽쥬?
    분리할 때 d2 타입에서 d3 타입으로 변경했다.

     

    6. Kafka 클러스터 관리/운영

    2022년 카프카는 다양한 곳에서 사용되고 있었다. (trace 데이터, 로깅 파이프라인, 결제, 보안 분석 등)

    구성되는 인프라도 어마어마 해졌다.

    • 네트워크 사용량은 6.5 Gbps
    • 1초에 1M 메시지
    • 700TB 데이터
    • 카프카 클러스터 10개
    • 100개 서버 노드

    카프카 클러스터 10개를 관리하려면 수작업으로는 한계가 있다.

    그래서 많은 부분을 자동화하는 프로그램을 만들었다.

    • topic / partition 생성과 재할당
    • 브로커 추가/삭제
    • 서버 노드 교체와 버전 업그레이드
    • 모니터링

    Provisioning

    • OS 설치와 카프카 설정은 Chef
    • AWS에서 Auto Scaling Group(ASG) 생성은 Terraform
    • Fork 한 Kafka를 CI/CD 하고 빌드해서 생성한 바이너리 파일은 S3에 올리고 Chef로 땡겨받음
    • Consul KV를 이용해서 unique ID 생성 (어디에 쓰였다는 건지 이해 못 함)

    Slack에서는 균등하게 배분하기 위해 파티션 개수를 브로커 개수의 배수로 늘렸다.

    10개 브로커가 있다면 한 토픽의 파티션은 10개, 20개, 30개로 지정한다.

     

    동시에 많은 파티션을 재할당하면 네트워크 bandwidth를

    순간적으로 많이 잡아먹어 producer와 consumer가 멍때린다.

    그래서 Cruise Control을 이용해서 파티션 재할당 작업을 한번에 하지 않고 조금씩 진행했다.

     

    모든 팀들이 Kafka 상태를 쉽게 확인하기 위해 CMAK을 설치했다. (마지막 커밋이 2022년 12월)

     

    Prometheus 대시보드를 만들어서 per-topic, per-consumer 메트릭을 모니터링했다.

    (Prometheus exporter의 "kafka offset explorer" 사용)

     

    Kafka 업그레이드는 한 대씩 하지 않고 아예 새로운 카프카 클러스터 하나 구성한 뒤
    dark traffic 보내 정상동작 확인 후producer가 새로운 클러스터를 바라보도록 수정한다.

    기존 클러스터는 data retention 기간 이후에 제거한다.

     

    왜냐? 편안한 밤을 위해서!!

     


    Uber에선 MSA의 큐로 Kafka 사용한 사례가 있어요. 관심 있으신 분은 아래 링크 고고!
    https://dol9.tistory.com/296

    반응형

    댓글

Designed by Tistory.