ZooKeeper

ZooKeeper

이 문서는 HBase에서 ZooKeeper를 설정하고 운영하는 방법을 설명해요. HBase는 기본적으로 ZooKeeper "클러스터"를 관리하며 시작/정지 프로세스의 일부로 앙상블을 시작하고 멈춰요. ZooKeeper 앙상블을 HBase와 독립적으로 관리하고 HBase가 사용할 클러스터를 가리키게 할 수도 있어요. 대규모 클러스터를 구성한다면 반드시 알아야 할 내용이에요.

출처: 문서

본문

Apache HBase는 기본적으로 ZooKeeper "클러스터"를 관리해 줘요. HBase 시작/정지 프로세스의 일부로 ZooKeeper 앙상블을 시작하고 멈춰요. ZooKeeper 앙상블을 HBase와 독립적으로 관리하고 HBase가 사용할 클러스터를 가리키게 할 수도 있어요. HBase의 ZooKeeper 관리를 토글하려면 conf/hbase-env.sh의 HBASE_MANAGES_ZK 변수를 사용하세요. 기본값 true인 이 변수는 HBase가 ZooKeeper 앙상블 서버를 HBase 시작/정지의 일부로 시작/정지할지 여부를 알려줘요.

HBase가 ZooKeeper 앙상블을 관리할 때 ZooKeeper 구성을 conf/hbase-site.xml에 직접 지정할 수 있어요. ZooKeeper 구성 옵션은 ZooKeeper 옵션 이름 앞에 hbase.zookeeper.property를 붙여 HBase hbase-site.xml XML 구성 파일의 프로퍼티로 설정할 수 있어요. 예를 들어 ZooKeeper의 clientPort 설정은 hbase.zookeeper.property.clientPort 프로퍼티를 설정해 변경할 수 있어요. HBase가 사용하는 모든 기본값(ZooKeeper 구성 포함)은 hbase default configurations를 참고하세요. hbase.zookeeper.property 접두사를 찾으세요. ZooKeeper 구성의 전체 목록은 ZooKeeper의 zoo.cfg를 참고하세요. HBase는 zoo.cfg와 함께 배포되지 않으므로 적절한 ZooKeeper 다운로드의 conf 디렉터리를 찾아봐야 해요.

앙상블 서버를 적어도 hbase-site.xml의 hbase.zookeeper.quorum 프로퍼티로 나열해야 해요. 이 프로퍼티는 기본적으로 localhost의 단일 앙상블 멤버를 가리키는데, 완전 분산 HBase에는 적합하지 않아요(로컬 머신에만 바인딩되어 원격 클라이언트가 연결할 수 없음).

ZooKeeper를 몇 개 실행해야 할까요?

1개 노드만으로 구성된 ZooKeeper 앙상블을 실행할 수 있지만, 프로덕션에서는 3, 5 또는 7대 머신의 ZooKeeper 앙상블을 실행하는 것이 권장돼요. 앙상블 멤버가 많을수록 앙상블이 호스트 장애에 더 관대해져요. 또한 홀수 대의 머신을 실행하세요. ZooKeeper에서 짝수 개의 피어도 지원되지만 보통 사용되지 않아요. 짝수 크기의 앙상블은 홀수 크기의 앙상블보다 쿼럼을 형성하는 데 비례적으로 더 많은 피어가 필요하기 때문이에요. 예를 들어 4개 피어의 앙상블은 쿼럼을 형성하는 데 3개가 필요하고, 5개 앙상블도 쿼럼 형성에 3개가 필요해요. 따라서 5개 앙상블은 2개 피어의 장애를 허용해서, 1개 피어 다운만 허용하는 4개 앙상블보다 더 장애 허용적인 거예요.

각 ZooKeeper 서버에 약 1GB의 RAM을 주고, 가능하다면 전용 디스크를 주세요(전용 디스크는 성능 좋은 ZooKeeper 앙상블을 보장하는 데 가장 좋은 방법이에요). 아주 과부하가 큰 클러스터라면 ZooKeeper 서버를 RegionServer(DataNode와 TaskTracker)와 별개 머신에서 실행하세요.

