Hadoop eco

[발표 자료] Kafka를 다뤄본 경험

root_bridger 2022. 12. 1. 03:01

 

데이터 파이프라인 구축 및 시각화 프로젝트를 끝내고 Kafka에 대해 같이 공부하는 사람들과 내용을 공유할 수 있는 기회가 생겼다. Kafka에 대해 생소한 사람들이 많았기 때문에 기본적인 내용을 담고자 했다. 블로그에도 그때 발표 했던 내용을 작성해 놓기로 했다.

대상은 Kafka를 모르는 분들이다. Kafka를 들어보기만 했고, 사용해 보지는 않은 사람, 또는 Kafka를 실습 시작 전에 한번 빠르게 훑어 보고 싶은 사람들을 위한 내용이다. 발표를 들은 동기들 역시 그러한 케이스들이였다.

 

 

 

내가 Kafka를 쓴 이유는 단순했다. 데이터를 수집했어야 했고, 모은 데이터가 날아가지 않고 온전히 서버 컴퓨터로 전달 됐어야 했다. 여러가지 데이터를 모아야 할 수도 있었고, 데이터가 실시간으로 발생하는 만큼 수집하는 과정 역시 실시간 진행 되어야 했다. Kafka는 그러한 역할을 아주 잘 성실히 해준다. 고속 메세징 큐로 데이터를 빠르게 통신하며 디스크로 데이터를 저장한다. 

 

사실 지금 생각해보면 오로지 데이터 수집을 목적으로 하는데 kafka까지 써야 했을까? 물어본다면 나도 과하다고 생각한다. 해당 상황에선 Python 코드로 API를 수집하고 File로 저장해둬도 된다. 하지만 여러가지 데이터를 끊임없이 수집하며, 하나의 컴퓨터만을 사용하는 것이 아닌, 범용 컴퓨터를 여러개 묶어 하나의 큰 컴퓨터로 사용할 수 있는 클러스터링을 통해

서버 자원을 좀 더 효율적으로 사용할 수 있다는 장점으로 생각하면 충분히 사용할 수 있다고 생각했다.

 

그리고 무엇보다 '이때 아니면 언제 Kafka - Spark Streaming을 붙여서 써보겠나?'라는 이유 역시 강하게 작용했다..ㅎㅎ

Kafka는 Input과 Output을 위한 저장공간이다. 그것을 여러 컴퓨터를 묶어 하나의 컴퓨터처럼 사용하고 있다. 위의 사진처럼 과거에는 상호간에 통신을 통해 데이터를 전송했지만, 해당 서버나 아키텍처가 커짐에 따라, 서비스가 증가함에 따라 여러가지 어플리케이션, 데이터 베이스 등이 늘어나게 되고 이는 서버관리에 커다란 문제점을 야기했다.

링크드인에서 처음 개발한 Kafka는 이러한 아키텍처를 효율적이고 쉽게 만들어 준다. 카프카로 Input, Output을 지정해주고 모든 데이터를 카프카 안에서 찾기만 하면 되는 것이다. 이렇게 Kafka를 데이터 허브로 운영하면 서버 관리에 효율성을 더해 줄 수 있다.

추가로 Kafka에 저장할 때는 데이터가 저장되는 시간을 지정할 수 있다. 지정된 시간이 지나면 자동으로 사라진다. 이는 Kafka의 가장 큰 장점 중 하나다. 이로 인해 Kafka는 다양한 회사에서 다양한 목적으로 운용되고 있다.

카프카를 설치하려면?

  • zookeeper 설치 : 설치 및 앙상블(클러스터) 구축, 환경 설정
  • Kafka 설치 : 설치 및 브로커 클러스터 구축, 주키퍼 연결 등 환경 설정
  • 프로듀서 생성 : 해당 데이터를 받아 올 주소로 요청, 해당 데이터를 받아온 다음 브로커로 데이터 전송
  • 컨슈머 생성 : 브로커에 있는 데이터를 불러오는 코드를 생성

Kafka를 설치 한다면 zookeeper와 kafka를 같이 설치 해줘야 한다. Kafka의 메타 데이터는 Zookeeper로 관리한다. 그렇기 때문에 Zookeeper가 동작하고 있어야 kafka가 메타 데이터를 전송하며 동작할 수 있다.

