1. 쿠버네티스란?

  • 컨테이너화 된 워크로드와 서비스를 관리하기 위한 플랫폼. 

2. 쿠버네티스가 유용하게 된 히스토리

  • 물리 배포 시대에는 리소스 할당이 어려웠음. 하나의 물리 서버에 여러 개의 애플리케이션이 돌아갈 경우 한 애플리케이션이 모든 리소스를 할당해 가져갈 수도 있었고 이를 격리하기에는 물리 격리가 필요했음.
  • 이를 해결하기 위해 VM을 도입함. VM간의 격리를 두고 폐기 가능하도록 했다.

3. 컨테이너와 VM의 차이는?

  • VM이 좀 더 격리 수준이 높음. 컨테이너는 운영체제를 공유한다. 그렇기에 VM보다 좀 더 가볍다.
  • 배포 시점이 아닌 빌드해서 배포할 수 있고 빠르고 효율적으로 롤백할 수 있다.

4. 쿠버네티스가 그래서 왜 필요한가?

  • 컨테이너화 된 워크로드를 확장성있게, 중단 없이 운영하기 위한 많은 기능들을 제공하기 때문임.

5. 어떤 기능?

  • 자동 복구 : 실패한 컨테이너를 다시 시작
  • 롤아웃, 롤백
  • 스토리지 오케스트레이션
  • 서비스 디스커버리, 로드밸런싱
  • 스크릿과 구성 관리

6. 쿠버네티스의 구성 요소

  • 노드 : 컨테이너화 된 애플리케이션을 실행하는 것을 노드. 워커 머신의 집합.
  • 파드 : 노드는 애플리케이션의 구성요소인 파드를 호스팅함.
  • 컨트롤 플래인 : 워커 노드와 클러스터 내 파드를 관리한다. 

6-1. 컨트롤 플레인

  • 클러스터에 관한 전반적인 결정(스케줄링 등)을 수행. 클러스터 이벤트를 감지하고 반응(ex. Replicas 맞추기)
  • 어디서든 동작 가능하지만, 보통 사용자 컨테이너와 분리하여 동작시킨다.(간결성을 위하여)

6-1.-1. 컨트롤 플레인의 컴포넌트들

  • Kube-apiserver
  • Etcd : 모든 클러스터 데이터를 담는 쿠버네티스 뒷단의 저장소. 
  • Kube-scehduler : 노드가 배정되지 않은 파드를 감지, 실행할 노드를 선택하는 컨트롤 플래인 컴포넌트
    • 노드 컨트롤러, 컨트롤러, 엔드포인트 컨트롤러, 서비스 어카운트 & 토큰 컨트롤러
  • Kube-controller-manager : 컨트롤러 프로세스를 실행하는 컴포넌트.
  • Cloud-controller-manager
    • 노드 컨트롤러, 라우트 컨트롤러, 서비스 컨트롤러의 컴포넌트를 가지고 있음.

6-2. 노드 컴포넌트

  • 노드컴포넌트는 동작중인 파드를 유지시키고, 런타임 환경을 제공하며 모든 노드상에서 동작한다.

6-2-1. 노드의 컴포넌트들

  • Kubelet: 파드에서 컨테이너가 확실하게 동작하도록 관리한다.
  • Kube-proxy : 네트워크 프록시로, 쿠버네티스 서비스 개념의 구현부.
  • 컨테이너 런타임: 컨테이너 런타임은 컨테이너 실행을 담당하는 소프트웨어

6-3. 애드온

  • 리소스를 이용하여 클러스터 기능을 구현. 클러스터 단위 기능을 제공하기에 kube-system 네임스페이스에 속한다.
  • DNS, 웹 UI, 컨테이너 리소스 모니터링, 클러스터-레벨 로깅