예를 들어 HBase가 rs{1,2,3,4,5}.example.com 노드에서 ZooKeeper 쿼럼을 관리하게 하려면 포트 2222(기본값 2181)에 바인딩하고, conf/hbase-env.sh에서 HBASE_MANAGE_ZK가 주석 처리되었거나 true로 설정되어 있는지 확인한 다음 conf/hbase-site.xml을 편집하고 hbase.zookeeper.property.clientPort와 hbase.zookeeper.quorum을 설정하세요. 기본값이 ZooKeeper가 /tmp 아래에 데이터를 영속화하는데 시스템 재시작 시 자주 지워지므로 hbase.zookeeper.property.dataDir도 기본값이 아닌 다른 값으로 설정해야 해요. 아래 예시에서는 ZooKeeper가 /user/local/zookeeper에 영속화해요.

<configuration>
  ...
  <property>
    <name>hbase.zookeeper.property.clientPort</name>
    <value>2222</value>
    <description>Property from ZooKeeper's config zoo.cfg.
    The port at which the clients will connect.
    </description>
  </property>
  <property>
    <name>hbase.zookeeper.quorum</name>
    <value>rs1.example.com,rs2.example.com,rs3.example.com,rs4.example.com,rs5.example.com</value>
    <description>Comma separated list of servers in the ZooKeeper Quorum.
    For example, "host1.mydomain.com,host2.mydomain.com,host3.mydomain.com".
    By default this is set to localhost for local and pseudo-distributed modes
    of operation. For a fully-distributed setup, this should be set to a full
    list of ZooKeeper quorum servers. If HBASE_MANAGES_ZK is set in hbase-env.sh
    this is the list of servers which we will start/stop ZooKeeper on.
    </description>
  </property>
  <property>
    <name>hbase.zookeeper.property.dataDir</name>
    <value>/usr/local/zookeeper</value>
    <description>Property from ZooKeeper's config zoo.cfg.
    The directory where the snapshot is stored.
    </description>
  </property>
  ...
</configuration>

어떤 버전의 ZooKeeper를 사용해야 할까요?

새로운 버전일수록 좋아요. HBase 1.0.0부터 ZooKeeper 3.4.x가 필요해요.

ZooKeeper 유지보수

ZooKeeper Maintenance에 설명된 데이터 디렉터리 클리너를 반드시 설정하세요. 그렇지 않으면 몇 달 후 '재미있는' 문제가 생길 수 있어요. 즉 리더 재선거 시기에 수십만 개의 로그가 있는 디렉터리를 훑어야 한다면 zookeeper가 세션을 떨어뜨리기 시작할 수 있어요. 이 과정은 드물지만 머신이 내려가거나 딸꾹질할 때 때때로 발생해요.

기존 ZooKeeper 앙상블 사용

HBase가 관리하지 않는 기존 ZooKeeper 클러스터를 가리키려면 conf/hbase-env.sh에서 HBASE_MANAGES_ZK를 false로 설정하세요.

  ...
  # Tell HBase whether it should manage its own instance of ZooKeeper or not.
  export HBASE_MANAGES_ZK=false

다음으로 표준이 아니면 hbase-site.xml에서 앙상블 위치와 클라이언트 포트를 설정하세요.

HBase가 ZooKeeper를 관리할 때 일반 시작/정지 스크립트의 일부로 ZooKeeper 서버를 시작/정지해요. HBase 시작/정지와 독립적으로 ZooKeeper를 직접 실행하려면 다음을 수행하면 돼요.

${HBASE_HOME}/bin/hbase-daemons.sh {start,stop} zookeeper

이런 방식으로 HBase를 사용해 HBase와 무관한 ZooKeeper 클러스터를 띄울 수 있다는 점에 유의하세요. HBase 재시작 후에도 계속 켜져 있길 원한다면 HBASE_MANAGES_ZK를 false로 설정하기만 하면 돼요. 그러면 HBase가 종료될 때 ZooKeeper를 함께 끌지 않아요.

별도 ZooKeeper 클러스터 실행에 대한 자세한 내용은 ZooKeeper Getting Started Guide를 참고하세요. 또한 ZooKeeper 크기 조정에 대한 자세한 내용은 ZooKeeper Wiki 또는 ZooKeeper documentation을 참고하세요.

ZooKeeper와 SASL 인증

