본문 바로가기

Apache/ZooKeeper

클라이언트 라이브러리: C Binding

바인딩

Zookeeper 클라이언트 라이브러리는 Java와 C, 두 가지의 언어를 공식 지원한다.


C 바인딩

C 바인딩에는 싱글 쓰레드와 멀티 쓰레드의 라이브러리가 있습니다. 이 중 가장 사용하기 쉬운 것은 멀티 쓰레드 라이브러리이며, Java API와 거의 비슷합니다. 멀티 쓰레드 라이브러리는 IO 쓰레드와 이벤트 디스패치 쓰레드를 생성하여 접속의 유지와 콜백을 처리합니다. 싱글 쓰레드 라이브러리에서는 멀티 쓰레드 라이브러리에서 사용하는 이벤트 루프를 공개하는 것으로 ZooKeeper를 이벤트 구동 어플리케이션으로 사용할 수 있습니다.


패키지에는 zookeeper_st와 zookeeper_mt, 두 개의 공유 라이브러리가 포함되어 있습니다. 전자는 어플리케이션의 이벤트 루프에 짜넣기 위한 비동기 API와 콜백만을 제공합니다. 이 라이브러리의 유일한 존재 이유는 pthread 라이브러리가 이용되지 않는 불안정한 플랫폼 (즉, FreeBSD 4.x)를 지원하기 위해 있습니다. 그 이외의 모든 경우에는 어플리케이션 개발자는 동기 API와 비동기 API의 양쪽을 지원하고 있는 zookeeper_mt를 링크해야 합니다.


C클라이언트의 사용

클라이언트를 테스트 하기 위해서는 Zookeeper 서버를 실행하여 (실행 방법에 대해서는 프로젝트의 Wiki 페이지에 있는 순서를 참조하세요) C 클라이언트를 설치할 때 생성된 cli 어플리케이션을 사용하여 서버에 접속합니다. 아래의 예에서는 cli_mt (zookeeper_mt 라이브러리와 링크한 멀티 쓰레드 클라이언트)를 사용하지만 cli_st(zookeeper_st 라이브러리와 링크한 싱글 쓰레드 클라이언트)도 사용할 수 있습니다.


$ cli_mt zookeeper_host:9876


클라이언트 애플리케이션을 사용하면 간단한 Zookeeper 명령어를 실행할 수 있는 쉘이 기동됩니다. 애플리케이션이 정상적으로 기동되어 서버에 접속되면 쉘 프롬프트가 표시됩니다. 이 쉘 프롬프트는 ZooKeeper 명령어를 입력할 수 있습니다. 예를 들면 노드를 작성하기 위해서는 다음과 같이 입력합니다.


> create /my_new_node


노드가 작성된 것을 확인합니다.


> ls /


루트 노드 "/"의 자식 리스트가 표시될 것입니다.

자기가 작성한 애플리케이션 중에서 ZooKeeper API를 사용하기 위해서는 다음과 같이 해야 합니다.


  1. ZooKeeper 헤더를 Include 합니다: #include <zookeeper/zookeeper.h>
  2. 멀티 쓰레드 클라이언트를 빌드 하는 경우에는 멀티 쓰레드 버전의 라이브러리를 유효하게 하는 -DTHREADED 라고 하는 컴파일 플러그를 지정하여 컴파일하면, zookeeper_mt 라이브러리와 링크 합니다. 싱글 쓰레드 클라이언트를 빌드 하는 경우에는 -DTHREADED 를 지정하지 않고 컴파일하면 zookeeper_st 라이브러리와 링크합니다.

에러처리
Java와 C의 클라이언트 바인딩에는 에러를 보고하는 것이 가능합니다. Java 클라이언트 바인딩에는 KeeperException이 Throw되어서 예외에 대한 code() 를 호출하면 구체적인 에러 코드를 반환합니다. C 클라이언트 바인딩에서는 enum ZOO_ERRORS에 정의된 에러 코드를 반환합니다. API 콜백한 어떤 언어 바인딩의 경우에도 결과 코드를 반환합니다. 발생할 가능성이 있는 에러와 그 의미의 상세한 것은 API 문서(Java의 경우에는 javadoc, C의 경우에는 doxygen)을 참조하세요.


