# ZooKeeper

分布式 Apache HBase 安装依赖于正在运行的 ZooKeeper 集群。所有参与节点和客户端都需要能够访问正在运行的 ZooKeeper 集合。 Apache HBase 默认为您管理 ZooKeeper“集群”。它将启动和停止 ZooKeeper 集合作为 HBase 启动/停止过程的一部分。您还可以独立于 HBase 管理 ZooKeeper 集合，只需将 HBase 指向它应该使用的集群。要切换 ZooKeeper 的 HBase 管理，请使用 _conf / hbase-env.sh_ 中的`HBASE_MANAGES_ZK`变量。此变量默认为`true`，告诉 HBase 是否启动/停止 ZooKeeper 整体服务器作为 HBase 启动/停止的一部分。

当 HBase 管理 ZooKeeper 集合时，您可以直接在 _conf / hbase-site.xml_ 中指定 ZooKeeper 配置。通过在 ZooKeeper 选项名称前加上`hbase.zookeeper.property`，可以将 ZooKeeper 配置选项设置为 HBase _hbase-site.xml_ XML 配置文件中的属性。例如，可以通过设置`hbase.zookeeper.property.clientPort`属性来更改 ZooKeeper 中的`clientPort`设置。对于 HBase 使用的所有默认值，包括 ZooKeeper 配置，请参见 [hbase 默认配置](#hbase_default_configurations)。查找`hbase.zookeeper.property`前缀。有关 ZooKeeper 配置的完整列表，请参阅 ZooKeeper 的 _zoo.cfg_ 。 HBase 不附带 _zoo.cfg_ ，因此您需要在的 ZooKeeper 下载中浏览 _conf_ 目录。

您必须至少使用`hbase.zookeeper.quorum`属性列出 _hbase-site.xml_ 中的整体服务器。此属性默认为`localhost`上的单个集合成员，它不适用于完全分布式 HBase。 （它仅绑定到本地计算机，远程客户端将无法连接）。

> 我应该运行多少 ZooKeepers？
> 
> 您可以运行仅包含 1 个节点的 ZooKeeper 集合，但在生产环境中，建议您运行 3 个，5 个或 7 个机器的 ZooKeeper 集合;一个集群的成员越多，对主机失败的容错度就越高。此外，运行奇数台机器。在 ZooKeeper 中，支持偶数个对等体，但通常不使用它，因为偶数大小的集合比奇数大小的集合所需要更多的对等点来支持合法集群数量。例如，具有 4 个对等体的集合需要 3 来形成仲裁，而具有 5 的集合也需要 3 来形成仲裁。因此，5 的集合允许 2 个对等体失败，因此比 4 的集合更容错，而不是仅允许 1 个服务器崩溃。
> 
> 为每个 ZooKeeper 服务器提供大约 1GB 的 RAM，如果可能的话，给它自己的专用磁盘（专用磁盘是确保高性能 ZooKeeper 集合的最佳方法）。对于负载很重的集群，在 RegionServers（DataNodes 和 TaskTrackers）的不同机器上运行 ZooKeeper 服务器。

例如，让 HBase 管理节点 _rs {1,2,3,4,5} .example.com_ 上的 ZooKeeper 仲裁，绑定到端口 2222（默认为 2181），确保`HBASE_MANAGE_ZK`为在 _conf / hbase-env.sh_ 中注释掉或设置为`true`，然后编辑 _conf / hbase-site.xml_ 并设置`hbase.zookeeper.property.clientPort`和`hbase.zookeeper.quorum`。您还应该将`hbase.zookeeper.property.dataDir`设置为默认值以外的值，因为默认情况下 ZooKeeper 会在 _/ tmp_ 下保留数据，这通常会在系统重启时清除。在下面的示例中，我们将 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 维护](https://zookeeper.apache.org/doc/r3.1.2/zookeeperAdmin.html#sc_maintenance)中描述的数据目录清理器，否则您可能会在几个月内遇到“有趣”问题;例如，如果zookeeper必须运行成千上万的日志目录，zookeeper就可以删除会话，而这种情况在领导者重新选举时间周围不会执行 - 这个过程很少见，但有时会运行，无论是因为机器掉落还是间接性耽误，这个都会运行。

## 196.使用现有的 ZooKeeper 集合

要将 HBase 指向现有的 ZooKeeper 集群（不受 HBase 管理的集群），请将 _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 服务器作为常规启动/停止脚本的一部分。如果您想自己运行 ZooKeeper，独立于 HBase 启动/停止，您将执行以下操作

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

请注意，您可以使用hbase以这种方式启动与 HBase 无关的 ZooKeeper 集群。只要确保将`HBASE_MANAGES_ZK`设置为`false`，如果希望它在 HBase 重启时保持不变，那么当 HBase 关闭时，它不会使 ZooKeeper 失效。

有关运行不同 ZooKeeper 集群的更多信息，请参阅 ZooKeeper [入门指南](https://hadoop.apache.org/zookeeper/docs/current/zookeeperStarted.html)。另外，有关 ZooKeeper 大小调整的更多信息，请参阅 [ZooKeeper Wiki](https://wiki.apache.org/hadoop/ZooKeeper/FAQ#A7) 或 [ZooKeeper 文档](https://zookeeper.apache.org/doc/r3.3.3/zookeeperAdmin.html#sc_zkMulitServerSetup)。

## 197.使用 ZooKeeper 进行 SASL 身份验证

较新版本的 Apache HBase（＆gt; = 0.92）将支持连接到支持 SASL 身份验证的 ZooKeeper Quorum（可在 ZooKeeper 版本 3.4.0 或更高版本中使用）。

介绍如何设置 HBase 与 ZooKeeper Quorum 进行相互认证。 ZooKeeper / HBase 相互认证（ [HBASE-2418](https://issues.apache.org/jira/browse/HBASE-2418) ）是完整安全 HBase 配置（ [HBASE-3025](https://issues.apache.org/jira/browse/HBASE-3025) ）的一部分。为简化说明，本节忽略了所需的其他配置（安全 HDFS 和协处理器配置）。建议首先使用 HBase 管理的 ZooKeeper 配置（而不是独立的 ZooKeeper 配置），以便于学习。

### 197.1。操作系统先决条件

您需要有一个有效的 Kerberos KDC 设置。对于将运行 ZooKeeper 服务器的每个`$HOST`，您应该具有`zookeeper/$HOST`原则。对于每个这样的主机，为`zookeeper/$HOST`添加一个服务密钥（使用`kadmin`或`kadmin.local`工具的`ktadd`命令）并将此文件复制到`$HOST`，并使其仅对将在`$HOST`上运行 zookeeper 的用户可读。请注意此文件的位置，我们将在下面使用它作为 _ $ PATH_TO_ZOOKEEPER _KEYTAB_ 。

同理，对于将运行 HBase 服务器（主服务器或区域服务器）的每个`$HOST`，您应该有一个原则：`hbase/$HOST`。对于每个主机，添加一个名为 _hbase.keytab_ 的密钥表文件，其中包含`hbase/$HOST`的服务密钥，将此文件复制到`$HOST`，并使其仅对将`$HOST`运行 HBase 服务的用户可读。注意这个文件的位置，我们将在下面使用它作为 _ $ PATH_TO_HBASE _KEYTAB_ 。

每个将成为 HBase 客户端的用户也应获得 Kerberos 主体。此主体通常应该为其分配密码（与 HBase 服务器相反，密钥表文件），只有该用户知道。应设置客户端的主体`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_ 。

### 197.2。 HBase 管理的 ZooKeeper 配置

在将运行 zookeeper，master 或 regionserver 的每个节点上，在节点的 _HBASE _HOME_ 目录的 conf 目录中创建一个 [JAAS](http://docs.oracle.com/javase/7/docs/technotes/guides/security/jgss/tutorials/LoginConfigFile.html) 配置文件，如下所示：

```
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 主服务器和区域服务器使用。此文件的路径应替换下面 _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 
```

### 197.3。外部 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 服务在此主机上运行的密钥表，`$HOST`是该节点的主机名。把它放在 HBase home 的配置目录中。我们将此文件的完整路径名称称为 _ $ 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 主机上启动 ZooKeepers：

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

通过在相应节点上运行以下一组或多组命令来启动 HBase 集群：

```
bin/hbase master start
bin/hbase regionserver start 
```

### 197.4。 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/ip-10-166-175-249.us-west-1.compute.internal@HADOOP.LOCALDOMAIN;
  authorizationID=hbase/ip-10-166-175-249.us-west-1.compute.internal@HADOOP.LOCALDOMAIN.
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 
```

### 197.5。 ZooKeeper 客户端身份验证日志输出

在 ZooKeeper 客户端（HBase 主服务器或区域服务器）上，您应该看到类似于以下内容的内容：

```
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 
```

### 197.6。从 Scratch 配置

这已经在当前的标准 Amazon Linux AMI 上进行了测试。首先如上所述设置 KDC 和主体。下一个检查代码并运行完整性检查。

```
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 & 
```

### 197.7。未来的改进

#### 197.7.1。修复 target / cached_classpath.txt

您必须使用包含 HADOOP-7070 修复程序的版本覆盖`target/cached_classpath.txt`文件中的标准 hadoop-core jar 文件。您可以使用以下脚本执行此操作：

```
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 
```

#### 197.7.2。以编程方式设置 JAAS 配置

这将避免需要一个单独的 Hadoop jar 来修复 [HADOOP-7070](https://issues.apache.org/jira/browse/HADOOP-7070) 。

#### 197.7.3。消除`kerberos.removeHostFromPrincipal`和`kerberos.removeRealmFromPrincipal`