7. 쿠버네티스 오브젝트 (핵심 개념)

  • 쿠버네티스 오브젝트는 시스템에서 영속성을 가지는 오브젝트. 클러스터의 상태를 나타내기 위해 이 오브젝트를 이용한다.
  • 상태?
    • 어떤 애플리케이션이 동작중이고 어느 노드에서 동작 중인지
    • 애플리케이션이 이용할 수 있는 리소스
    • 재구동 정책, 업그레이드 등 동작 정책
  • 결국 쿠버네티스 오브젝트는 의도를 가진 레코드라고 할 수 있다. 
  • 생성 방식?
    • 오브젝트를 생성하기 위해서는 컨트롤플레인의 쿠버네티스 API를 사용해야 함. 주로 Kubectl cli를 통해 api를 대신 호출한다.

8. 오브젝트 명세(Spec)와 상태(Status)

  • 거의 모든 쿠버네티스 오브젝트는 spec과 status를 가진다. 
  • spec을 통해 의도하는 상태를 기술하여 쿠버네티스에 전달하면 해당 오브젝트의 status라는 개념이 생기고 이는 쿠버네티스 시스템에 의해 제공된다.
  • 의도된 spec과 현재 status를 일치시키기 위해 능동적으로 관리한다.

9. 오브젝트 기술 방법

  • 쿠버네티스 API를 활용하기 위해서는 JSON 형식으로 정보를 포함시켜 줘야 한다. (대부분은 kubectl을 활용하여 yaml로 기술하여 제공한다, 이를 kubectl이 JSON형태로 변환하여 전달해 준다.)
  • 요구되는 필드
    • apiVersion : 오브젝트를 생성하기 위해 사용되고 있는 쿠버네티스 API 버전이 어떤 것인지
    • Kind: 어떤 종류의 오브젝트를 생성하려고 하는지
    • Metadata: 이름 문자열, UID, 선택적인 namespace를 포함하여 오브젝트를 유일하게 구분 지어줄 데이터
    • spec: 오브젝트에 대해 어떤 상태를 의도하는지

'Developer > Architecture, Cloud' 카테고리의 다른 글

Kafka 학습  (1) 2022.12.11

 토픽이란?

 하나의 데이터 스트림이라 볼 수 있음. 어떤 형태의 데이터도 가능하다.(json, binary, text 등). 토픽은 파티션으로 나뉜다. 각 토픽 파티션에는 오프셋이 증가하면서 데이터가 쌓인다. 데이터는 일정시간만 유지된다.(기본은 1주일). 파티션내에서만 순서가 보장된다. 오프셋은 데이터가 삭제된다하더라도 변경되지 않는다.

 프로듀서가 메시지와 메시지의 키를 정의해서 토픽으로 메시지를 보낸다. 키가 없을 경우에는 라운드로빈으로 보낸다. 키가 존재하면 해싱해서 보낸다. 동일한 키는 항상 동일한 파티션으로 가게 된다. 

 메시지의 기본 구성 요소는 헤더, 키, 메시지, 압축방식, 파티션과 오프셋, 타임스탬프 로 구성된다. 메시지 직렬화를 통해 키와 밸류값을 바이너리 값으로 변경해준다. 

 카프카 파티셔너의 기본 해싱 알고리즘은 murmur2 algorithm이다. 파티션의 수가 바뀌면 바뀐다.

컨슈머

카프카의 컨슈머는 기본적으로 pull model이다. 카프카의 deserializer가 키와 밸류값을 역직렬화한다. 이 프로듀서에서의 직렬화와 컨슈머에서의 역직렬화의 타입을 토픽내에서는 변경하면 안된다.

 모든 컨슈머는 컨슈머그룹으로써 데이터를 읽는다. 컨슈머가 파티션보다 많을 경우 파티션 개수만큼만 동작한다. 당연히 여러 컨슈머그룹이 하나의 토픽을 읽을 수 있다.

 카프카에서는 __consumer_offsets라는 토픽에 컨슈머그룹이 어떤 offset까지 읽었는지 저장하고 있다. 오프셋을 커밋치면 다음것을 읽도록 한다. 이 커밋전략은 기본적으로는 자동인데 3개의 선택지가 존재한다. 

1. At leat Once(usually preferred)
- 메시지가 처리된 후에 커밋, 오류가 날 경우 다시 읽도록 함.
- 이 경우 메시지를 다시 처리해도 동일한 결과가 나오도록 해야 함( idempotent )

