[아파치 카프카 어플리케이션 프로그래밍] 3. 카프카의 기본 개념 정리 (브로커, 페이지 캐시, 리플리케이션, 컨슈머 그룹, 코디네이터, 주키퍼, 토픽, 레코드, 오프셋)

반응형
728x90
반응형

카프카 브로커

카프카 클라이언트와 데이터를 주고받기 위해 사용하는 주체이자, 데이터를 분산 저장하여 장애가 발생하더라도 안전하게 사용할 수 있도록 도와주는 애플리케이션이다.

하나의 서버에는 한 개의 카프카 브로커 프로세스가 실행된다.

데이터를 안전하게 보관하고 처리하기 위해 3개 이상의 브로커 서버를 1개의 클러스터로 묶어서 운영한다.

카프카 클러스터로 묶인 브로커들은 프로듀서가 보낸 데이터 를 안전하게 분산 저장하고 복제하는 역할을 수행한다.

 

 

카프카 브로커가 프로듀서로부터 데이터를 전달받았을때

프로듀서가 요청한 토픽의 파티션에 데이터를 저장하고, 컨슈머가 데이터를 요청하면 파티션에 저장된 데이터를 전달한다.

프로듀서로부터 전달된 데이터는 파일 시스템에 저장된다.

 

카프카는 메모리나 데이터베이스에 저장하지 않으며 따로 캐시 메모리도 사용하지 않는다.

파일 시스템에 저장하고, 페이지 캐시(page cache)를 사용하여 디스크 입출력 속도를 향상시킨다.

 

 

페이지 캐시

OS에서 파일 입출력의 성능 향상을 위해 만들어 놓은 메모리 영역이다.

한번 읽은 파일의 내용은 메모리의 페이지 캐시 영역에 저장되어, 추후 동일한 파일의 접근이 일어나면 디스크에서 읽지 않고 메모리에서 직접 읽는 방식이다.

JVM 위에서 동작하는 카프카 브로커가 페이지 캐시를 사용하지 않는다면 속도가 느려질 수 있다. 

 

 

데이터 복제(replication)

데이터 복제(replication)는 카프카를 장애 허용 시스템으로 동작하도록 하는 원동력이다.

복제의 이유는 클러스터로 묶인 브로커 중 일부에 장애가 발생하더라도 데이터를 유실하지 않고 안전하게 사용하기 위함이다.

 

카프카의 데이터 복제는 파티션 단위로 이루어진다.

토픽을 생성할때 파티션의 복제 개수(replication factor)도 같이 설정되는데, 직접 옵션을 선택하지 않으면 브로커에 설정된 옵션값으로 설정된다. 

 

복제개수의 최솟값 : 1(복제 없음)
복제 개수의 최댓값 : 브로커 개수

 

복제 개수가 3인 경우

브로커 0 브로커 1 브로커 2
토픽 토픽 토픽
파티션1
(리더)
파티션1
(팔로워)
파티션1
(팔로워)

 

복제된 파티션은 리더(leader)와 팔로워(follower)로 구성된다.

리더 : 프로듀서 또는 컨슈머와 직접 통신하는 파티션
팔로워 : 나머지 복제 데이터를 가지고 있는 파티션

 

복제(Repication) 과정

팔로워 파티션들은 리더 파티션의 오프셋을 확인하여 현재 자신이 가지고있는 오프셋과 차이가 나는 경우 리터 파티션으로부터 데이터를 가져와서 자신의 파티션에 저장한다.

파티션 복제로 인해 나머지 브로커에도 파티션의 데이터가 복제되므로 복제 개수만큼의 저장 용량이 증가한다.

그러나 복제를 통해 데이터를 안전하게 사용할 수 있으므로, 이러한 단점을 감수하고 복제를 수행한다. 

그러므로 운영시에 복제 개수를 2개 이상으로 정하는 것이 중요하다.

(데이터가 일부 유실되어도 무관하고 데이터 처리 속도가 중요하다면 1 또는 2로 설정한다.)

 

브로커 0 브로커 1 브로커 2
토픽 토픽 토픽
파티션1
(리더)
파티션1
(팔로워)
파티션1
(팔로워)

 

브로커 0번에 장애가 발생한다면?

브로커 0 브로커 1 브로커 2
토픽 토픽 토픽
파티션1
(리더)
파티션1
(리더)
파티션1
(팔로워)

리더 파티션은 더이상 사용할 수 없으므로 팔로워 파티션 중 하나가 리더 파티션의 지위를 넘겨받는다.

