프로젝트/기술적 선택

[기술적 선택] 카프카의 도입 이유와 ELK-Stack과 결합한 시스템 설계

배발자 2023. 7. 23.
반응형

 

프로젝트를 진행하면서 서비스의 API 기능을 구현하는 것뿐만이 아니라 '성능 개선', '트래픽 처리'를 주제로 어떤 기술을 도입을 할지 고민을 하는 시점이 있었다. 그때 당시 ELK-Stack을 활용한 로그 수집과 프로젝트 전체 인프라 구축 및 Top-10 인기 검색어 서비스와 알림 서버 구현 등 필자가 맡은 역할은 모두 완료한 상태였다. 

 

어떠한 기술을 도입할 지 고민하고 있을 때 많은 기업 공채에서 'kafka를 적용해본 경험이 있는 분' 이라는 글을 상당히 많이 봤었다. 그게 대체 뭐길래? 기업들이 찾는건지 그때 당시에는 정확히 알지 못했다. 

 

모놀리식 아키텍처가 아닌 MSA 환경의 아키텍처 설계를 현재 수많은 기업들이 채택하고 활용하고 있다. 카프카는 MSA 구조에서 상당히 효율적으로 활용할 수 있는 기술 중 하나이다. 

 

이번 포스팅은 카프카에 대한 개념과 필자가 왜 이 기술을 도입하였는지, 그리고 이 기술을 활용하여 어떻게 아키텍처를 구성하였는지에 대해 설명하고자 한다. 

 

카프카

Kafka는 링크드인(Linked-in)에서 처음 개발되어 2011년 오픈소스화 된 솔루션이며, 실시간으로 스트리밍 데이터를 게시, 구독, 저장 및 처리할 수 있는 '분산형 데이터 스트리밍 플랫폼' 이다. 

 

정확히 무슨 얘기인지 모를 것이다. 다음 그림을 보자. 

 

 

 

기존의 서비스 환경은 end-to-end 연결 방식 즉, 직접적으로 연결하면서 데이터 연동이 복잡해지고 확장이 어려운 구조이다. 하지만 kafka를 활용하면 보내는 쪽에서는 kafka로 메시지만 보내면 되고, 받는 쪽에서는 누가 그 메세지를 보냈는지 상관이 없다. 단순히 메시지를 들고와서 처리하는 구조이다.

* text 형식의 메시지뿐만 아니라 json, xml, java의 Object 등 다양한 데이터 포맷을 사용한다. 

 

이처럼 '확장이 용이한 시스템'이라는 점과 함께 '클러스터링에 의한 고가용성'이라는 특징, '낮은 지연(Latency)과 높은 처리량(Throughput)'으로 인해 Kafka를 활용하면 많은 데이터를 효과적으로 처리할 수 있다. 

 

카프카 공식 문서를 참조해보면 kafka로 데이터를 보내는 'Producer'와 데이터를 가져오는 'Consumer'가 있고, 'Kafka Cluster'를 중심으로 프로듀서가 데이터를 발행, 컨슈머가 데이터 구독하는 즉, 'Pub-Sub(Publisher-Subscribe)' 모델로 동작하고 있다. 

 

사용이유

정리해보면 다음과 같다. 

 

1. 병렬처리에 의한 데이터 처리율 향상

카프카는 데이터를 병렬로 처리함으로써 데이터를 빠르고 효과적으로 처리할 수 있다. disk에 순차적으로 데이터를 적재하기 때문에 임의 접근(random access) 방식보다 훨씬 더 빠르게 데이터를 처리한다.

 

2. 데이터 유실 방지

disk에 적재되기 때문에 만약 불의의 사고로 서버가 다운되었을 시에도 데이터가 유실되는 일 없이 재시작하여 기존 데이터를 안정적으로 처리 가능하다.


3. 클러스터링에 의한 고가용성 서비스

Scale-out이 가능하여 시스템 확장이 용이하며 어떤 하나 혹은 몇 개의 서버가 다운되도 서비스 자체가 중단될 일 없이 시스템이 운용가능하다. 

 

왜 이러한 특징을 가지는지 좀 더 알아보자.

 

 

카프카 구성

 

[프로듀서]

데이터를 발생시키고 카프카 클러스터(Kafka Cluster)에 적재하는 프로세스이다.

 

[클러스터]

실제 서비스에서 사용되는 카프카는 고가용성을 위해 '여러 개의 Kafka 서버와 Zookeeper로 구성된 클러스터 구조'로 사용된다고 한다. 일반적으로 3개 이상의 kafka 서버(Broker)로 구성되며, 이러한 구조를 통해 broker에 저장된 메시지를 다른 broker에게 공유하고 하나의 브로커에 문제가 생겼을 때, 다른 브로커로 그 역할을 대체해서 시스템을 정상적으로 유지시키는 방식으로 동작한다. 각각의 카프카 서버를 kafka broker라고 한다.

 

[브로커] 

카프카 서버를 의미한다. 

 

[Zookeeper]

'Zookeeper'는 분산 어플리케이션의 데이터 관리 기능을 가지고 있으며, 여러 개의 broker 들을 컨트롤해 주는 역할을 수행하기 때문에 zookeeper 없이 kafka가 동작할 수 없다는 특징이 있다. 즉, multi broker들 간의 정보 변경 공유 및 동기화 등을 수행한다.

 

[토픽]

카프카 클러스터에 데이터를 관리할 시 그 기준이 되는 개념이다. 토픽은 카프카 클러스터에서 여러개를 만들 수 있고 하나의 토픽은 1개 이상의 파티션으로 구성된다. 

 

