Zookeeper 集群由三种角色组成:Leader、Follower 和 Observer。每种角色在集群中的职责和行为各不相同。下面详细介绍 Follower 和 Observer 的区别,并结合代码示例说明它们的具体实现和应用。
Follower 和 Observer 的区别
-
Follower:
- 参与选举:Follower 参与 Leader 选举过程。当 Leader 出现故障时,Follower 会参与新的 Leader 选举。
- 处理写请求:Follower 接收客户端的写请求,并将其转发给 Leader 进行处理。Leader 将写请求同步到多数派 Follower 后,返回写操作的结果。
- 处理读请求:Follower 可以独立处理读请求,从而减轻 Leader 的负担。
- 数据一致性:Follower 保持与 Leader 的数据一致性,确保集群中的数据副本一致。
-
Observer:
- 不参与选举:Observer 不参与 Leader 选举过程。即使 Leader 出现故障,Observer 也不会参与新的 Leader 选举。
- 处理写请求:Observer 接收客户端的写请求,并将其转发给 Leader 进行处理,但不会参与写请求的投票过程。
- 处理读请求:Observer 可以独立处理读请求,从而减轻 Leader 和 Follower 的负担。
- 数据一致性:Observer 保持与 Leader 的数据一致性,但不会参与事务的投票过程,因此不会影响集群的写吞吐量。
代码示例
以下示例展示了如何配置 Zookeeper 集群中的 Follower 和 Observer 节点,并说明它们的配置差异。
1. Zookeeper 配置文件(zoo.cfg)
假设我们有一个包含 5 个节点的 Zookeeper 集群,其中 3 个节点作为 Follower,2 个节点作为 Observer。
Follower 配置(zoo1.cfg, zoo2.cfg, zoo3.cfg)
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/var/lib/zookeeper
clientPort=2181
# 集群节点配置
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888
server.4=zoo4:2888:3888:observer
server.5=zoo5:2888:3888:observer
Observer 配置(zoo4.cfg, zoo5.cfg)
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/var/lib/zookeeper
clientPort=2181
# 集群节点配置
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888
server.4=zoo4:2888:3888:observer
server.5=zoo5:2888:3888:observer
2. 使用 Curator 客户端进行读写操作
以下代码示例展示了如何使用 Apache Curator 客户端库进行读写操作,分别连接到 Follower 和 Observer 节点。
添加 Maven 依赖
在 pom.xml 中添加 Curator 客户端的依赖:
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.2.0</version>
</dependency>
示例代码
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
public class ZookeeperClientExample {
private static final String ZK_FOLLOWER_ADDRESS = "zoo1:2181,zoo2:2181,zoo3:2181";
private static final String ZK_OBSERVER_ADDRESS = "zoo4:2181,zoo5:2181";
public static void main(String[] args) throws Exception {
// 连接到 Follower 节点
CuratorFramework followerClient = CuratorFrameworkFactory.newClient(ZK_FOLLOWER_ADDRESS, new ExponentialBackoffRetry(1000, 3));
followerClient.start();
// 执行写操作
String path = "/example/path";
String data = "Hello, Zookeeper!";
followerClient.create().creatingParentsIfNeeded().forPath(path, data.getBytes());
System.out.println("Data written to Follower: " + data);
// 执行读操作
byte[] readData = followerClient.getData().forPath(path);
System.out.println("Data read from Follower: " + new String(readData));
// 连接到 Observer 节点
CuratorFramework observerClient = CuratorFrameworkFactory.newClient(ZK_OBSERVER_ADDRESS, new ExponentialBackoffRetry(1000, 3));
observerClient.start();
// 执行读操作
readData = observerClient.getData().forPath(path);
System.out.println("Data read from Observer: " + new String(readData));
// 关闭客户端
followerClient.close();
observerClient.close();
}
}
详细解释
-
Follower 配置:
- 在
zoo.cfg文件中配置 Follower 节点。Follower 节点参与 Leader 选举,并处理读写请求。 - 配置示例中,
server.1到server.3为 Follower 节点。
- 在
-
Observer 配置:
- 在
zoo.cfg文件中配置 Observer 节点。Observer 节点不参与 Leader 选举,但可以处理读请求,并将写请求转发给 Leader。 - 配置示例中,
server.4和server.5为 Observer 节点,配置时需要在节点地址后添加:observer标识。
- 在
-
Curator 客户端:
- 使用
CuratorFrameworkFactory.newClient创建 Curator 客户端实例,分别连接到 Follower 和 Observer 节点。 - 通过
create().forPath方法在 Follower 节点上执行写操作,并通过getData().forPath方法在 Follower 和 Observer 节点上执行读操作。
- 使用
总结
Zookeeper 中的 Follower 和 Observer 节点在职责上有所区别。Follower 参与 Leader 选举,并处理读写请求;Observer 不参与 Leader 选举,但可以处理读请求,并将写请求转发给 Leader。通过合理配置 Follower 和 Observer 节点,可以提高 Zookeeper 集群的读写性能和可用性。以上代码示例展示了如何配置和使用 Follower 和 Observer 节点,并通过 Curator 客户端进行读写操作。