욱'S 노트

ZooKeeper - 개요 본문

Programming/ZooKeeper

ZooKeeper - 개요

devsun 2015. 3. 12. 17:26

주키퍼는 분산 어플리케이션을 위한 오픈소스 분산 코디네이션 서비스이다. 주요기능은 단순한 세트로 제공한다. 분산 어플리케이션은 동기화, 설정 관리, 그룹핑 및 Naming를 위한 고수준의 서비스를 구현할 수 있다. 프로그래밍하기 쉽게 설게 되었으며, 데이터 모델은 file system의 디렉토리 트리 구조와 유사해서 친숙할 것이다. 또한 Java나 C 모두 바인딩이 쉽다. 


코디네이션 서비스는 정확성을 가지긴 매우 어렵다. 특히 race condition과 데드락 같은 에러가 발생하기 쉽다. 주키퍼의 목적은 코디네이션 서비스를 구현해야하는 분산 어플리케이션을 오류로부터 도와주는 것이다.


Design Goals


주키퍼는 단순하다. 주키퍼는 분산 프로세스들의 코디네이션을 허용한다. 공유되는 계층 네임스페이스는 단순 파일시스템처럼 구성한다. 네임스페이스는 znode라고 불리는  data 등록자들로 구성된다. 주키퍼의 용어는 파일과 디렉토리와 비슷하다. 일반적인 파일시스템과 다르게 Zookeeper 데이터는 메모리에 유지되어 고성능에 대기시간의 거의 없는 서비스가 가능하다. 주키퍼는 고성능, 신뢰성, 정확한 순서 처리에 장점이 있다. 주키퍼의 성능은 대용량 분산 시스템에서도 사용할 수 있다는 것을 의미한다. Single point of failure에도 신뢰성을 보장하며 엄격한 순서처리는 정교한 동기화처리 구현에 사용될 수 있다는 것을 의미한다.


주키퍼는 복제한다. 코디네이션을 원하는 분산 프로세스 처럼 주키퍼는 앙상블이라고 불리우는 호스트의 집합에 자기 자신을 복제할려고 한다.



주키퍼 서비스를 구성하는 서버는 서로 알아야 한다. 그들은 메모리에 상태 이미지를 유지하며, 트랜잭션 로그를 따라 퍼시스턴트 스토어에 스냅샷을 저장한다. 과반수의 서버가 유효하면 주키퍼 서비스는 유지된다. 클라이언트는 하나의 주키퍼 서버에 접속한다. 클라이언트는 TCP 연결을 유지하면서 요청을 전송하고 응답을 받고 watch event를 받고 heart beat를 전송한다. 만약 서버로의 TCP 연결이 끊기면 클라이언트는 다른 서버로 연결될 것이다.


주키퍼는 순차적이다. 주키퍼는 모든 주키퍼 트랜잭션을 순차적으로 반영한다. 이러한 기능은 synchronization primitive와 같은 고수준의 추상화 구현을 위해 이용될 수 있다.


주키퍼는 빠르다. 특히 읽기에 특화된 부하에 빠르다. 주키퍼 어플리케이션은 수천대의 머신에서 수행되었을 때 read와 write의 비율이 10:1일 때 최대 성능을 낼 수 있다.


Data model and the hierarchical namespace


주키퍼에서 제공되는 네임스페이스는 일반적인 파일 시스템과 매우 유사하다. 이름의 path element의 순서는 /로 구분된다. 주키퍼의 모든 노드는 패스로 식별할 수 있다.




Nodes and ephemeral nodes


표준 파일 시스템과는 다르게 주키퍼 네임스페이스의 각 노드는 자식뿐만 아니라 연관된 데이터를 가질 수 있다. 파일시스템에서 디렉토리가 파일을 가지고 있는 것과 비슷하다. 주키퍼는 코디네이션 데이터를 저장하도록 설계되었다. (상태 정보, 설정, 위치 정보 등 각 노드의 데이터는 일반적으로 바이트에서 킬로바이트 범위로 작다.) 주키퍼 데이터 노드를 znode라고 한다.


Znode는 캐쉬 검증 및 코디네이션 업데이트를 위해 데이터 변경, ACL 변경, 타임스탬프 등의 버젼 넘버 통계 구조를 유지한다.  Znode의 데이터가 변경될 떄 마다 버젼 넘버는 증가한다. 예를 들어 클라이언트에서 데이터를 조회할 때 마다 데이터의 버젼 정보 또한 전달 받게 된다. 


각 Znode에 저장된 데이터를 읽고 쓰는 것은 원자적이다. Znode와 연관된 모든 데이터를 읽고 모든 데이터를 변경할 수 있다. 각 노드는 접근 제어를 위한 ACL 정보를 가진다.


주키퍼는 ephemeral node를 가질 수 있다. 이러한 znode는 노드를 생성한 세션이 존대할 동안만 znode가 유효하다. 세션이 종료되면 znode는 지워진다. Ephemeral 노드는 구현시 유용하게 이용된다.

Conditional updates and watches


주키퍼는 watches 개념을 지원한다. 클라이언트는 znode에 watch를 설정할 수 있다. Watch는 znode가 변경될 떄 트리거되고 삭제될 것이다. Watch가 트리거되면 클라인언트는 znode가 변경된 사항을 전달받을 수 있다. 그리고 만약 클라이언트와 주키퍼 서버간의 연결이 끊어졌다면 클라이언트는 로컬 통지를 받게 될 것이다.