새로운 버전의 Apache HBase(>= 0.92)는 SASL 인증을 지원하는 ZooKeeper Quorum에 연결하는 것을 지원해요(ZooKeeper 3.4.0 이상 버전에서 사용 가능).

이 문서는 HBase가 ZooKeeper Quorum과 상호 인증하도록 설정하는 방법을 설명해요. ZooKeeper/HBase 상호 인증(HBASE-2418)은 완전한 보안 HBase 구성(HBASE-3025)의 일부로 필요해요. 설명의 단순화를 위해 이 섹션은 추가 구성(Secure HDFS와 Coprocessor 구성)을 무시해요. 학습의 용이함을 위해 HBase 관리 ZooKeeper 구성(스탠드얼론 ZooKeeper 쿼럼보다)으로 시작하는 것이 권장돼요.

운영체제 사전 준비

동작하는 Kerberos KDC 설정이 필요해요. ZooKeeper 서버를 실행할 각 $HOST에 대해 zookeeper/$HOST 프린시펄이 있어야 해요. 각 호스트에 대해 kadmin 또는 kadmin.local 도구의 ktadd 명령을 사용해 zookeeper/$HOST에 대한 서비스 키를 추가하고 이 파일을 $HOST에 복사하고, $HOST에서 zookeeper를 실행할 사용자만 읽을 수 있게 하세요. 아래에서 $PATH_TO_ZOOKEEPER_KEYTAB로 사용할 이 파일의 위치를 기록해 두세요.

마찬가지로 HBase 서버(master 또는 regionserver)를 실행할 각 $HOST에 대해 hbase/$HOST 프린시펄이 있어야 해요. 각 호스트에 대해 hbase/$HOST용 서비스 키를 담은 hbase.keytab이라는 keytab 파일을 추가하고, 이 파일을 $HOST에 복사하고, $HOST에서 HBase 서비스를 실행할 사용자만 읽을 수 있게 하세요. 아래에서 $PATH_TO_HBASE_KEYTAB으로 사용할 이 파일의 위치를 기록해 두세요.

HBase 클라이언트가 될 각 사용자에게도 Kerberos 프린시펄이 부여되어야 해요. 이 프린시펄에는 보통(HBase 서버와 달리 keytab 파일 대신) 이 사용자만 아는 비밀번호가 할당되어야 해요. 클라이언트 프린시펄의 maxrenewlife는 사용자가 HBase 클라이언트 프로세스를 완료할 수 있을 만큼 갱신될 수 있도록 설정해야 해요. 예를 들어 사용자가 최대 3일이 걸리는 장기 실행 HBase 클라이언트 프로세스를 실행한다면 kadmin에서 이 사용자의 프린시펄을 addprinc -maxrenewlife 3days로 만들 수 있어요. ZooKeeper 클라이언트와 서버 라이브러리는 주기적으로 깨어나 갱신을 수행하는 스레드를 실행해 자체 티켓 갱신을 관리해요.

HBase 클라이언트(예: hbase shell)를 실행할 각 호스트에서 HBase 홈 디렉터리의 conf 디렉터리에 다음 파일을 추가하세요.

Client {
  com.sun.security.auth.module.Krb5LoginModule required
  useKeyTab=false
  useTicketCache=true;
};

아래에서 이 JAAS 구성 파일을 $CLIENT_CONF로 부르겠어요.

HBase 관리 ZooKeeper 구성

zookeeper, master, regionserver를 실행할 각 노드에서 노드의 HBASE_HOME 디렉터리의 conf 디렉터리에 다음과 같은 JAAS 구성 파일을 만드세요.

Server {
  com.sun.security.auth.module.Krb5LoginModule required
  useKeyTab=true
  keyTab="$PATH_TO_ZOOKEEPER_KEYTAB"
  storeKey=true
  useTicketCache=false
  principal="zookeeper/$HOST";
};
Client {
  com.sun.security.auth.module.Krb5LoginModule required
  useKeyTab=true
  useTicketCache=false
  keyTab="$PATH_TO_HBASE_KEYTAB"
  principal="hbase/$HOST";
};

여기서 $PATH_TO_HBASE_KEYTAB와 $PATH_TO_ZOOKEEPER_KEYTAB 파일은 위에서 만든 것이고, $HOST는 그 노드의 호스트 이름이에요.

