기본 콘텐츠로 건너뛰기

[SolrCloud] ZooKeeper Cluster 구성해 보기

[ 참고 및 주의 사항 ]
여기에 정리된 내용은 원문을 기준으로 여러 가지 테스트와 문제점의 검토 및 해결책을 찾으면서 나름대로 정리한 내용으로 오역과 잘 못 이해하고 정리한 부분이 있을 수 있습니다.

ZooKeeper 란?

ZooKeeper는 분산 어플리케이션들에 대한 분산 조정 서비스를 제공하는 프로그램으로 표준 파일 시스템과 유사하게 구성되어 공유된 계층적 공간을 통해서 분산된 프로세스들이 서로 조정할 수 있는 기능을 관리한다. 공유되는 공간은 ZooKeepr의 용어로 zNodes라고 불리는 데이터 등록의 집합으로 구성 되어 있으며 이 구조는 폴더들과 파일들의 구성과 유사하다. 파일 시스템과는 달리 ZooKeeper는 자바로 실행되며 자바와 C에 대한 바인딩을 가지고 있다.

ZooKeeper Cluster 기본 구성

ZooKeeper Service 는 “Ensemble” 이라고 불리는 Host 들의 집합들을 통해서 복제되며, 동일한 어플리케이션을 구성하는 서버들의 복제된 그룹을 “Quorum” 이라고 부른다. Quorum 내의 모든 서버는 동일한 설정 파일들의 복제본을 가지고 있다. ZooKepper의 서버 구성의 수는 절반이 실패해도 기능을 수행할 수 있도록 항상 홀수로 구성하는 것을 권장한다. 예를 들어 2대의 서버가 장애 상태가 되어도 나머지 서버들이 동작할 수 있도록 5대의 서버로 구성하는 것이다. 이 중에 한 대는 Leader가 된다. 최소한의 구성은 3 대가 된다.

ZooKeeper 구성할 때 검토할 부분

ZooKeeper를 구성하기 위해서는 최소한 아래에 언급한 내용들에 대한 검토가 선행이 되어야 한다. 그리고 ZooKeeper Cluster의 구성은 아래의 그림과 같이 기본적으로 Leader를 포함하는 홀 수의 서버 구성이 되어야 한다.
ZooKeeper Cluster (Multi-Server) Diagram
여기서는 샘플을 테스트하는 것을 기준으로 검토를 진행하도록 한다.
  • ZooKeeper 서버 구성의 수는 어떻게 할 것인가? - 위에서 언급한 것과 같이 홀수를 기준으로 구성하며, 테스트 환경이므로 3대의 서버로 구성한다.
  • 물리적인 서버의 수는 어떻게 할 것인가? - 물리적인 장애가 발생하는 경우를 대비해서 가능하면 물리적으로 존재하는 서버로 구성하는 것이 좋다. 그러나 테스트이므로 단일 서버를 사용하도록 한다.
  • 운영을 위한 포트의 구성은 어떻게 할 것인가? - 별도의 서버로 존재하면 Port를 크게 신경쓰지 않아도 되지만 테스트를 위해서 단일 서버에 구성하는 것이기 때문에 아래와 같이 구성한다.
    • Client Port 는? - 클러스터에서 운영할 어플리케이션에 ZooKeeper로 접속하기 위한 포트를 의미한다.
    • Qourum Port 는? - 클러스터내의 ZooKeeper 서버간에 통신을 위한 포트를 의미한다.
    • Leader election Port 는? - 클러스터내의 ZooKeeper 서버간에 Leader를 선출하기 위한 통신 포트를 의미한다.
    Notes
    샘플 구성을 위해서 3개의 ZooKeeper 서버를 단일 장비에서 운영한다면 아래와 같이 포트 구성을 조정해 주어야 한다.
    Server ID Client Port Quorum Port Leader Election Port
    1 2181 2888 3888
    2 2182 2889 3889
    3 2183 2890 3890
  • ZooKeeper 서버의 dataDir 경로는? - “D:\ZooKepper\data” 와 같이 고정된 경로를 사용하여 데이터 구성을 위한 기본 폴더로 사용한다. 이 경로를 설정하는 것은 ZooKeeper의 성능과도 연결되므로 성능관련 고려사항을 검토하도록 한다.
  • ZooKeeper 서버의 dataLogDir 경로는? - “D:\ZooKeeper\logs” 와 같이 고정된 경로를 사용하여 Log 구성을 위한 기본 폴더로 사용한다. 이 경로를 설정하는 것은 ZooKeeper의 성능과도 연결되므로 성능관련 고려사항을 검토하도록 한다.
  • ZooKeeper에 대한 메모리 설정은? - 테스트를 위한 것이라면 기본 Heap size를 사용해도 상관없다. 그러나 실제 운영을 위한 것이라면 ZooKeeper 설치 경로의 “/conf/java.env” 파일을 생성해서 관련된 메모리 설정을 조정해 주어야 한다. 이런 설정은 ZooKeeper의 성능과도 연결되므로 성능관련 고려사항을 검토하도록 한다.
    Notes
    {ZooKeeper_HOME}\conf\java.env 파일을 생성하고 다음과 같이 설정해 주면 된다. (Heap Max size 설정으로 크기는 상황에 맞게 지정하면 된다)
    export JVMFLAGS=”-Xmx2048m”