기본적으로 Kafka는 Pub/Sub 구조이다. 데이터를 생산하면(Producer의 역할) 데이터를 저장하는 여러대의 서버 묶음(Broker Cluster의 역할)에서 저장하고 있다가, 해당 데이터를 사용할 때(Consumer의 역할) 데이터를 전송 받아 사용한다.

 

이쯤에서 kafka가 뭔지, Zookeeper가 뭔지 Producer, Consumer? 다양한 개념이 나온다. 잠깐 짚고 넘어 가자면,

 

Kafka 내부 구성

  • Zookeeper : 메타데이터 저장(브로커id, 컨트롤러id), 대장 브로커(컨트롤러 브로커)정보 저장, 주키퍼에 저장되는 데이터는 모두 메모리에 저장되어 처리량이 크고 속도가 빠르다. 
  • Zookeeper ensemble : 여러 대의 주키퍼를 클러스터링 한 것. 주키퍼에선 클러스터를 앙상블이라고 부른다. 홀수대(3,5)로 구성 권장, 주키퍼 몇 개 다운 되더라도 과반수가 살아 있다면 상태 지속 가능
  •  
  • Kafka : 대용량 고속 메시징 큐 : MQTT 방식처럼 작동(MQTT 프로토콜로 작동하는 것은 아님)
  • Kafka가 고속으로 동작하는 이유 : 브로커는 하는 것이 거의 없다. 그냥 저장을 해둘.
    (프로듀서와 컨슈머에서 데이터 write/read 하고, 저장할 공간도 정하고(토픽, 파티션 지정)…다 하니까..)
  • Producer : 생산자,데이터를 불러와 브로커에 저장하거나 직접 생성(Producer)하는 일종의 인풋 개념.
  • Producer를 조정하며, 목적에 따라 사용할 수 있다.
    • 메시지 전송 시 배치 처리 가능
      (batch_size를 조절, batch size를 키운다면 한번에 모아서 데이터를 전송하기 때문에 네트워크 통신 횟수를 줄일 수 있다.)
    •  
      특정 파티션으로만 전송 가능
      (key값에 따라 해당 Key에 맞는 Partition을 지정하기 때문에)
    • Acks : 전송하는 방식을 지정 할 수 있다. 0, 1, -1로 설정 가능하다.
       
      Ack 0 : 빠르게 전송, 난 줬음 받았는지는 확인 안함
      Ack 1 : 기본값, 리더 파티션이 받았는지는 확인
      ack all : 보냈는데 리더 파티션, 팔로워 파티션 둘 다 받음?
    •  
      Serializer : byte 배열로 변환, 직렬화 방식을 지정할 수 있다.
    • Partitioner : 파티션 결정
  • Consumer : 소비자, 데이터를 읽어오는(Consumer) 일종의 아웃풋 개념.
    • 커밋한 오프셋부터 읽어올 수 있음
    • 한 개의 컨슈머는 여러 개의 토픽을 처리 가능
    • 같은 그룹의 컨슈머는 같은 파티션을 공유할 수 없음.
    • 메시지 데이터를 받아 오는게 아니라 읽어 오는 것.(이미 데이터를 파일로 저장했기에), 그래서 메시지를 읽어 왔다고 해서 지우지 않음.
      이는 데이터를 디스크에 저장하기 때문.
    • 컨슈머 하나 다운? Rebalance : 파티션 별로 컨슈머 그룹 내에 컨슈머가 재배치
라고 정리할 수 있다. 여기까지 이해가 됐다면 다음은 토픽과 파티션의 개념을 알면 좋을 것이다. 브로커에는 데이터가 저장되고, 이 데이터는 토픽 안에 있는 파티션에 저장된다.
 
  • Topic : 메시지 구분 단위, 하나 이상의 파티션으로 구성, 메시지를 목적에 맞게 구분하기 위함, 이름도 지정 가능
    (Topic 생성 시 파티션 개수를 지정 가능, 개수 변경은 추가만 가능하고 삭제는 불가능)
  • 전송한 메시지는 어디에? Log Segment : 브로커 컴퓨터의 로컬디스크에 로그파일 형태로 저장되어 있음
  • Partition : 메시지 파일 단위, 몇 줄의 레코드를 가짐
  • Offset : 파티션 내 메시지 위치, 레코드 번호(인덱스 번호라고 생각하면 쉬움)
  • Relication : 복제본
    • Leader Partition : 데이터 요청을 처리 담당, 일명 "진짜 데이터"
    • Follow Partition : 리더 파티션 데이터 복제본이 있는 파티션, 리더 파티션이 다운되면 리더로 선출된다.
    • ISR(In-Sync Replica) : 파티션에 리더와 팔로워가 복제되어 있는 그룹(ISR 그룹의 구성원은 리더의 자격을 받음)
  • 파티션 내에서 메시지는 순서대로 쌓임 -> 순서대로 읽힘(FIFO, "메세징 큐"니까)
    (ex 1~100
    까지 있는 파티션 : 50번부터 읽는다고 정의하면 50,51,52,53…..순서로 읽음)
  • 메시지 처리 순서는 파티션 별로 유지 관리
    • 파티션이 여러 개일 때 데이터는 어떻게 쌓일까? : key 값을 설정했다면 key에 따라 송신처 파티션을 정함
    • key값 안 정했다면? Round Robin : 포커에서 여러 사람한테 카드패 뿌리듯 데이터 하나씩 줌