이를 통해 데이터가 유실되지 않고 컨슈머나 프로듀서와 데이터를 주고받도록 동작할 수 있다.

운영 시에는 데이터 종류마다 다른 복제 개수를 설정하고 상황에 따라서는 토픽마다 복제 개수를 다르게 설정하여 운영하기도 한다.

 

카프카의 리플리케이션 관리 포스팅 바로가기

https://devfunny.tistory.com/381?category=829528 

 

카프카의 리플리케이션 관리

들어가며 리플리케이션의 이해가 먼저 필요하다. devfunny.tistory.com/380?category=829528 카프카의 토픽과 파티션, 오프셋 토픽 카프카에서는 프로듀서가 전달하는 메시지를 '토픽'에 저장하고, 컨슈머

devfunny.tistory.com

 

 

컨트롤러 (Controller)

클러스터의 다수 브로커 중 한대가 컨트롤러의 역할을 한다.

컨트롤러는 다른 브로커들의 상태를 체크하고 브로커가 클러스터에서 빠지는 경우 해당 브로커에 존재하는 리더 파티션을 재분배한다.

만약 컨트롤러 역할을 하는 브로커에 장애가 생기면 다른 브로커가 컨트롤러 역할을 한다.

 

데이터 삭제

카프카는 다른 메시징 플랫폼과 다르게 컨슈머가 데이터를 가져가더라도 토픽의 데이터는 삭제되지 않는다.

또한, 컨슈머나 프로듀서가 데이터 삭제를 요청할 수도 없다.

오직 브로커만이 데이터를 삭제할 수 있다.

데이터 삭제는 파일 단위로도 이루어지는데 이 단위를 "로그 세그먼트(log segment)"라고 부른다.

이 세그먼트에서는 다수의 데이터가 들어있기 때문에 일반적인 데이터베이스처럼 특정 데이터를 선별해서 삭제할 수 없다.

 

 

 

컨슈머 오프셋 저장

컨슈머 그룹은 토픽이 특정 파티션으로부터 데이터를 가져가서 처리하고 이 파티션의 어느 레코드까지 가져갔는지 확인하기 위해 오프셋을 커밋한다. 

커밋한 오프셋은 _consumer_offets 토픽에 저장된다.

여기에 저장된 오프셋을 토대로 컨슈머 그룹은 다음 레코드를 가져가서 처리한다.

 

컨슈머 그룹

https://devfunny.tistory.com/382?category=829528 

 

카프카의 컨슈머 그룹

컨슈머 그룹 카프카에는 프로듀서가 전달한 데이터를 저장하는 데이터 저장소인 토픽이 있다. 컨슈머는 해당 토픽에서 데이터를 가져오는데, 여러 컨슈머들은 컨슈머 그룹을 이루어 동시에 접

devfunny.tistory.com

 

 

코디네이터(coordinator)

클러스터의 다수 브로커 중 한대는 코디네이터의 역할을 수행한다. 

코디네이터는 컨슈머 그룹의 상태를 체크하고 파티션을 컨슈머와 매칭되도록 분배하는 역할을 한다.

 

리밸런스(rebalance) 수행

파티션을 컨슈머로 재할당하는 과정이다.

컨슈머가 컨슈머 그룹에서 빠지면 매칭되지 않은 파티션을 정상 동작하는 컨슈머로 할당하여 끊임없이 데이터가 처리되도록한다.

 

 

 

주키퍼가 하는 역할은 무엇일까?

주키퍼는 분산 코디네이션 서비스를 제공해준다. 카프카의 클러스터 설정 리더 정보, 컨트롤러 정보를 담고있어 카프카를 실행하는데에 필요한 필수 어플리케이션이다.

주키퍼는 카프카의 메타데이터를 관리하는 데에 사용된다.

 

https://jace.link/open/kafka

 

카프카 클러스터로 묶인 브로커들은 동일한 경로의 주키퍼 경로로 선언해야 같은 카프카 브로커 묶음이 된다.

만약 클러스터를 여러 개로 운영한다면 한개의 주키퍼에 다수의 카프카 클러스터를 연결해서 사용할 수도 있다.

 

 

 

토픽

카프카에서 데이터를 구분하기 위해 사용하는 단위이다.

토픽은 1개 이상의 파티션을 소유하고 있다. 

파티션에는 프로듀서가 보낸 데이터들이 들어가 저장되는데, 이 데이터를 '레코드(record)'라고 한다.

 

https://velog.io/@ehdrms2034/Kafka-3%EC%9E%A5-%EC%B9%B4%ED%94%84%EC%B9%B4-%EA%B8%B0%EB%B3%B8-%EA%B0%9C%EB%85%90-%EC%84%A4%EB%AA%85-1

 