ZooKeeper Multiple Server 구성하기

샘플 테스트를 위한 ZooKeeper 서버들을 구성하도록 한다.
  1. ZooKeeper 서버 운영을 위한 기본 폴더 구조를 작성한다.
    Root 폴더는 “D:\ZooKeeper” 로 한다.
    각 서버는 다음과 같이 3개의 폴더로 구성한다.
    D:\ZooKeeper\zk-server1
    D:\ZooKeeper\zk-server2
    D:\ZooKeeper\zk-server3
    각 서버별 데이터 관리를 위한 폴더를 “data” 폴더 밑으로 구성한다.
    D:\ZooKeeper/data/zk1
    D:\ZooKeeper/data/zk2
    D:\ZooKeeper/data/zk3
    각 서버별 Log 관리를 위한 폴더를 “logs” 폴더 밑으로 구성한다.
    D:\ZooKeeper/logs/zk1
    D:\ZooKeeper/logs/zk2
    D:\ZooKeeper/logs/zk3
  2. 이제 각 서버별로 식별할 수 있는 ID 를 지정하기 위해서 위에서 설정한 “data” 폴더의 각 서버 밑에 “myid” 라는 파일을 생성하고 (ex. D:\ZooKeeper\data\zk1\myid) 파일의 내용에 서버를 식별할 수 있는 ID 값 (zk1 은 1, zk2 는 2, zk3 는 3) 으로 설정한다.
  3. 다운로드 해 놓은 ZooKeeper 3.4.6 폴더에서 전부를 복사해도 되고, 필수적인 폴더들 (bin, conf, lib) 과 필요한 jar (zookeeper-3.4.6.jar) 파일을 각 서버 (zk1, zk2, zk3) 폴더에 복사해 넣는다.
  4. ZooKeeper 서버를 구동할 수 있는 환경 설정을 각 서버별로 구성한다. 복사한 서버(ex. zk1) 폴더의 conf 에 보면 zoo-sample.cfg 파일이 존재하므로 이를 복사해서 zoo.cfg 파일을 생성한다.
    1. zk1 서버 폴더의 conf 에 zoo-sample.cfg 파일이 존재한다. 이 파일을 복사하여 zoo.cfg 파일을 생성한다.
    2. 파일의 내용 중에서 해당 서버와 연결되는 항목인 clientPort, dataDir, dataLogDir 정보를 위에서 설정한 폴더 구조에 맞도록 설정한다. 물론 포트도 역시 위에서 정리한 서버 별 포트 내용에 맞도록 설정한다.
    Notes
    zk1 서버에 zoo.cfg 는 다음과 같이 구성되어야 한다.
    tickTime=2000
    initLimit=10
    syncLimit=5
    dataDir=D:\\ZooKeeper\\data\\zk1
    clientPort=2181
    dataLogDir=D:\\ZooKeeper\\logs\\zk1
    server.1=localhost:2888:3888
    server.2=localhost:2889:3889
    server.3=localhost:2890:3890
    >
  5. 위에서 구성한 Log 폴더를 이용하기 위해서는 각 ZooKeeper 서버의 bin 폴더에 존재하는 zkEnv 파일에서 “ZOO_LOG_DIR” 을 수정해 주면 된다. (Log 설정을 위한 정보는 conf 폴더에 log4j.properties 파일이 존재하며, bin 폴더의 zkServer 스크립트 파일에서 Log와 관련된 정보를 사용한다)
    ...
    set ZOOCFGDIR=%~dp0%..\conf
    set ZOO_LOG_DIR=%~dp0%..\..\logs\zk1
    set ZOO_LOG4J_PROP=INFO,ROLLINGFILE
    ...
  6. 구동을 위한 설정이 준비되었으므로 각 ZooKeeper 서버를 구동하면 된다. 각 서버의 bin 폴더에서 zkServer.cmd 를 실행하면 된다.
    Notes
    zk-server1 을 실행하면 Log 상에 2번과 3번 서버로의 통신이 실패했다는 Log를 볼 수 있다. zk-server2 를 실행하면 3 번 서버로의 통신이 실패했다는 Log를 볼 수 있다. 1번과 2번이 실행되었으므로 1번과 2번 모두 3번과 연결할 수 없다는 Log를 확인할 수 있다. 마지막으로 zk-server3 을 실행하면 연결이 모두 되어 동작하는 것을 확인할 수 있다.
    zkServer.sh 스크립트는 다양한 명령을 제공한다.
    • start
    • start-foreground
    • stop
    • restart
    • status
    • upgrade
    • print-cmd
    그러나 Windows 에서 사용할 zkServer.cmd 파일은 배포된 버전에서는 위와 같은 명령을 제공하지 않는다. 따라서 “zkServer.cmd start” 라고 실행하면 오류가 발생한다. 따라서 zsServer.cmd 만을 실행하면 ZooKeeper 서버가 실행된다. zkServer.cmd 와 명령이 제공되는 버전은 여기서 받으면 된다. 그러나 역시 start 는 되지만 stop 은 오류가 발생할 수 있으며, 정상 동작하는 경우에 전체 ZooKeeper 서버를 모두 종료 시킨다. 한다.