2. At most once
- 메시지를 받자마자 커밋을 친다.
- 오류가 날 경우 메시지 손실이 날 수 있다.

3. Exactly Once
- 카프카 스트림즈 API를 활용하는 것처럼 완벽히 한번만 실행되도록 한다. - 아직 정확히 이해가 안된다.

autocommit을 Enable할 경우 Interval이 지난 후에 poll을 할 경우 commit을 하는 구조. 다음 Poll까지는 이번 배치의 Processing을 끝내줘야함. 

offset을 가지고 있는 주기는 설정 가능하다. 2.0미만버전은 하루 리셋이 기본 그 이상은 7일이다.

컨슈머 설정 값

- heartbeat.interval.ms 몇초에 한번씩 보낼지
- session.timeout.ms : heartbeat가 몇초동안 오지 않으면 해당 컨슈머를 죽였다고 판정하고 리밸런싱할지
- Max.poll.interval.ms: 두 폴 사이의 Interval의 최대시간을 얼마로 기다려줄지, 이 시간이 지나면 컨슈머 죽었다고 판단
- max.poll.records : 한번에 몇개나 받을지
- fetch.min.bytes: 최소 몇 바이트까지 기다릴건지 fetch.max.wait.ms가 도달하면 어쨌든 가져온다.
- max.partition.fetch.bytes: 서버가 돌려주는 파티션별 maximum byte. fetch.max.bytes로 제한된다.

 

카프카 브로커

- ID로 정해지며 어떤 브로커로 연결되든지 모든 클러스터에 연결된다. 
- Topic-A 3 파티션, Topic B 2 Partition이 있다고 가정하자.
- 카프카 브로커들은 bootstrap server로 불리기도 한다. 카프카 클라이언트가 하나의 브로커(부트스트랩 서버)에 연결하고 메타데이터를 요청하면 모든 브로커들의 리스트를 제공한다. 

토픽 레플리케이션

- 두개 이상의 레플리케이션 팩터를 사용한다. 주로 2~3. 브로커가 오류가 생길경우 데이터를 서빙할 수 있게끔.
- 파티션의 리더 : 하나의 브로커가 하나의 파티션에 리더이다. 프로듀서는 파티션의 리더에게만 데이터를 서빙한다. 마찬가지로 컨슈머도 파티션의 리더에게서 데이터를 읽어간다. 하지만 2.4버전 이후부터는 컨슈머는 ISR중 하나에서 읽을 수 있도록 됨. 
- 파티션 리더가 데이터를 받으면 다른 브로커가 그 데이터를 복사해간다. multiple ISR(In-Sync-Replica)

Producer Acknowledgements & Topic Durability

- acks = 0 : 프로듀서가 보내고 끝 (metric 모으는등의 곳에 쓰이면 쓰루풋에 좋음)
- acks = 1 : 프로듀서가 파티션 리더가 데이터를 썼는지 기다림 (리턴값을 기다림)
- acks = all : 프로듀서가 모든 레플리카에 다 동기화 됐는지 기다림 ( acks = -1 )
- Topic Durability : replica가 3이면 2개의 브로커 로스까지는 버틸 수 있음
- 딥하게 들어가면 min.insync.replicas 값이 있는데, 이건 최소 레플리카의 개수를 뜻한다. 최소 3개의 레플리카를 원한다면 이 값을 2로 해야한다. 흔한 설정값은 RF=3일 경우 min.insync.replicas를 2로 두는 것이다. 하나의 브로커가 down되어도 가능하도록.

 

 

Zookeeper

- 2.x 버전은 주키퍼가 필수, 3.x 버전은 kafka raft(kraft)를 사용(주키퍼 없이도 사용가능), 4.x 버전은 주키퍼 없이 사용
- zookeeper는 브로커들을 매니징하고, 파티션 리더를 뽑는 도움을 줬(었)다.
- 주키퍼 서버는 홀수로 동작하도록 되어있음.
- 4.0버전 전에 production-ready가 되려면 주키퍼를 사용해야함. 운영이 아니라면 주키퍼 없이 동작은 가능함.
- 카프카 클라이언트입장에서는 이젠 주키퍼에 연결할 일이 없음. 
- 주키퍼는 카프카 클라이언트에서 연결됐을 경우 안전하지 않다.( Not secure )
- 주키퍼는 10만 파티션이상일 경우 스케일링 이슈가 있었음
- 주키퍼를 제거함으로써 더 쉽게 모니터링할 수 있고 하나의 시큐리티만 신경쓰면 되고( 클라이언트가 주키퍼를 연결하지 않으므로 ). 시작과 컨트롤러 셧다운 리커버리 타임이 짧다.