프로듀서가 전송한 레코드는 파디션에 저장된다.

 

파티션은 카프카의 병렬처리의 핵심이다.

그룹으로 묶인 컨슈머들이 레코드를 병렬로 처리할 수 있도록 매칭된다.

컨슈머의 처리량이 한정된 상황에서 많은 레코드를 병렬로 처리하는 가장 좋은 방법은 컨슈머의 개수를 늘려 스케일 아웃하는 것이다.

컨슈머 개수를 늘림과 동시에 파티션 개수도 늘리면 처리량이 증가하는 효과를 볼 수 있다.

 

파티션은 자료구조에서 접히는 큐(queue)와 비슷한 구조라고 생각하자.

First-In-First-out 구조와 같이, 먼저 들어간 레코드는 컨슈머가 먼저 가져가게 된다.

다른점은 카프카에서는 데이터를 가져가고(pop) 삭제하지 않는다.

파티션의 레코드는 컨슈머가 가져가는 것과는 별개로 관리되기 때문에, 토픽의 레코드는 여러 컨슈머 그룹들이 토픽의 데이터를 여러번 가져갈 수 있다.

 

 

레코드

https://1ambda.blog/2021/12/29/practical-kafka-1/

레코드는 타임스탬프, 메시지, 키, 메시지 값, 오프셋, 헤더로 구성되어 있다.

프로듀서가 생성한 레코드가 브로커로 전송되면 오프셋과 타임스탬프가 지정되어 저장된다.

브로커에 한번 적재된 레코드는 수정할 수 없고 로그 리텐션 기간 또는 용량에 따라서만 삭제된다.

 

타임스탬프

프로듀서에서 해당 레코드가 생성된 시점(CreateTime)의 유닉스 타임이 설정된다.

 

컨슈머는 레코드의 타임스탬프를 토대로 레코드가 언제 생성되었는지 알 수 있다. 

메시지 키는 메시지 값을 순서대로 처리하거나 메시지 값의 종류를 나타내기 위해 사용한다. 

메시지 키를 사용하면 프로듀서가 토픽에 레코드를 전송할때 메시지 키의 해시값을 토대로 파티션을 지정하게 된다. 

즉, 동일한 메시지 키라면 동일 파티션에 들어가는 것이다.

다만 어느 파티션에 지정될지 알 수 없고, 파티션 개수가 변경되면 메시지 키와 파티션 매칭이 달라지므로 주의해야한다.

메시지 키를 설정하지 않을 수도 있다. (null)

메시지 키가 null로 설정된 레코드는 프로듀서 기본 설정 파티셔너에 따라서 파티션에 분배되어 적재된다. 

 

메시지 키와 메시지 값은 직렬화되어 브로커가 전송되기 때문에 컨슈머가 이용할때는 직렬화한 형태와 동일한 형태로 역직렬화를 수행해야한다. 

예를들어, 프로듀서가 StringSerializer로 직렬화한 메시지 값을 컨슈머가 IntegerDesrializer로 역직렬화하면 정상적인 데이터를 얻을 수 없다.

 

레코드의 오프셋은 0 이상의 숫자로 이루어져있다.

레코드의 오프셋은 직접 지정할 수 없고 브로커에 저장될 때 이전에 전송된 레코드의 오프셋 +1 값으로 생성된다. 

오프셋은 카프카 컨슈머가 데이터를 가져갈때 사용된다.

오프셋을 사용하면 컨슈머 그룹으로 이루어진 카프카 컨슈머들이 파티션의 데이터를 어디까지 가져갔는지 명확히 지정할 수 있다.

 

카프카의 토픽, 파티션, 오프셋

https://devfunny.tistory.com/380?category=829528 

 

카프카의 토픽과 파티션, 오프셋

토픽 카프카에서는 프로듀서가 전달하는 메시지를 '토픽'에 저장하고, 컨슈머가 해당 '토픽'에서 메시지를 가져온다고 하였다. 메시지의 저장소 역할을 하는 토픽은 데이터베이스의 '테이블'의

devfunny.tistory.com

https://devfunny.tistory.com/383?category=829528 

 

카프카의 오프셋과 커밋

들어가며 컨슈머가 poll()을 호출할 때마다 컨슈머 그룹은 카프카에 저장되어있는 아직 읽지않은 메시지를 가져온다. 이렇게 동작할 수 있는 것은 컨슈머 그룹이 메시지를 어디까지 가져왔는지

devfunny.tistory.com

 

 

반응형

Designed by JB FACTORY