ZooKeeper CLI Client 사용법

ZooKeeper CLI 는 Command Line 으로 ZooKeeper를 관리할 수 있는 도구로 “How to connect ZooKeeper through CLI?”“Famous Four letter commands” 를 참조하면 된다.

ZooKeeper Cluster를 어플리케이션에서 사용하는 방법

ZooKeeper Cluster 를 이용할 어플리케이션은 ZooKeeper Cluster 구성 후에는 바로 연결할 수 있다. 이 때 필요한 정보는 다음과 같다.
  • ZooKeeper Server 의 Host Address / Host IP
  • ZooKeeper Server 의 Client Access Port No
현재 작업 중인 부분이 SolrCloud 이기 때문에 이에 대한 사용 방법은 “ZooKeeper 와 SolrCloud를 Tomcat7 에 설정해 보기” 를 참고하도록 한다.

기본적인 유지 관리 부분

별다른 작업이 필요한 것은 아니고 다음과 같은 정보를 정리하면 된다.
  • 데이터 디렉토리 정리
  • 디버그 Log 정리
ZooKeeper는 “autopurge.snapRetainCount” 와 “autopurge.purgeInterval” 과 같은 설정을 통해서 자동으로 정리하는 기능 (Autopurge) 을 제공하고 있다. 그러나 실제 ZooKeeper 관리 방법은 IT 조직의 운영 방침과 요구에 따라서 달라지므로 “ZooKeeper maintenance” 를 참고하여 적절한 방침과 방법을 수립하면 된다.

