ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Kafka(1) - 카프카란 무엇일까?
    CS/Spring 2024. 7. 26. 01:32

    Kafka란?

    아파치 카프카(Apache Kafka)는 LinkedIn에서 개발한 분산 스트리밍 플랫폼이다.

    발행-구독 모델을 기반으로 동작한다.

     

    카프카 전의 링크드인의 데이터 처리 시스템 구조

     

    기존 링크드인의 데이터 처리 시스템은 그림과 같이 각 애플리케이션과 DB가 end-to-end 로 연결되어 있고, 요구사항이 늘어남에 따라 데이터 시스템 복잡도가 높아지면서 장애 발생 대응이 어렵고 확장성이 떨어져 관리의 어려움을 겪었다.


    이러한 문제를 해결하기 위해 새로운 시스템의 개발 필요성이 높아졌고, 다음과 같은 목표를 가지고 새로운 시스템을 개발했다.

    모든 시스템으로 데이터를 전송할 수 있고, 실시간 처리도 가능하며, 급속도로 성장하는 서비스를 위해 확장이 용이한 시스템을 만들자!

     

    카프카 구조를 적용한 후

     

     

    카프카를 적용함으로써 앞서 말했던 문제점들이 어느정도 완화되었다.

    • 모든 이벤트/데이터의 흐름을 중앙에서 관리할 수 있게 됨
    • 새로운 서비스/시스템이 추가되도 카프카가 제공하는 표준 포맷으로 연결하면 되므로 확장성과 신뢰성이 증가
    • 개발자는 각 서비스간의 연결이 아닌, 서비스들의 비즈니스 로직에 집중 가능

     

    발행 구독 모델

    발행-구독 모델은 비동기 메시징 패러다임이다. 발행-구독 모델에서 발행자와 구독자는 서로 알지 못한다.

    주제(topic)에 맞게 중간 역할자인 브로커에게 전달하면 구독자(Consumer)가 브로커에 요청해서 가져가는 방식으로 발행자는 메시지를 topic으로 카테고리화 구독자는 topic에 맞는 메시지를 브로커에게 요청한다.

    따라서 수신자는 발행자에 대한 지식이 없어도 원하는 메시지만을 수신할 수 있다.

    이러한 발행자와 구독자의 디커플링은 더 다이나믹한 네트워크 토폴로지와 높은 확장성을 허용한다.

    디커플링(Decoupling
    발행자(publisher)와 구독자(subscriber) 간의 종속성을 줄이는 것을 의미한다.

    디커플링의 주요 목적은 시스템의 유연성과 확장성을 높이는 것이다.

    [디커플링의 목적] 
    독립적 개발 및 배포: 발행자와 구독자는 서로의 존재를 몰라도 되기 때문에, 독립적으로 개발 및 배포가 가능하다.
    확장성: 구독자는 필요에 따라 추가하거나 제거할 수 있으며, 발행자는 이에 영향을 받지 않는다. 반대로, 발행자의 수가 늘어나더라도 구독자는 동일한 방식으로 메시지를 받을 수 있다.
    내결함성 및 안정성: 발행자 또는 구독자 중 하나가 실패하더라도, 시스템 전체가 영향을 받지 않도록 설계할 수 있다. 메시지 브로커가 메시지를 중간에서 관리하기 때문에, 발행자가 보낸 메시지는 나중에라도 구독자가 받을 수 있다.

     

     

    Topic-Partition

    Topic

    메시지는 topic으로 분류된다. topic은 발행자가 스트림을 발행하는 단위

    Partition

    • 하나의 topic은 여러 개의 파티션으로 저장할 수 있다. (기본은 토픽 하나에 파티션 한개)
    • 1개의 토픽은 여러 개의 파티션으로 저장되고, 하나의 파티션은 여러개의 로그로 기록된다.
    • 하나의 토픽을 여러 파티션으로 나누면 메세지 분산 처리로 처리량을 높일 수 있고, 분산 저장을 통해 오류가 발생할 때 데이터를 복구할 수 있다.
    • partition내의 메세지의 고유한 위치를 offset이라고 하며 각 파티션의 메시지는 오프셋에 따라 순서대로 저장되고 읽힌다. (배열에서 index라고 생각하면 된다.)
    • 또한, 파티션을 늘렸을 때 메세지가 Round-robin방식으로 쓰여진다. 즉, 순차적으로 메세지가 쓰여지지 않는다.
    • 파티션의 크기는 운영 중에 동적으로 줄일 수 없기 때문에 파티션 개수를 설정할 때 주의해야 한다.

     

    Offset의 사용
    하나의 토픽에 두 개의 파티션이 있다고 가정.
    이 토픽으로 네 개의 메시지를 전송하면 다음과 같이 각 파티션에 메시지가 저장될 수 있다.
    Partition 1 : [오프셋0] "msg1" / [오프셋1] "msg3"
    Partition 2 : [오프셋0] "msg2" / [오프셋1] "msg4"
    만약 메세지를 읽는 주체인 Consumer가 partition1의 offset0 메세지를 읽었다고 할 때, 다시 메세지를 읽으려할 때 마지막으로 읽은 위치부터 다시 읽기 시작할 수 있다. (책갈피 같은것!)
    라운드 로빈 방식의 문제점
    하나의 토픽에  "안녕"-> "내가"-> "카프카에 대해" -> "설명해줄게" 순서대로 발행자가 메세지를 보냈고, 메세지들이 다음과 같이 저장됐다고 해보자.
    Partition 1 : [오프셋0] "안녕" / [오프셋1] "카프카에 대해"
    Partition 2 : [오프셋0] "내가" / [오프셋1] "설명해줄게"
    하나의 파티션 안에서는 메세지가 보내진 순으로 저장되지만, 파티션이 결정될 때는 라운드 로빈 방식에 의해 결정되므로 순차적으로 저장되지 않는다. 

    이런 상황에서 컨슈머가 메세지를 읽을 때, 실제 메세지 발행자가 보낸 메세지 순서와 다르게
    "내가" "설명해줄게" "안녕" "카프카에 대해" 
    "안녕" "내가" "설명해줄게" "카프카에 대해" 
    이런 식으로 의도와 다른 순서로 읽게 될 수도 있다

    해결 방안
    컨슈머가 동일한 순서로 메시지를 읽도록 하려면 다음과 같은 방법들을 사용할 수 있다.
    1. 파티션을 하나로 유지
    토픽을 하나의 파티션으로 구성하는 것이다. 이렇게 하면 메시지가 보낸 순서대로 저장되고 읽힐 수 있다. 그러나 이 방법은 확장성(scalability)을 제한한다.
    2. 메시지에 타임스탬프 또는 시퀀스 번호 추가
    발행자 측에서 각 메시지에 타임스탬프 또는 시퀀스 번호를 추가하고, 컨슈머 측에서 이를 기반으로 메시지를 정렬하는 방법이다. 이 방법은 파티션 간 순서를 맞추기 위한 추가적인 작업이 필요하다.
    3. 특정 파티션에 키를 사용하여 메시지 분배
    메시지를 특정 파티션으로 보내도록 키를 설정한다. 예를 들어, 모든 메시지를 하나의 파티션에만 보내면 해당 파티션 내에서 순서가 보장된다.

     

    Producer, Consumer, Broker

    발행자(Producer)

    • 메세지를 생산하는 주체 메세지를 만들고 브로커(Broker)에게 토픽(Topic)으로 분류된 메시지를 전달
    • 메시지는 배치 형태로 전달
    • 발행자는 구독자의 존재를 알지 못함

    구독자(Consumer)

    • 소비자로 메세지를 소비하는 주체
    • 발행자의 존재를 알지 못함
    • 원하는 토픽을 구독하여 스스로 조절해가면서 소비할 수 있음
    • 원하는 토픽의 각 파티션에 존재하는 오프셋의 위치를 기억하고 관리하여 데이터의 중복을 관리한다.
    • 또한 발행자, 구독자에 장애가 발생해도 마지막으로 읽었던 위치에서 부터 다시 구독 가능하다. (fail-over에 대한 신뢰가 존재)
    • 구독자는 여러 그룹으로 나뉠 수 있다.
    [구독자 그룹 (Consumer Group)]
    구독자 그룹은 여러 구독자가 협력하여 하나의 토픽의 메시지를 병렬로 처리할 수 있게 하는 구조다.
    구독자 그룹 내의 각 구독자는 그룹 내에서 유일한 컨슈머로 간주되며, 특정 파티션을 담당한다.

    - 파티션 할당:
    구독자 그룹에 속한 각 구독자는 토픽의 파티션을 할당받아 메시지를 처리한다.
    (하나의 파티션은 동일한 그룹 내의 여러 구독자에게 할당되지 않으며, 이는 메시지 중복 소비를 방지한다.)

    - 리밸런싱:
    구독자 그룹 내 구독자의 수가 변경되거나, 새로운 파티션이 추가되는 등의 변화가 있을 때, 파티션 할당이 재조정된다. 이 과정을 리밸런싱(Rebalancing)이라고 한다.

    - 장애 복구:
    특정 구독자에 장애가 발생하면, 해당 구독자가 처리 중이던 파티션은 그룹 내 다른 구독자에게 재할당된다.
    이를 통해 높은 가용성을 유지한다.

    예시:
    하나의 토픽이 6개의 파티션을 가지고 있고, 구독자 그룹에 컨슈머 A,B,C가 있다면, 각 구독자는 2개의 파티션을 할당받게 된다.
    Consumer A: 파티션 0, 파티션 3
    Consumer B: 파티션 1, 파티션 4
    Consumer C: 파티션 2, 파티션 5

    구독자 그룹의 장점
    병렬 처리: 여러 구독자가 동시에 메시지를 처리함으로써 전체 처리 속도를 높일 수 있다.
    확장성: 구독자 수를 늘림으로써 쉽게 확장할 수 있다.
    신뢰성: 구독자 중 하나가 장애를 겪더라도 다른 구독자가 해당 파티션의 메시지를 이어서 처리할 수 있다.

    브로커(Broker)

    • 클러스터로 구성된 메시지 큐
    • 브로커 여러개가 클로스터로 구성돼어 하나의 카프카 클러스터를 만든다.
    • 토픽의 파티션은 리더 브로커에 저장되며 복제본들이 팔로워 브로커에 저장된다.
    • 파일 시스템에 메시지를 저장하므로 유실이 없고 복구 가능
    • 하드디스크의 순차적 읽기 기능을 이용하여 속도를 유지
    • 구독자가 메시지를 가져가도 바로 삭제하지 않음 기본 설정은 7일간 저장하고 삭제

    리더와 팔로워:
    - 리더: 각 파티션에는 리더가 있으며, 클라이언트의 읽기 및 쓰기 요청을 처리한다.
    - 팔로워: 리더의 데이터를 복제하여 저장하며, 리더가 장애가 발생하면 팔로워 중 하나가 리더 역할을 대신한다.

    데이터 복제:
    각 파티션은 클러스터 내의 다른 브로커에 복제본을 가진다. 이를 통해 하나의 브로커에 장애가 발생해도 다른 브로커에서 데이터를 복구할 수 있다.

    분산 저장:
    파티션이 여러 브로커에 분산 저장됨으로써, 클러스터의 부하가 분산되고, 성능이 향상된다.

    이 구조를 통해 각 브로커는 특정 파티션의 리더 역할을 하며, 동시에 다른 파티션의 팔로워 역할도 하여 데이터의 일관성과 가용성을 보장한다.

     

     

    kafka 전체 구조

Designed by Tistory.