HomeBlogGuestbookLab 

JDM's Blog

온갖 테스트 결과가 기록되는 이곳은 JDM's Blog입니다. :3

아파치 주키퍼(Apache Zookeeper)

ZooKeeper, 우리나라말로는 "사육사" 정도입니다. 어떻게 이런 이름이 붙었을까요? 원래 주키퍼는 아파치 재단의 하둡 프로젝트 소속의 하위 프로젝트였습니다. 하둡(Hadoop) 생태계는 대부분 프로젝트명이 동물이름입니다. 그래서 이러한 동물 프로젝트(?)들을 관리하는 소프트웨어로 사육사, 즉 주키퍼(ZooKeeper)가 탄생했는데요. 좀 지나긴 했지만 주키퍼는 하둡에서 벗어나 독립된 상위 프로젝트가 되었지만 이름은 변경되지 않았습니다. 그래서 이번 포스팅은 이 주키퍼에 대해 알아보고자 합니다.

주키퍼란 무엇인가?(What is ZooKeeper?)

주키퍼는 환경 정보 유지보수, 이름 정의(naming), 분산 동기화 그리고 그룹 서비스 제공을 위한 집중화 서비스입니다. 모든 종류의 서비스는 분산 어플리케이션으로써 약간의 형태를 따르거나 또는 다르게 사용 될 수 있습니다. 그 서비스들은 매번 버그 또는 피할 수 없는 경쟁 상태를 고치기 위한 많은 작업이 구현됩니다. 이러한 서비스의 구현상 어려움 때문에, 어플리케이션들은 분산 처리에 대해 일반적으로는 날림으로 초기화합니다. 따라서 분산 처리 과정은 관리하기 위한 어려움과 상태의 변화로 부서지기 쉽게 만들어집니다. 심지어 분산 처리를 정확하게 완료했을 때라도, 어플리케이션들이 배포될때 분산 처리 구현체들이 다르다면 관리의 복잡성을 초래합니다. [출처] Apache Zookeeper - What is Zookeeper?

만들어진 배경은 상기 서술된 문단의 두번째 문장부터군요. 실제로 분산 처리를 위한 작업이 복잡하고 또한 구현하기의 어려움 때문에 분산 처리 어플리케이션에서 실제 분산에 대한 부분은 날림으로 만들어지고 결국엔 이것으로 문제가 많이 생긴다는 것으로 보입니다.

그렇다는 말은 주키퍼의 등장 배경엔 이러한 어려움을 제거하기 위한 용도로 만들어졌음을 짐작 할 수 있겠네요.

개요(OverView)

주키퍼의 간략한 등장 배경을 알아봤으니 이번엔 주키퍼의 내부가 어떤지 또 어떤 철학을 가지고 만들어졌는지 알아봅시다. 해당 절은 Apache Zookeeper - OverView의 내용을 의역했습니다.

주키퍼: 분산 어플리케이션을 위한 분산 관리 서비스(ZooKeeper: A Distributed Coordination Service for Distributed Applications)

주키퍼는 분산 어플리케이션들을 위한 오픈 소스 분산 관리 서비스입니다. 주키퍼의 간단한 기본형 집합만으로도 분산 어플리케이션들은 동기화, 환경 유지, 그룹 및 네이밍을 위한 높은 레벨의 서비스를 구현에 따라 빌드할 수 있습니다. 주키퍼는 파일 시스템에서 친숙한 디렉토리 트리 구조의 데이터 모델을 사용하고 프로그램 하기 쉽도록 설계 되었습니다. 또한 주키퍼는 Java 그리고 C언어는 바인딩을 통해 실행할 수 있습니다.

설계 목표(Design Goals)
  • 주키퍼는 간단합니다. 주키퍼는 표준 파일 시스템과 유사하게 만들어진 각각의 공유 계층적 네임스페이스를 통해 관리를 위한 분산 프로세스를 허용합니다. 네임 스페이스는 데이터 레지스터 - 주키퍼 내에선 znodes 라고 불립니다. - 로 구성하는데 파일 및 디렉토리와 유사합니다. 전형적인 파일 시스템과는 달리 저장공간(Storage)를 위해 설계되었습니다. 참고로 주키퍼 데이터는 메모리 상에서 유지합니다. 이러한 이유로 주키퍼는 높은 처리량과 낮은 지연률을 달성할 수 있습니다. 주키퍼 구현은 고성능, 고가용성, 엄격한 명령 접근에 프리미엄이 붙습니다. 주키퍼의 성능적인 측면은 거대한 분산 시스템에서 사용할 수 있다는 것입니다. 신뢰성 측면에서는 단일 지점 실패로부터 서비스를 유지하는 것입니다. 엄격한 명령은 정교한 동기화가 클라이언트에서 구현될 수 있다는 것입니다.
  • 주키퍼는 복제됩니다. 주키퍼에 관리 되는 분산 프로세스처럼 주키퍼 자체는 앙상블(ensemble)이라고 불리는 호스트(host)들의 집합에 복제됩니다. 주키퍼 서비스로 지정된 서버들은 반드시 서로에 대해 알고 있어야 합니다. 주키퍼 서비스는 상태의 메모리 이미지(an in-memory image of state)와 별도의 공간(persistent store, 데이터를 유지 가능한 저장공간)에 트랜잭션 로그와 스냅샷을 함께 유지합니다. 주키퍼 서버들의 과반수가 허용하는 한, 주키퍼 서비스는 지속됩니다. 클라이언드들은 단일 주키퍼 서버에 연결합니다. 클라이언트는 TCP 연결로 요청을 보내거나, 응답을 받고, 이벤트를 감시하며 하트비트(heartbeats)를 보내는 것을 통해 유지합니다. 만약 주키퍼 서버가 사용 불가한 상태가 되면 클라이언트의 TCP 연결은 다른 주키퍼 서버로 연결됩니다.
  • 주키퍼는 정렬됩니다. 주키퍼는 각각의 업데이트마다 숫자를 찍습니다. 이 숫자는 모든 주키퍼 트랜잭션 순서에 반영됩니다. 이후 동작은 동기화 같은 고수준 추상화를 구현하기 위해 사용할 수 있습니다.
  • 주키퍼는 빠릅니다. 주키퍼는 특별하게 "읽기 지배적인(read-dominant)" 워크로드에서 빠릅니다. 주키퍼 어플리케이션은 수천개의 기기상에서 실행합니다. 그리고 이것은 일반적으로 쓰기보다는 읽기에 적합한 수행을 합니다. 대략적으로 읽기/쓰기의 비율은 10:1 정도입니다.