성능과 가용성에 대한 검토 사항들

  • Ensemble 을 구성하는 서버들의 대부분이 가동되면 ZooKeeper 서비스를 이용할 수 있다. 위에서도 계속 언급을 했지만 절반이 실패하더라도 구성이 가능할 수 있도록 홀 수를 유지하는 것이 중요하다. 예를 들어 짝수로 구성된 4개의 서버 중에서 2개의 서버가 실패하면 나머지 2개의 서버 중에서 1개의 서버는 리더가 되고 1개의 서버가 복제 상태가 되는데 이런 경우는 복제가 실패했을 때 대응을 할 수 없는 상태가 된다. 여기서 리더는 복제 단위가 아니기 때문에 1개 서버 만으로 복제를 운영할 수 없는 상태가 된다.
  • ZooKeeper는 오류가 발생하면 프로세스가 종료되는 Fail-Fast 정책으로 운영된다. 따라서 자동으로 복원을 하는 것이 아니기 때문에 관리자의 감독하에서 실행하는 것이 상당히 중요하다. 자세한 내용은 여기를 참고하면 된다.
  • ZooKeeper의 데이터 디렉토리는 Emsemble 에서 처리되는 zNodes 들의 정보 복사본들이 저장된다. 이 파일들은 Snapshot 파일들로 zNodes 들에서 처리된 변경들을 트랜잭션 로드로 추가하며, 때때로 Log들이 커지게 되면 모든 zNode 들의 현재 상태의 Snapshot 들을 파일 시스템에 기록하고 기존의 Log들을 대체한다.
  • ZooKeeper의 Transaction Log는 전용 장치에 존재해야 하며, 파티션으로 처리된 전용 공간으로는 충분하지 않다고 명시되어 있다. 즉 ZooKeeper는 Log를 순차적으로 기록하며, 다른 프로세스들과 탐색이 경합이 발생할 수 있는 Log 장치의 공유를 허용하지 않는 것을 원칙으로 해야 한다.
  • ZooKeeper 을 Swap이 발생할 수 있는 상황으로 관리하면 안 된다. ZooKeeper가 기능을 제대로 발휘할 수 있도록 하기 위해서는 Swap 발생을 미리 차단해 놓아야 한다. 예를 들어 ZooKeeper가 사용할 수 있는 Heap Size를 물리적인 사용 가능 메모리보다 크게 지정하면 나중에 메모리 Swap이 발생하므로 이런 설정은 피해야 한다. 이와 같은 피해야 할 부분들은 여기를 참고하면 된다.

댓글

이 블로그의 인기 게시물

OData 에 대해서 알아보자.

얼마 전에 어떤 회사에 인터뷰를 하러 간 적이 있었다. 당시 그 회사는 자체 솔루션을 개발할 기술인력을 찾고 있었고 내부적으로 OData를 사용한다고 했다. 좀 창피한 이야기일 수도 있지만 나름 기술적인 부분에서는 많은 정보를 가지고 있다고 했던 것이 무색하게 OData란 단어를 그 회사 사장님에게서 처음 들었다. 작고, 단순한 사이트들만을 계속해서 작업을 하다 보니 어느덧 큰 줄기들을 잃어버린 것을 느끼기 시작했다. 명색이 개발이 좋고, 기술적인 기반을 만들려고 하는 인간이 단어조차도 모른다는 것은 있을 수 없는 것이라서 다시 새로운 단어들과 개념들을 알아보는 시간을 가지려고 한다. OData (Open Data Protocol) 란? 간단히 정리하면 웹 상에서 손쉽게 데이터를 조회하거나 수정할 수 있도록 주고 받는 웹(프로토콜)을 말한다. 서비스 제공자 입장에서는 웹으로 데이터를 제공하는 방식으로 각 포탈 사이트들이 제공하는 OPEN API 포맷을 독자적인 형식이 아니라 오픈된 공통규약으로 제공 가능하며, 개발자는 이 정보를 다양한 언어의 클라이언트 라이브러리로 어플리케이션에서 소비할 수 있도록 사용하면 된다. 공식 사이트는 www.odata.org 이며 많은 언어들을 지원하고 있다. 좀더 상세하게 정의를 해 보면 OData는 Atom Publishing Protocol  (RFC4287) 의 확장 형식이고 REST (REpresentational State Transfer) Protocol 이다. 따라서 웹 브라우저에서 OData 서비스로 노출된 데이터를 볼 수 있다. 그리고 AtomPub 의 확장이라고 했듯이 데이터의 조회만으로 한정되는 것이 아니라 CRUD 작업이 모두 가능하다. Example 웹 브라우저에서 http://services.odata.org/website/odata.svc 를 열어 보도록 하자. This XML file does not appear to have any style in...

C# 에서 Timer 사용할 때 주의할 점.

