dist. system

Zookeeper 컨셉 정리

식피두 2020. 10. 26. 14:41

'하둡완벽가이드(한빛미디어)' 및 아래 링크 글을 참조하여 정리해보았다.

 

분산 코디네이터 Zookeeper(주키퍼) 소개

ZooKeeper란 무엇인가? 조대협 (http://bcho.tistory.com) 소개 분산 시스템을 설계 하다보면, 가장 문제점 중의 하나가 분산된 시스템간의 정보를 어떻게 공유할것이고, 클러스터에 있는 서버들의 상태를

bcho.tistory.com

 

ZooKeeper: Because Coordinating Distributed Systems is a Zoo

 

[ZooKeeper] (1) ZNode - ZooKeeper가 data를 저장하는 방법.

What is a znode in ZooKeeper

blog.seulgi.kim

 

주키퍼의 역할 및 특성

1. 분산 시스템 간의 정보 공유역할을 하며, solr cloud가 zookeeper를 이용하는 것 처럼 클러스터의 공통 config를 저장하는 용도로도 자주 쓴다.

2. Ephemeral Node를 이용한 서버 상태 체크 용도.

3. 동기화 및 락(Lock)

4. 디렉터리 구조 기반의 데이터 모델 제공 (znode ; data-register ; key-value store), 해당 객체에 데이터를 넣고 빼는 것이 주키퍼의 핵심 중 하나다. 디스크에 저장되는 파일시스템 같은 '디렉터리 구조'로 되어있지만, znode는 in-memory에 저장 된다.

5. 주키퍼의 모든 트랜잭션엔 '순서 정보'까지 같이 저장 된다.

6. read/write 비율이 10:1 정도가 될 때 Best Performance를 제공한다.

 

* 주키퍼를 이용해 그룹 멤버십 애플리케이션을 구현할 수 있는데,

/lang 이라는 그룹을 정의하고

/lang/python, /lang/java, /lang/c 등과 같이 계층적인 네임스페이스/노드를 만든 뒤

각 노드에는 호스트명이나 IP주소와 같이 필요한 데이터를 저장하면 된다.

레플리케이션

앙상블로 불리며, 여러 서버를 이용해 클러스터 구성이 가능하다.

주키퍼 서버 끼리는 서로 알고 있어야 하고, in-memory에 데이터를 저장하며,

트랜잭션 로그나 스냅션은 디스크에 저장한다.

 

클라이언트

클라이언트는 하나의 주키퍼로 연결된 이후에,

TCP 커넥션을 유지하면서

요청/응답 및 watch event을 받으며 heart-beat을 보낸다.

커넥션이 끊길 경우 다른 서버로 연결한다.

 

주키퍼 서버에 연결되면 서버는 클라이언트를 위한 '세션'을 생성하는데,

세션 타임 아웃 값은 클라이언트 측에서 설정한다.

서버가 타임아웃 기간 내에 응답을 받지 못하면 세션은 만료된다.

 

클라이언트는 특정 시간 이상 세션이 일하지 않는 상태가 되면,

그 때마다 ping(heartbeat)을 보내서 세션을 유지한다. (라이브러리가 알아서 해줌)

이 때, ping은 세션 타임 아웃 기간보다 충분히 낮게 설정하여,

서버 장애 발생시 다른 서버로 빠르게 재접속할 수 있게 해야 한다.

 

서버 장애 발생시 클라이언트가 자동으로 다른 주키퍼로 연결을 재시도한다.

(앙상블을 구성하는 서버리스트 필요)

물론 서버 이동을 했을 때, 세션을 유효하다.

단, 이동하는 도중에는 클라이언트의 작업 수행시 실패.

 

주키퍼의 데이터모델, 지노드 ; znode

주키퍼의 네임스페이스(ex. /a/b/c)는 데이터를 가질 수 있다.

znode는 계층적 트리 형태를 가지며, 파일 역할과 디렉터리 역할을 동시에 한다.

 

znode는 몇 가지 메타정보를 유지한다.

1. 버전 넘버를 데이터 업데이트 마다 변경 (클라이언트의 데이터 read시 버전 정보도 함께 전달)

2. 연관된 ACL(Access Control List)를 유지

3. 타임스탬프 유지 (캐시 유효성 체크 등을 위해)

 

주키퍼는 분산 시스템의 코디네이션용이므로,

대용량 데이터 저장을 염두해 두고 있지 않다.

따라서, 한 노드는 1MB 정도의 크기로 제한되어 있다. 

 

데이터 접근이 원자성(atomicity)를 가진다.

읽을 때 데이터 일부만 받을 수 없고, 전체를 못받는 다면 실패다.

쓰기도 마찬가지로 관련된 모든 데이터를 갱신해야만 성공.

 

znode의 종류

1. Persistent ; 영구 저장

2. Ephemeral ; 생성 요청을 한 클라이언트의 세션이 연결되어 있을 경우에만 유효

 

순차 번호(Sequential Number)를 통해 자동으로 증가하는 번호가 노드 이름 뒤에 붙는다.

znode의 uniqueness를 보장한다.

전체 이벤트를 정렬하거나, 클라이언트가 순서를 알고 싶을 때 사용한다.

(공유 락 서비스 구현이 가능)

 

Watcher (Conditional Updates)

클라이언트는 특정 znode에 watch를 걸어 놓고,

데이터 변경에 대한 콜백을 받을 수 있다. (동시에 watcher는 삭제 됨)

이는 단 한 번만 동작하고, 원할 경우 다시 등록해야한다.

 

주키퍼가 보장하는 것

1. 순서의 일관성 (Sequential Consistency)

2. 원자성(Atomicity) ; 업데이트(들)은 성공 아니면 실패

3. 하나의 시스템 이미지(Single System Image) ; 어떤 서버에 연결되든 같은 뷰를 가짐

4. 신뢰성(Reliablity) ; 하나의 업데이트가 반영되면, 다음 업데이트까지 유지함

5. 적시성(Timelisness) ; 항상 최신의 데이터를 보장함

 

몇 가지 API 리스트

- create ; 트리의 특정 위치에 노드 생성

- delete

- exists ; 존재 유무 체크

- getACL, setACL ; ACL 관련 설정 및 읽기

- getData, setData ; 노드로 부터 데이터 읽기 및 쓰기

- getChildren ; 노드의 자식 리스트 조회

- sync ; 데이터가 전파되길 기다림, znode 클라이언트 뷰와 주키퍼를 동기화 시킴

 

* 주키퍼의 업데이트 연산은 조건부. delete, setData시 znode의 버전 숫자(exists를 통해 알아낸)를 지정해야함.

버전 일치 하지 않을 경우 연산 실패, 그리고 업데이트 연산은 논블로킹!

* 하나의 쓰기 연산 성공은 전체 주키퍼 서버 중 과반수의 서버에 위치한 persistent storage로 쓰기가 완료되었음을 보장함!

* 다중 갱신(multi)도 가능. 여러 연산을 하나의 배치로 묶어 전체 연산의 성공/실패 가능. 예를 들어, 두 노드를 반드시 동시에 업데이트해야하는 그래프 노드의 경우가 그렇다.

* 몇 가지 읽기 연산에 watcher 설정이 가능

- exists에 설정할 경우: 대상 znode가 생성/삭제/업데이트 되는 경우 작동

- getData에 설정할 경우: 대상 znode가 삭제/업데이트 시 신호 받음

- getChildren에 설정할 경우: 대상 znode의 자식이 생성/삭제, 아니면 자신이 삭제될 때 작동.