Server 섹션은 ZooKeeper 쿼럼 서버가 사용하고, Client 섹션은 HBase master와 regionserver가 사용해요. 이 파일의 경로는 아래의 hbase-env.sh 목록에서 $HBASE_SERVER_CONF 텍스트로 대체되어야 해요.

이 파일의 경로는 아래의 hbase-env.sh 목록에서 $CLIENT_CONF 텍스트로 대체되어야 해요.

hbase-env.sh를 수정해 다음을 포함하세요.

export HBASE_OPTS="-Djava.security.auth.login.config=$CLIENT_CONF"
export HBASE_MANAGES_ZK=true
export HBASE_ZOOKEEPER_OPTS="-Djava.security.auth.login.config=$HBASE_SERVER_CONF"
export HBASE_MASTER_OPTS="-Djava.security.auth.login.config=$HBASE_SERVER_CONF"
export HBASE_REGIONSERVER_OPTS="-Djava.security.auth.login.config=$HBASE_SERVER_CONF"

여기서 $HBASE_SERVER_CONF와 $CLIENT_CONF는 위에서 만든 JAAS 구성 파일의 전체 경로예요.

zookeeper, master, regionserver를 실행할 각 노드의 hbase-site.xml을 수정해 다음을 포함하세요.

<configuration>
  <property>
    <name>hbase.zookeeper.quorum</name>
    <value>$ZK_NODES</value>
  </property>
  <property>
    <name>hbase.cluster.distributed</name>
    <value>true</value>
  </property>
  <property>
    <name>hbase.zookeeper.property.authProvider.1</name>
    <value>org.apache.zookeeper.server.auth.SASLAuthenticationProvider</value>
  </property>
  <property>
    <name>hbase.zookeeper.property.kerberos.removeHostFromPrincipal</name>
    <value>true</value>
  </property>
  <property>
    <name>hbase.zookeeper.property.kerberos.removeRealmFromPrincipal</name>
    <value>true</value>
  </property>
</configuration>

여기서 $ZK_NODES는 ZooKeeper Quorum 호스트의 호스트 이름을 쉼표로 구분한 목록이에요.

적절한 호스트에서 다음 명령 집합 중 하나 이상을 실행해 hbase 클러스터를 시작하세요.

bin/hbase zookeeper start
bin/hbase master start
bin/hbase regionserver start

외부 ZooKeeper 구성

다음과 같은 JAAS 구성 파일을 추가하세요.

Client {
  com.sun.security.auth.module.Krb5LoginModule required
  useKeyTab=true
  useTicketCache=false
  keyTab="$PATH_TO_HBASE_KEYTAB"
  principal="hbase/$HOST";
};

여기서 $PATH_TO_HBASE_KEYTAB은 위에서 이 호스트에서 실행할 HBase 서비스를 위해 만든 keytab이고, $HOST는 그 노드의 호스트 이름이에요. 이 파일을 HBase 홈의 구성 디렉터리에 넣으세요. 아래에서 이 파일의 전체 경로를 $HBASE_SERVER_CONF로 부르겠어요.

hbase-env.sh를 수정해 다음을 포함하세요.

export HBASE_OPTS="-Djava.security.auth.login.config=$CLIENT_CONF"
export HBASE_MANAGES_ZK=false
export HBASE_MASTER_OPTS="-Djava.security.auth.login.config=$HBASE_SERVER_CONF"
export HBASE_REGIONSERVER_OPTS="-Djava.security.auth.login.config=$HBASE_SERVER_CONF"

master 또는 regionserver를 실행할 각 노드의 hbase-site.xml을 수정해 다음을 포함하세요.

<configuration>
  <property>
    <name>hbase.zookeeper.quorum</name>
    <value>$ZK_NODES</value>
  </property>
  <property>
    <name>hbase.cluster.distributed</name>
    <value>true</value>
  </property>
  <property>
    <name>hbase.zookeeper.property.authProvider.1</name>
    <value>org.apache.zookeeper.server.auth.SASLAuthenticationProvider</value>
  </property>
  <property>
    <name>hbase.zookeeper.property.kerberos.removeHostFromPrincipal</name>
    <value>true</value>
  </property>
  <property>
    <name>hbase.zookeeper.property.kerberos.removeRealmFromPrincipal</name>
    <value>true</value>
  </property>
