반응형

[주키퍼, Zookeeper] 아파치 주키퍼(Apache Zookeeper) 소개 및 아키텍처

반응형

| 대규모 분산 시스템과 코디네이션 시스템의 필요성?

 

과거에는 한 대의 컴퓨터에서 동작하는 단일 프로그램이 대다수였지만, 현재 빅데이터와 클라우드 환경에서 대규모의 시스템들이 동작하고 있습니다. 이 대규모 시스템은 수많은 서버와 인프라로 구성되어 있죠. 또한 이 시스템들은 보통 다양하고 수많은 어플리케이션들로 이루어져 있습니다.

 

결국 이 개별적인 시스템들을 각각 조율해야하는 코디네이션 시스템의 수요가 생기게 되었습니다. 하지만 이 코디네이션 시스템을 작성하는 것은 아주 까다롭고 복잡한 과정이었습니다. 분산 코디네이션 시스템을 구축하기 위해 들인 노력에 비해 정작 중요한 핵심 로직을 작성하는 시간은 부족하였기 때문에 분산 코디네이션 시스템을 대강 만들게 되거나 아니면 필요한 로직에 집중하지 못하게 된 경우가 많아졌습니다.

 

분산 코디네이션 시스템을 제대로 작성하지 못하게 될 경우 단일 장애점(Single Point of Failure)가 발생하게 되고 이것은 시스템의 신뢰성을 떨어뜨리는 요소가 됩니다. 또한 분산되어 있는 어플리케이션이 제대로 조율되지 못할 경우 각 어플리케이션이 공유하고 있는 클러스터 자원에 무분별한 쓰기 동작(write operation)으로 인해 경쟁상태(Race codition)가 일어나게 될 가능성이 커집니다.

 

| 주키퍼란(Zookeeper)?

 

주키퍼는(Zookeeper)는 분산 코디네이션 서비스를 제공하는 오픈소스 프로젝트입니다. 이러한 어플리케이션의 목적은 개발자가 코디네이션 로직보다는 비즈니스 핵심 로직에 집중하게끔 지원하는 역할을 합니다.

 

주키퍼는 Leader Follower로 구성되는 Master-Slave 아키텍처를 기반으로 구성되어 있습니다. 이것을 기반으로 여러 주키퍼 서버로 이루어진 앙상블(Ensemble), 앙상블 데이터의 불일치를 방지하고자 하는 쿼럼(Quorum) 그리고 분산 데이터 시스템인 znode로 이루어진 주키퍼 데이터 모델(zookeeper data model)이 주키퍼를 구성하게 됩니다.

 

주키퍼는 znode로 이루어진 분산 데이터 모델을 지원하는 시스템이라고 해도 과언이 아닙니다. 이 데이터 모델은 리눅스(linux) 파일시스템과 유사한 시스템을 제공하고 이것이 주키퍼의 핵심입니다.  주키퍼에 채택된 아키텍처와 기법들은 이 데이터 모델을 안정적으로 제공하고자 하기 위함입니다. 이 시스템을 통해 주키퍼는 글로벌락, 클러스터 정보, Leader 선출 등을 구현해야하는 곳에 활용할 수 있습니다. 이러한 목적으로 HBase, Kafka(아파치 카프카), Hadoop, kubernetes와 같은 인기 오픈소스 프로젝트에서도 분산 코디네이션 시스템을 구현하기 위해 주키퍼를 채택했습니다.

 

| 주키퍼의 사용용도(Zookeeper, Purpose use of)

 

주키퍼는 클러스터에서 구성 서버들끼리 공유되는 데이터를 유지하거나 어떤 연산을 조율하기 위해 주로 사용됩니다. 주요 사용 용도는 다음과 같습니다.

  • 설정 관리(Configuration management) : 클러스터의 설정 정보를 최신으로 유지하기 위한 조율 시스템으로 사용됩니다.
  • 클러스터 관리(Cluster management) : 클러스터의 서버가 추가되거나 제외될 때 그 정보를 클러스터 안 서버들이 공유하는 데 사용됩니다.
  • 리더 채택(Leader selection) : 다중 어플리케이션 중에서 어떤 노드를 리더로 선출할 지를 정하는 로직을 만드는 데 사용됩니다. 주로 복제된 여러 노드 중 연산이 이루어지는 하나의 노드를 택하는 데 사용됩니다.
  • 락, 동기화 서비스(Locking and synchronization service) : 클러스터에 쓰기 연산이 빈번할 경우 경쟁상태에 들어갈 가능성이 커집니다. 이는 데이터 불일치를 발생시킵니다. 이 때, 클러스터 전체를 대상을 동기화해( 락을 검 ) 경쟁상태에 들어갈 경우를 사전에 방지합니다.

| 주키퍼 아키텍처(Zookeeper Architecture)

 

주키퍼의 아키텍처는 znode를 제공하기 위한 안정적인 분산 시스템을 구현하기 위해 설계되었습니다. 주키퍼는 다음과 같은 그림과 같이 구성되어 있습니다.

 

 

 

클라이언트들은 주키퍼 서버들로 이루어진 앙상블(Ensemble)에 접근하여 znode의 데이터를 읽거나 데이터를 업데이트 합니다. 앙상블안의 주키퍼 서버들은 조율된 상태이며 항상 동일한 데이터를 가지고 있습니다. 따라서 어느 서버에서 데이터를 읽어도 똑같죠.

 