예전에 알고 지내시던 분의 질문을 받았다. Windows Forms 개발을 하는데, 주기적 (대략 1분)으로 데이터 요청을 하는 프로그램을 작성하기 위해서 Timer 를 사용하는데, 어떤 기능을 처리해야 하기 때문에 Sleep 을 같이 사용했다고 한다. 여기서 발생하는 문제는 Sleep 5초를 주었더니, Timer 까지 5초 동안 멈춘다는 것이다. Timer 라는 것은 기본적으로 시간의 흐름을 측정하는 기능이기 때문에 Sleep 을 했다고 해서 Timer 가 멈추는 일은 생겨서는 안된다. 그러나 실제 샘플을 만들어 보면 ... Timer 가 Sleep 만큼 동작이 멈추는 것을 확인할 수 있다. Windows Forms 는 UI Thread 를 사용하는 것으로 최적화 되어 있으며 여기서 Timer 를 쓰면 UI Thread 에 최적화된 System.Windows.Forms.Timer 가 사용된다. 여기서 문제의 발생이 시작되는 것이다. Sleep 을 사용하게 되면 UI Thread 가 Sleep 이 걸리기 때문에 여기에 속한 Timer 까지도 멈추는 것이다. 이런 문제를 해결하기 위해서는 System.Threading.Timer 를 사용해야 한다. 이 Timer 는 별도의 Thread 에서 동작하기 때문에 Sleep 의 영향을 받지 않는다. 언뜻 보면 쉬운 해결 방법인 것 같지만 Thread 가 분리되었기 때문에 Timer 가 돌아가는 Thread 에서 UI Thread 의 메서드나 컨트롤에 접근하기 위해서는 별도의 명령을 사용해야 하는 문제가 존재한다. 자~ 그럼 여기서 Timer 에 대해서 다시 한번 정리해 보도록 하자. .NET 에서 제공하는 Timer 들 .NET 에서는 기본적으로 3가지 Timer를 제공하고 있다. (MSDN) System.Windows.Forms.Timer - 사용자가 지정한 간격마다 이벤트를 발생시키며 Windows Forms 응용 프로그램에서 사용할 수 있도록 최적화 되어 있다. System...

[Logging] NLog 사용법 정리...

SCSF 에는 기본적으로 Enterprise Library가 사용된다. 예전에도 그랬지만 기능은 훌륭하고 많은 부분에서 최적화(?)된 것일지도 모르지만, 역시나 사용하기에는 뭔가 모르게 무겁고, 사용하지 않는 기능이 더 많다라는 느낌을 지울수가 없다. 이번 프로젝트도 SCSF를 기반으로 하고 있지만, Enterprise Library를 걷어내고 각 부분에 전문화된 오픈 소스를 사용하기로 하였다. 예전에는 Log4Net을 사용했지만, 대량 사용자 환경에서는 메모리 누수와 기타 문제점이 존재한다는 MS 컨설턴트(?)의 전해진 말을 들은 후로는 사용하지 않는다. 대안으로 사용하는 것이 NLog 이다. 조금 후에는 3.0 버전도 나온다고 홈 페이지에 기재되어 있지만, 그 때가 되면 프로젝트는 끝나기 때문에 현재 2.1.0 버전을 사용하기로 했다. [원본 출처] http://cloverink.net/most-useful-nlog-configurations-closed/ 위의 참조 자료에는 다양한 정보들이 존재하므로 꼭 링크를 통해서 관련된 정보를 확인하고 이해하는 것이 좋을 듯 하다. 여기서는 당장 필요한 부분만을 정리하도록 한다. [ Logger 찾기 ] 기본적으로 Logger가 존재하는 클래스를 기반으로 Logger 정보를 구성한다. Logger logger = LogManager.GetCurrentClassLogger(); 주로 Namespace 기반으로 Logger를 설정하는 경우에 유연하게 사용할 수 있다. 또 다른 방법으로는 지정한 문자열로 특정 Logger를 직접 선택하는 방법도 제공된다. 이를 혼용해서 Namespace와 직접 지정 방식을 같이 사용할 수도 있다. 물론 Logger 환경 설정에서 Wildcard (*)를 지정할 수도 있다. Logger logger = LogManager.GetLogger("Database.Connect"); Logger logger = LogManager.Get...