</configuration>

여기서 $ZK_NODES는 ZooKeeper Quorum 호스트의 호스트 이름을 쉼표로 구분한 목록이에요.

또한 이 각 호스트에서 다음을 포함하는 JAAS 구성 파일을 만드세요.

Server {
  com.sun.security.auth.module.Krb5LoginModule required
  useKeyTab=true
  keyTab="$PATH_TO_ZOOKEEPER_KEYTAB"
  storeKey=true
  useTicketCache=false
  principal="zookeeper/$HOST";
};

여기서 $HOST는 각 Quorum 호스트의 호스트 이름이에요. 아래에서 이 파일의 전체 경로를 $ZK_SERVER_CONF로 부르겠어요.

각 ZooKeeper Quorum 호스트에서 다음으로 ZooKeeper를 시작하세요.

SERVER_JVMFLAGS="-Djava.security.auth.login.config=$ZK_SERVER_CONF" bin/zkServer start

적절한 노드에서 다음 명령 집합 중 하나 이상을 실행해 HBase 클러스터를 시작하세요.

bin/hbase master start
bin/hbase regionserver start

ZooKeeper 서버 인증 로그 출력

위 구성이 성공적이면 ZooKeeper 서버 로그에서 다음과 유사한 내용이 보일 거예요.

11/12/05 22:43:39 INFO zookeeper.Login: successfully logged in.
11/12/05 22:43:39 INFO server.NIOServerCnxnFactory: binding to port 0.0.0.0/0.0.0.0:2181
11/12/05 22:43:39 INFO zookeeper.Login: TGT refresh thread started.
11/12/05 22:43:39 INFO zookeeper.Login: TGT valid starting at:        Mon Dec 05 22:43:39 UTC 2011
11/12/05 22:43:39 INFO zookeeper.Login: TGT expires:                  Tue Dec 06 22:43:39 UTC 2011
11/12/05 22:43:39 INFO zookeeper.Login: TGT refresh sleeping until: Tue Dec 06 18:36:42 UTC 2011
..
11/12/05 22:43:59 INFO auth.SaslServerCallbackHandler:
  Successfully authenticated client: authenticationID=hbase/[email protected];
  authorizationID=hbase/[email protected].
11/12/05 22:43:59 INFO auth.SaslServerCallbackHandler: Setting authorizedID: hbase
11/12/05 22:43:59 INFO server.ZooKeeperServer: adding SASL authorization for authorizationID: hbase

ZooKeeper 클라이언트 인증 로그 출력

ZooKeeper 클라이언트 측(HBase master 또는 regionserver)에서 다음과 유사한 내용이 보일 거예요.

11/12/05 22:43:59 INFO zookeeper.ZooKeeper: Initiating client connection, connectString=ip-10-166-175-249.us-west-1.compute.internal:2181 sessionTimeout=180000 watcher=master:60000
11/12/05 22:43:59 INFO zookeeper.ClientCnxn: Opening socket connection to server /10.166.175.249:2181
11/12/05 22:43:59 INFO zookeeper.RecoverableZooKeeper: The identifier of this process is 14851@ip-10-166-175-249
11/12/05 22:43:59 INFO zookeeper.Login: successfully logged in.
11/12/05 22:43:59 INFO client.ZooKeeperSaslClient: Client will use GSSAPI as SASL mechanism.
11/12/05 22:43:59 INFO zookeeper.Login: TGT refresh thread started.
11/12/05 22:43:59 INFO zookeeper.ClientCnxn: Socket connection established to ip-10-166-175-249.us-west-1.compute.internal/10.166.175.249:2181, initiating session
11/12/05 22:43:59 INFO zookeeper.Login: TGT valid starting at:        Mon Dec 05 22:43:59 UTC 2011
11/12/05 22:43:59 INFO zookeeper.Login: TGT expires:                  Tue Dec 06 22:43:59 UTC 2011
11/12/05 22:43:59 INFO zookeeper.Login: TGT refresh sleeping until: Tue Dec 06 18:30:37 UTC 2011
11/12/05 22:43:59 INFO zookeeper.ClientCnxn: Session establishment complete on server ip-10-166-175-249.us-west-1.compute.internal/10.166.175.249:2181, sessionid = 0x134106594320000, negotiated timeout = 180000