특히 파티션의 경우, Consumer와 1:1 대응 이상적이라고 생각한다. 만약 파티션 3, 컨슈머 4개라면? 컨슈머 한대는 파티션 할당을 못 받기 때문에 대기하게 되는 것이고, 이는 리소스 낭비라고 생각한다. 그렇다고 하나의 파티션에 N개의 컨슈머가 붙는다고 해서 성능 상 이득을 볼 수 없다. 고로 1:1 대응이 최대한 구성될 수 있도록 설계하는 것이 중요하다.
(해당 내용은 다음에 다시 알아보도록 한다.)
또한 Consumer 하나에 장애 발생 한다면, 할당된 파티션은 다른 컨슈머에서 처리(재조정)된다. 하나의 파티션을 여러 파트에서 컨슈밍을 해야 한다면 컨슈머 그룹을 다르게 지정하면 된다. 다른 그룹 컨슈머는 같은 파티션을 공유 가능하기 때문이다. 이로 인해 다양한 목적 따라 컨슈머 그룹을 분리해서 관리한다면 추후 수정이나 확장 시 편하게 관리 할 수 있다.

 

나는 어떻게 썼을까?

 

3대의 Kafka 브로커와 3대의 Zookeeper로 구성했다. 또한 Producer는 Python으로 작성했다(Kafka-python 라이브러리 사용). 공공자전거 실시간 사용 데이터를 받아와야 했기 때문에, 2000여개의 대여소 정보를 API로 받아왔다. Producer는 While문을 사용해서 API 호출 코드가 계속 작동 되도록 돌려놨다. 이후 Consumer는 Spark Streaming 하나에서만 불러오면 됐기 때문에 Partition은 하나만 구성했다.

 

다음에 Spark Streaming에 대해 포스팅 하겠지만, Kafka 내의 데이터를 Spark Streaming으로 불러오려면 기본적인 테이블 형태에 맞춰 불러와진다. 원하는 형태로 사용하려면 한번의 전처리가 필요하다 이후 데이터를 가공하면 된다. 해당 내용은 다음에 Spark Streaming에 대한 경험을 작성할 때 다시 올리겠다.

 

끝으로

Kafka를 사용하기 전에 어느정도 도움이 됐으면 좋겠다. 다시 말하지만 초심자를 위한 내용으로 너무나도 기본적인 내용을 담고 있다. 또한, 내 개인적인 경험에 의거해서 작성된 글이기 때문에 틀린 부분이 많을 수 있다. 댓글로 말씀 해주시면 너무나도 감사하겠다. 이는 다음 이 글을 볼 지 모르는 다른 사람에게 도움이 될 것이다.

 

Kafka는 참 범용으로 다양하게 쓰일 수 있다. 그만큼 다양한 파라미터와 기능을 제공한다. 지금은 나는 현재 프로젝트를 위한 클러스터에 더 성능과 안정성이 향상될 수 있도록 설정을 조정해보고 있다. 배워보며 경험해보며, 하면 할 수록 많은 기능에 감탄하게 된다.

 

정말 마지막으로 Kafka를 배워보고 싶은 사람들에게 한가지 말하고 싶다.

정말로 재밌는 기술이다. 설치하고 단순히 사용하는게 아닌, 데이터 양을 고려하고, 가용 가능 리소스를 고려하며 배워본 다면 끝이 안 보일 만큼 방대한 내용을 습득 해야 한다. 그만큼 알 수 있는 내용이 많아 재밌을 것이다. Kafka의 필요성과 장점은 이미 충분히 알고 있을 것이라 생각한다.