만일 주키퍼 서버에 쓰기 동작을 할 경우에, 클라이언트는 특정 서버에 접속하여 그 서버의 데이터를 업데이트 합니다. 그리고 업데이트 된 서버는 leader의 역할을 맡은 주키퍼 서버에 그 데이터를 알리고 업데이트하죠. 이 업데이트를 감지한 leader 서버는 그 정보를 다른 곳에 브로드캐스트(Broadcast) 형식으로 알리게 됩니다. 그 업데이트 정보를 받은 나머지 Follower 주키퍼 서버들은 그 내용을 갱신하여 전체 서버들의 데이터들이 일관된 상태로 유지된 상태로 있게 됩니다.

 

| 주키퍼 znode(Zookeeper znode)

 

znode는 주키퍼의 핵심입니다. 이 znode를 통해 주키퍼가 제공할 수 있는 글로벌 락, 동기화, 리더 채택, 설정 관리 등의 기능을 구현할 수 있습니다.

 

결국 클라이언트의 관점에서 보게 되면 서버에 접속할 시 보이게 되는 것은 이 znode들입니다. 주키퍼에 채택된 아키텍처와 기법들은 결국 znode로 구성된 데이터 모델을 안정적으로 제공하고자 하는 목적으로 만들어졌다고 해도 과언이 아닙니다.

 

 

 

이 데이터 모델은 위 그림에서 보시는 바와 같이 linux 파일 시스템과 유사한 형태입니다. 이 구조를 주키퍼 데이터 모델(Zookeeper Data Model)이라고 하고 명명 구조는 Hierarhical namespace 룰을 따릅니다. 마치 / 를 이용하여 디렉토리와 파일들을 나누는 명명법과 비슷하죠.

 

각각의 znode는 stat 구조를 유지하고 있습니다. 이 stat은 znode의 메타데이터(metadata)를 제공합니다. 이 메타데이터를 이루는 것은 버전 넘버(version number), ACL(Action control list), 타입스탬프(Timestamp), 그리고 데이터 길이(Data length)가 있습니다.

 

  • 버전 넘버(version number) : 모든 znode들은 버전 넘버가지고 있습니다. znode의 데이터가 업데이트 될 때마다 이 버전 넘버는 계속해서 업데이트됩니다. 이 정보는 다수의 주키퍼 클라이언트(client)들이 특정한 연산을 같은 znode에 수행할 때 꼭 필요한 정보입니다.
  • ACL(Action control list) : ACL은 znode에 접근하기 위한 권한 획득 메커니즘입니다. 이 권한을 통해 znode의 읽기 쓰기 연산을 통제하죠.
  • 타입스탬프(Timestamp) : znode는 타임스탬프 정보를 제공합니다. znode가 생성되고 나서 경과된 시간 및 업데이트된 시간이 그것이죠. 시간 단위는 보통 ms입니다. 주키퍼는 znode를 변경한 트랜잭션(Transaction)정보를 기록합니다. 이 트랜잭션 정보는 Zxid로 구분됩니다. 타임스탬프를 이용하면 어떤 연산이 얼마나 걸렸는지 얼마나 경과했는지 바로 알 수 있습니다.
  • 데이터 길이(Data length) : 주키퍼의 데이터 크기를 말합니다. 주키퍼의 데이터들은 최대 1MB까지 저장 가능합니다.

 

또한 znode들은 3가지 타입에 따라 나뉘어 집니다.

 

  • 영속 znode(Persistence znode) : 영속 znode는 이 znode를 만든 클라이언트의 접속이 끊어져도 계속 주키퍼 데이터 모델에 남아있습니다. znode가 만들어질 때 default로 이 영속 znode가 만들어집니다. 이 영속 znode는 클러스터 관리 로직을 구현할 때 중요한 역할을 하게 됩니다.
  • 임시 znode(Ephemeral znode) : 임시 znode는 이 znode를 만든 클라이언트의 접속이 끊기면 데이터 모델 상에서 사라집니다. 이런 특징덕분에 임시 znode는 자신의 자식 znode를 가질 수 없습니다. 임시 znode는 리더 선출을 구현할 때 요긴하게 사용됩니다.
  • 연속형 znode(Sequential znode) : 연속형 znode는 영속적일 수도 임시적일 수도 있습니다. 연속형 znode가 만들어 질 때 주키퍼 데이터 모델 상에서 이 znode는 10자리 연속된 숫자를 가지고 있는 이름을 가지고 만들어 집니다. 예로들어 /app 이라는 연속형 znode를 만들면 app0000000001 로 자동적으로 만들어지는 형식입니다. 그리고 다음에는 0000000002이 znode가 만들어 지죠. 이 두 znode들은 동시에 만들어지기 때문에 주키퍼는 똑같은 이름의 노드를 쓸 일이 없습니다. 이 연속형 znode는 lock을 구현하거나 글로벌 큐(global queue)를 구현할 때 요긴하게 사용됩니다.

 

| 마치며

 

주키퍼를 사용하게 되면 분산 처리 시스템을 손쉽게 구현할 수 있습니다. 주키퍼는 znode로 구성된 주키퍼 데이터 모델을 제공하며 이것을 통해 글로벌락, 클러스터 관리, 리더 선출 등 여러 코디네이션 로직을 구현할 수 있습니다. 결국 주키퍼는 안정적이고 가용성 높은 znode 데이터 시스템을 제공하는 클러스터 서버라고 해도 과언이 아닙니다. 다음 포스팅에서는 주키퍼의 쿼럼과 그 동작 방식 혹은 설치 방법을 다루어 보겠습니다.

반응형

이 글을 공유하기

댓글

Designed by JB FACTORY