Sticky Partitioner

- key값이 존재하지 않고 produce를 빠르게 하고 있을 경우에 퍼포먼스 증가를 위하여 같은 파티션내에 넣어준다. 

리밸런싱 과정

- 컨슈머그룹에 새로운 컨슈머가 들어오거나 나갔을 경우 어떤 파티션을 어떤 컨슈머가 컨슘할것인지 다시 결정하는 과정. 기본적으로는 Eager Rebalance로 Stop-the-world 이벤트가 발생하고 모든 파티션을 다시 재 지정해준다.
- Cooperative Rebalance는 비교적 최근 리밸런싱 과정인데 모두 멈추고 다시 하는것이 아니라 일부만 재 배정해주기 위해 멈춘다.

AutoCommit Interval

- 자바로 따지면 auto.commit.interval.ms = 5000일 경우 5초에 한번씩 커밋을 치는 것이라 보면 된다.
 - 동작 과정은 한번의 poll에 3초씩 걸릴 경우, 1poll, 2poll 후에 6초가 지나게 되는데 이 후에 동작하는 것이라 보면 된다. (5초라고 해서 6초 이전에 갑자기 동작하는 것이 아니다) 어떤 poll 후에 동작할지?를 정하면 된다.


Producer Retries

- kafka 2.0 이하일경우 retry 0 이 default, 이상일경우에는 2147483647이라는 높은 값이 설정된다. 하지만, delivery.timeout.ms 라는 설정값보다 오래 retry 하지 않는다.
-  retry.backoff.ms 설정값은 다음 리트라이를 몇 ms 이후에 할 것인지를 결정한다. 
- 이 리트라이 설정은 key ordering에 의존할 경우 문제가 될 수 있는데 - (producer는 정상적으로 kafka에 데이터를 보냈으나, ack을 받는 도중에 네트워크 에러가 생겼다. 프로듀서는 다시 리트라이를 하게 돼서 중복되는 메시지를 보내게 된다.) 의 경우에 그렇다.
- 이런걸 방지할 수 있는게 Idemptoent Producer이다. Duplicate 메시지를 발견하고 두번 보내지 않도록 해준다. (3.0부터 default임) 
  

Producer Message Compression

- snappy, ztsd 등의 압축을 적용하여 kafka에 보낼 수 있다.
- 장점 : 작아서 높은 throughput, kafka 용량 줄어듦
- 단점 : compress, decompress에 cpu 사이클이 들어감
- linger.ms batch.size를 조절하여 큰 배치를 진행하고 높은 처리량을 갖도록 한다.
- 브로커레벨에서의 compression도 가능하다.
- 프로듀서가 압축을해서 보낼경우 컨슈머에서 압축을 풀어줘야한다.(당연히)

 

 

Linger.ms & batch.size 등 프로듀서의 배치에 대해

  • 기본적으로 카프카 프로듀서는 레코드를 asap 보내는데, 많은 메시지가 한번에 나갈 경우 배치 프로세스를 통해 보낸다.
  • linger.ms 설정값은 보내기전에 얼마나 기다릴 것인지 결정한다. 이 값을 줄 경우 ex(5ms)를 줄경우 많은 메시지를 배치하게 된다.
  • batch.size 정하고 어떤 메시지가 이상일경우 바로 보낸다. 값은 최대치를 정하는 거다. 
  • 프로듀서가 높은 스루풋을 가질 경우 브로커가 속도를 못 따라가면 레코드는 메모리 버퍼안에 들어간다. 이 경우 async로 보내지 않고 블록을 하게 되는데 그 블록하는 시간이 max.block.ms이다.

 

 

 

 

+ Recent posts