처음부터 구성

이것은 현재 표준 Amazon Linux AMI에서 테스트됐어요. 먼저 위에서 설명한 대로 KDC와 프린시펄을 설정하세요. 다음으로 코드를 체크아웃하고 sanity check를 실행하세요.

git clone https://gitbox.apache.org/repos/asf/hbase.git
cd hbase
mvn clean test -Dtest=TestZooKeeperACL

그런 다음 위에서 설명한 대로 HBase를 구성하세요. target/cached_classpath.txt를 수동으로 편집하세요(아래 참고).

bin/hbase zookeeper &
bin/hbase master &
bin/hbase regionserver &

향후 개선

Fix target/cached_classpath.txt

표준 hadoop-core jar 파일을 target/cached_classpath.txt 파일의 HADOOP-7070 수정이 포함된 버전으로 재정의해야 해요. 다음 스크립트로 이 작업을 수행할 수 있어요.

echo `find ~/.m2 -name "*hadoop-core*7070*SNAPSHOT.jar"` ':' `cat target/cached_classpath.txt` | sed 's/ //g' > target/tmp.txt
mv target/tmp.txt target/cached_classpath.txt
JAAS 구성을 프로그래밍 방식으로 설정

이렇게 하면 HADOOP-7070을 고치는 별도 Hadoop jar의 필요성을 피할 수 있어요.

kerberos.removeHostFromPrincipal와 kerberos.removeRealmFromPrincipal 제거

ZooKeeper에 TLS 연결

Apache ZooKeeper는 전송 중 데이터를 암호화하기 위한 SSL/TLS 클라이언트 연결도 지원해요. ZooKeeper 앙상블이 HBase와 다른 호스트에서 실행되고 데이터를 와이어로 보내야 할 때 특히 유용해요.

Java 시스템 프로퍼티

ZooKeeper 클라이언트는 TLS 연결을 설정하기 위해 다음 Java 시스템 프로퍼티를 지원해요.

zookeeper.client.secure=true
zookeeper.clientCnxnSocket=org.apache.zookeeper.ClientCnxnSocketNetty
zookeeper.ssl.keyStore.location="/path/to/your/keystore"
zookeeper.ssl.keyStore.password="keystore_password"
zookeeper.ssl.trustStore.location="/path/to/your/truststore"
zookeeper.ssl.trustStore.password="truststore_password"

KeyStore 설정은 선택 사항이며 ZooKeeper 서버가 클라이언트 인증서를 요청할 때만 필요해요.

더 자세한 정보는 ZooKeeper SSL User Guide에서 찾을 수 있어요.

이것들은 HBase 명령줄에서 설정해야 하고 전체 Java 프로세스에서 유효한 표준 Java 프로퍼티예요. 같은 프로세스에서 실행되는 모든 ZooKeeper 클라이언트(coprocessor 포함)가 이걸 받아들여요.

ZooKeeper 3.8 버전부터 keystore와 truststore 비밀번호를 명령줄에 노출하지 않고 보호된 텍스트 파일에 저장하는 데 다음 두 프로퍼티가 유용해요.

zookeeper.ssl.keyStore.passwordPath=/path/to/secure/file
zookeeper.ssl.trustStore.passwordPath=/path/to/secure/file

HBase 구성

HBASE-28038을 추가함으로써 ZooKeeper 클라이언트 TLS 설정이 hbase-site.xml에서도 hbase.zookeeper.property 접두사를 통해 사용 가능해요. Java 시스템 프로퍼티와 달리 어떤 상황에서는 이것이 더 편리할 수 있어요.

<configuration>
  <property>
    <name>hbase.zookeeper.property.client.secure</name>
    <value>true</value>
  </property>
  <property>
    <name>hbase.zookeeper.property.clientCnxnSocket</name>
    <value>org.apache.zookeeper.ClientCnxnSocketNetty</value>
  </property>
  <property>
    <name>hbase.zookeeper.property.ssl.trustStore.location</name>
    <value>/path/to/your/truststore</value>
  </property>
  ...
</configuration>

이 설정들은 결국 Java 시스템 프로퍼티로 변환되는 편의 기능일 뿐이에요. 그래서 이전 포인트에서 언급한 것과 같은 규칙이 적용돼요.

더 알아보기 (Learn more)