[파티션] 

각 토픽 당 데이터를 분산 처리하는 단위이다. 카프카에서는 토픽 안에 파티션을 나누어 그 수대로 데이터를 분산처리한다. 카프 옵션에 지정한 replica의 수만큼 파티션이 각 서버들에게 복제된다. 

 

[리더, 팔로워]

카프카에서는 각 파티션당 복제된 파티션 중에서 하나의 리더가 선출된다. 이 리더는 모든 읽기, 쓰기 연산을 담당하게 된다. 리더를 제외한 나머지는 팔로워가 되고 이 팔로워들은 단순히 리더의 데이터를 복사하는 역할만 하게 된다. 

 

[컨슈머 그룹] 

컨슈머의 집합을 구성하는 단위이다. 카프카에서는 컨슈머 그룹으로서 데이터를 처리하며 컨슈머 그룹 안의 컨슈머 수만큼 파티션의 데이터를 분산처리하게 된다. 

 

 

위의 그림은 Foo, Bar를 토픽으로 가지며 각각 3개의 파티션으로 나누어져있다. 각 파티션들은 3개의 복제본으로 복제되며 그 중 하나의 리더가 선출되고 이 리더는 모든 데이터를 읽기, 쓰기 연산을 담당한다. 

여기서 중요한 것은 파티션들은 운영 도중 그 수를 늘릴 수 있지만 줄일 수 없다. 이 때문에 파티션을 늘리는 것은 신중하게 고려해서 결정해야될 문제가 있다. 

 

필자가 담당했던 로그 수집에서 토픽명을 'log'로 설정하였다. 이후 작업 프로세스인 로그 스태쉬가 해당 토픽으로의 메세지가 카프카에 담겨져서 전달된다면 이를 구독하여 데이터들을 엘라스틱서치에 저장하고 키바나로 시각화하였다. 

 

파티션 읽기, 쓰기

 

카프카에서의 쓰기, 읽기 연산은 카프카 클러스터 내의 리더 파티션들에게만 적용된다. 이 파티션들에게 프로듀서가 쓰기 연산을 진행한다. 쓰기 파티션 진행이 끝난 후 업데이트된 데이터들은 각 파티션들의 복제본들에게로 복사된다. 

 

 

 

 

프로듀서가 어떻게 write 연산을 하는지 설명하는 그림이다. 

위에서 언급했듯 카프카는 데이터를 순차적으로 디스크에 저장한다. 따라서 데이터 뒤에 붙이는 append 형식으로 write 연산을 진행한다. 이때 파티션들은 각각의 데이터들의 순차적인 집합인 오프셋(offset)으로 구성되어 있다. 

 

 

 

컨슈머그룹의 각 컨슈머들은 파티션의 오프셋을 기준으로 데이터를 순차적으로 처리하게 된다. 중요한 건 컨슈머들은 컨슈머 그룹으로 나뉘어서 데이터를 분산 처리하게 되고 같은 컨슈머 그룹 내에 있는 컨슈머끼리 같은 파티션의 데이터를 처리할 수 없다. 

 

파티션에 저장되어 있는 데이터들은 순차적으로 데이터가 저장되어 있으며 이 데이터들은 설정값에 따라 데이터를 디스크에 보관하게 된다. 

 

만약 컨슈머와 파티션의 개수가 같다면 컨슈머는 각 파티션을 1:1로 맡게 된다. 만일 컨슈머 그룹 안의 컨슈머의 개수가 파티션의 개수보다 적을 경우 컨슈머 중 하나가 남는 파티션의 데이터를 처리하게 된다. 만약 컨슈머의 개수가 파티션의 개수보다 많을 경우 남는 컨슈머는 파티션이 개수가 많아질 때까지 대기하게 된다. 

 

kafka는 consumer가 데이터를 가져가도 파티션에 있는 데이터가 삭제되지 않는다는 특징이 있기때문에 동일 데이터에 대해 여러 번 처리를 할 수 있으며, 이는 카프카를 사용하는 중요한 이유 중 하나이다.

(파티션에 저장된 데이터가 삭제되는 것은 옵션을 통해 설정할 수 있으며, 데이터가 저장되는 최대 시간과 크기를 지정할 수 있다.)

 

파티션을 늘리는 이유는 consumer의 개수를 늘려 데이터 처리를 분산시킬 수 있기 때문이다. 파티션을 늘리는 것은 가능하지만 다시 줄이는 것은 불가능하기 때문에 파티션을 늘릴 때는 주의해서 늘려야 한다는 특징이 있다. 

 

 

 

 

 

필자가 진행한 프로젝트에서 로그 수집을 위해 ELK-Stack을 활용했다고 언급한 적이 있다. 

Kafka 를 도입하는 많은 이유 중 하나는 트래픽이 몰리면 Logstash, Elasticsearch 만으로는 부하를 견디기 힘들다고한다

위에 언급한 것처럼 일반적으로 3개 이상의 kafka 서버를 활용해 브로커에게 공유를 하여 고가용성을 유지해야하지만 필자의 경우 소규모 시스템을 감안하여 기술 도입에 초점을 맞췄기때문에 위의 그림과 같은 아키텍처로 구성하였다. 

 

추후 다른 프로젝트를 진행하여 카프카를 구성한다면 최소 3대의 서버로 구성하여 가용성을 유지하는 것에 초점을 맞출 것이다. 

 

 

 

참고자료 

 

반응형

댓글