데이터 모델과 계층적 네임스페이스(Data model and the hierarchical namespace)

주키퍼로써 제공된 네임 스페이스는 표준 파일 시스템의 그것과 비슷합니다. 이름(name)은 슬래쉬(/) 기호로 분할된 경로 요소의 순서입니다. 주키퍼의 네임 스페이스안에 모든 노드(node)들은 경로(path)로써 식별됩니다.

/
	/app1
		/p_1 <-- full Path Name is "/app1/p_1"
		/p_2
		/p_3
...
	/app2
...
* 위의 파란색 공간은 주키퍼 내의 계층적 네임스페이스를 표현했습니다.
노드와 임시 노드(Nodes and ephemeral nodes)

표준 파일 시스템과는 다르게, 주키퍼 네임스페이스 내부 각각의 노드는 자신뿐만 아니라 연관된 자식의 데이터를 가집니다. 이것은 파일 시스템에서 디렉토리가 파일을 가질 수 있는 것과 비슷합니다. (주키퍼는 관리 데이터를 저장하기 위해 설계 되었습니다 : 상태 정보, 환경 구성, 위치 정보, 기타 등, 또한 각각 노드는 일반적으로 작은 데이터를 저장. 이 작은 데이터의 크기는 바이트에서 킬로바이트 사이.) 우리는 주키퍼의 데이터 노드에 관하여 얘기할 때 이것을 명확하게 znode라는 용어로 사용합니다.

Znode(이하 "Z노드")는 데이터 변경, ACL 변경, 타임스탬프, 캐시 유효성과 관리된 업데이트를 허용하는 버전 숫자를 포함하는 상태 구조를 유지합니다. Z노드의 데이터 변경이 일어나는 시간마다 버전 숫자는 증가합니다. 예를 들면, 언제든지 클라이언트가 데이터를 검색하면 이것은 또한 데이터의 버전을 받습니다.

네임스페이스 내에서 각 Z노드의 저장된 데이터는 자동적으로 읽고 쓰여집니다. Z노드에서 연관된 모든 데이터를 읽고 전체 데이터를 교체해서 씁니다. 각 노드는 무엇을 할 수 있는지 제한할 수 있는 접근 제어 목록(ACL, Access Control List)을 가집니다.

주키퍼는 또한 임시 노드의 개념을 가집니다. 임시 Z노드들은 Z노드가 활성화되어 만들어진 세션이 있는 한 존재합니다. 세션을 종료 할 때 임시 Z노드는 삭제됩니다. 임시 노드는 당신이 [tbd] 구현을 할 때 유용합니다.

{=* [tbd]는 to be decided의 약어입니다. 일반적으로 "미결상태", "결정되어야 하는 것"등으로 해석합니다. 다른 약어로는 to be developed이 있는데 이것일 수도 있겠네요. 이건 해석하자면 "개발될 것"등으로 되지 않을까 합니다.

조건적 업데이트와 감시(Conditional updates and watches)

주키퍼는 감시의 개념으로 지원합니다. 클라이언트들은 Z노드 상에서 감시를 설정할 수 있습니다. 감시는 Z노드가 변경 될 때 트리거(triggered) 되거나 삭제 됩니다. 감시가 트리거 될 때 클라이언트는 Z노드가 변경되었다고 전송하는 패킷을 받을 수 있습니다. 그리고 만약 클라이언트와 하나의 주키퍼 서버와의 연결이 끊어지면 클라이언트는 로컬 알림(local notification)을 받을 것입니다. 이것들 또한 [tbd]로 사용할 수 있습니다.

보장(Guarantees)

주키퍼는 매우 빠르고 매우 간단합니다. 동기화 같은 더 복잡한 서비스의 기초가 될 것입니다. 주키퍼는 다음과 같은 내용을 제공합니다.

  • 순차적인 일관성 - 클라이언트로부터의 업데이트는 그들이 보내졌을 때 순서대로 적용됩니다.
  • 원자성 - 업데이트는 성공하거나 실패합니다. 그 외 부분적인 결과는 없습니다.
  • 단일 시스템 이미지 - 클라이언트는 서버와 연결이 되어 있는 동안 서비스를 같은 시각으로 볼 수 있을겁니다.
  • 신뢰성 - 한번 업데이트가 적용되면, 이것은 클라이언트가 업데이트를 덮어 쓰기 전까지 지속됩니다.
  • 적시성 - 시스템의 클라이언트 시각적 관점은 특정 시간 내에 처리 될 수 있도록 보장합니다.

마무리

주키퍼가 어떤것인지 알 수 있는 공부가 되었습니다. 이제 실제로 써보는 일만 남았군요(?). 사실 Hadoop 관련 작업을 하면서 곁다리로 끼어 있는 부분이라 자세히는 몰랐지만 이젠 어떤 관점으로 주키퍼를 바라봐야 할지 알 수 있게 되서 좋습니다. :)