자주 있는 질문과 트러블 슈팅
이상으로 ZooKeeper에 대해서는 대략 이해가 되었다고 생각합니다. ZooKeeper는 고속이며 간단합니다. 작성된 애플리케이션도 동작합니다. 하지만 때로 애플리케이션이 기대한 그대로 동작하지 않을 수도 있습니다. 여기에 ZooKeeper 유저가 빠지기 쉬운 문제를 몇가지 나열합니다.

  1. 왓치 (Watch)를 사용하고 있는 경우엔 connected 왓치 이벤트를 감시하지 않으면 안됩니다. ZooKeeper 클라이언트가 서버로부터 접속이 끊기게 되면, 서버에 재접속할 때까지는 변경통지를 취득할 수 없습니다. znode의 존재를 감시하고 있는 경우 서버로부터 접속이 끊긴 사이에 그 znode가 작성되어 제거되면 이벤트가 제거 됩니다.

  2. ZooKeeper 서버에 장해가 발생할 때를 상정하여 테스트를 해둘 필요가 있습니다. ZooKeeper 서비스는 서버의 과반수가 활성화가 되어 있는 한 제공가능입니다. 문제는 애플리케이션 측에서 장해에 대처할 수 있는가 입니다. 현실의 운용에서는 클라이언트에서 ZooKeeper로의 접속이 끊기는 경우가 있습니다. (접속이 끊기는 원인으로서 자주 있는 것은 ZooKeeper 서버에서의 장해발생과 네트워크의 분단입니다). ZooKeeper 클라이언트 라이브러리는 접속을 복원하여 무언가 이벤트가 발생하면 통지를 해주지만 프로그래머 측에서는 이전의 상태를 복원하여 실패한 미처리의 요청을 다시 고칠 필요가 있습니다. 실제 구동 환경으로 이해하기 전에 테스트 환경에서 이러한 점을 주의깊게 체크할 필요가 있습니다. 특히 복수의 서버로 구성된 ZooKeeper 서비스에서 테스트를 하여 이것들의 서버를 재기동시키더라도 애플리케이션이 적절히 동작하는 지를 체크해주세요.

  3. 클라이언트가 사용하는 ZooKeeper 서버의 리스트는 각 ZooKeeper 서버가 보존하고 있는 ZooKeeper 서버의 리스트와 일치하지 않으면 안됩니다. 클라이언트의 리스트가 실제의 ZooKeeper 서버 리스트의 서브셋이 있는 경우에는 반드시 최적의 상태가 아니더라도 동작에 문제는 발생하지 않습니다. 다만 클리이언트의 리스트에 포함되어 있는 ZooKeeper 서버가 ZooKeeper 클러스터에 포함되어 있지 않는 경우에는 동작에 문제를 일으킵니다.

  4. 트랜잭션 로그의 설치 장소에는 주의해주세요. ZooKeeper 중에서 성능에 가장 큰 영향을 미치는 부분은 트랜잭션 로그입니다. ZooKeeper는 Response를 리턴하기 전에 트랜잭션을 매체(Media)에 sync하지 않으면 안됩니다. 일관되며 양호한 성능을 확보하기 위해서는 트랜잭션 로그 전용의 장치를 준비하는 것이 중요합니다. Busy한 장치에 트랜잭션을 처리하면 성능이 저하합니다. 스토리지 장치가 한 개밖에 없는 경우에는 추적 파일(Trace file)을 NFS에 설치하여 snapshotCount의 값을늘려주세요. 이것으로 문제가 제거되지는 않을 수 있지만 적어도 문제의 경감에는 이어집니다.

  5. Java의 최대 Heap 사이즈를 적절히 설정해주세요. Swap을 발생시키지 않도록 하는 것이 상당히 중요합니다. 불필요하게 디스크에 엑세스하게 되면 거의 틀림없이 허용할 수 없을 정도로 성능이 저하됩니다. ZooKeeper에서는 모든 것이 순서대로 처리된다는 것을 잊지 마세요. 즉, 어떤 요청으로 디스크 엑세스가 필요하다면 그 외의 모든 요청에도 디스크 엑세스가 필요하게 됩니다.
    Swap의 발생할 피하기 위해서는 머신에 탑재하고 있는 물리 메모리부터 OS와 캐시에 필요한 양을 뺀 사이즈를 Heap 사이즈로 설정합니다. 서비스의 구성에 최적인 Heap 사이즈를 결정하는 가장 좋은 방법은 부하 테스트를 실시하는 것입니다. 어떠한 이유로 부하 테스트를 실시할 수 없는 경우에는 예상을 어렴풋이 어림잡아 머신에서 Swap이 발생할 한계 값 보다도 대폭으로 낮은 값을 Heap 사이즈로 설정해주세요. 예를 들면 4GB의 메모리를 탑재한 머신에는 3GB부터 조절하는 식으로 하면 좋겠죠.