Guarantees


주키퍼는 매우 빠르고, 매우 심플하다. 하지만 동기화와 관련된 더욱 복잡한 서비스 구축을 기반으로 하기에 다음과 같은 사항을 보장한다.


  • Sequential Consistency - 클라이언트로부터 변경은 전송된 순서에 따라 적용된다.

  • Atomicity - 업데이트는 성공이 아니면 실패이다. 부분적인 결과는 없다.

  • Single System Image - 클라이언트는 연결된 서버와 상관없이 동일한 뷰를 제공받는다.

  • Reliability - 한번 업데이트가 적용되면 클라이언트에 의해 다른 변경이 일어나기전까지 유지된다.

  • Timeliness - 시스템의 클라이언트 뷰는 특정시간에 최신상태를 보장한다.


Simple API


주키퍼는 매우 간단한 프로그래밍 인터페이스를 제공한다.


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

delete - 노드를 삭제

exists - 위치에 노드가 존재하는지 테스트

get data - 노드로 부터 데이터를 읽음

set data - 노드에 데이터를 씀

get children - 자식노드 리스트를 조회

sync - 전파된 데이터를 기다림

Implementation


주키퍼 서비스의 하이레벨 컴포넌트는 아래와 같다.  Reqeust processor가 예외가 발생하면 각 서버는 각 컴포넌트의 복제본을 복제하여 주키퍼 서비스를 만든다.

복제된 데이터베이스는 모든 데이터 트리를 포함한 메모리상의 데이터베이스이다. 변경사항은 복구를 위해 디스크에 로깅된다.  그리고 메모리상의 데이터베이스에 적용되기 전에 디스크에 직렬화하여 기록된다. 


모든 주키퍼 서버는 클라이언트에 서비스 된다. 클라이언트는 하나의 서버에 접속하고 요청을 전송한다. 읽기 요청은 각 서버 데이터 베이스의 로컬 복제본을 통해 서비스 된다. 서비스의 상태를 변경하는 요청은 약속된 프로토콜로 처리된다.


클라이언트로 부터 모든 쓰기 요청은 약속된 프로토콜의 부분으로서 leader라고 불리는 하나의 서버로 전송된다. 나머지 주키퍼 서버는 follower라고 불리우며, 리더로 부터 메시지를 제공받고, 메시지 전송을 담당한다. 메시징 레이어는 리더가 죽을 경우 교체와  리더와 팔로워간 동기화를 담당한다.


주키퍼는 개별적인 원자적인 메시지 프로토콜을 사용한다. 메시징 레이어는 atomic하기 때문에 주키퍼는 로컬 복제본이 분리되지 않는 것을 보장한다. 리더가 쓰기 요청을 전송받으면 쓰기가 적용될 시스템의 상태를 계산하고 새로운 상태의 캡쳐를 트랜잭션으로 전송한다.


Uses


주키퍼의 프로그래밍 인터페이스는 단순하다. 하지만 당신은 주키퍼를 기반으로 고수준의 순차 작업을 구현할 수 있다. (synchronizations primitives, group membership, ownership)


Performance


주키퍼는 고성능을 목적으로 설계되었다. 이유는 주키퍼의 개발팀은 야후이다. 




주키퍼 읽기-쓰기 비율의 변화에 따른 처리량이다. 주키퍼의 처리량 그래프는 주키퍼 3.2를 듀얼 2Ghz Xeon 그리고 두개의 SATA 15K RPM drives에서 수행했을때의 결과이다. 하나의 드리이브는 전용 주키퍼 로그 장치로 사용된다. 스냅샷은 OS 드라이브에 의해 쓰여진 것이고. 쓰기와 읽이 요청은 !Kb이다. 서버는 주키퍼 앙상블의 사이즈를 의미하고 서버의 숫자는 서비스를 구성하는 숫자이다. 대략 30개의 서버가 클라인트를 시뮬레이션하기 위해 사용되었다. 

Reliability


주키퍼 서비스의 실패와 복구 시스템 소요시간을 보여주기 위한 내용이다.  주키퍼 서비스는 7대의 머신으로 구성하였다.


이 그래프의 중요한 점은 첫째 만약 팔로워 실패 및 복구가 빠르다면 주키퍼는 실패에도 불구하고 고성능처리량을 유지할 수 있다는 것이다. 하지만 더 중요한 것은 리더 선출 알고리즘이 시스템 복구를 충분히 빠르게 수행한다는 것이다. 주키퍼는 새로운 리더를 선출하는데 200ms 이하를 소요한다. 세번째로 팔로워가 복구되면 주키퍼는 다시 처리량을 증가시킬 수 있다는 것이다.

The ZooKeeper Project


주키퍼는 많은 산업의 어플리케이션에서 성공적으로 사용되고 있다. 야후에서 코디네이션 및 복구 서비스로 사용되고 있다.  또한 수천대의 토픽을 관리하는 확장성있는 publish-subscribe 시스템의 메시지 브로커로서 사용된다. 또한 실패 복구 서비스를 위한 crawler로서 사용되며, 야후의 광고 시스템에서도 사용된다.



'Programming > ZooKeeper' 카테고리의 다른 글

ZooKeeper - 시작하기  (0) 2015.03.12
Comments