基本原理
部署安装
部署假设3个节点,ip分别为A,B,C
在用户zookeeper用户下安装
# 增加用户,并赋予其密码
$ adduser zookeeper
$ passwd zookeeper # ur password for zookeeper user
# 赋予用户可以 sudo的权限
$ chmod u+w /etc/sudoers
$ vim /etc/sudoers
# 找到 `root ALL=(ALL) ALL`这行,并在下面添加 erick
zookeeper ALL=(ALL) ALL
$ chmod u-w /etc/sudoers
# 切换到 zookeeper用户
$ su - zookeeper
从zookeeper中下载zookeeper,然后将其导入3个节点中中的路径或者:
$ wget http://archive.apache.org/dist/zookeeper/zookeeper-3.4.10/zookeeper-3.4.10.tar.gz
$ cd /home/erick
# 存放软件目录 & 安装目录 & 日志目录
$ mkdir install && mkdir software && mkdir logs
然后解压到software中:
$ tar -zxvf zookeeper-3.4.10 -C ~/software
$ cd ~/software
$ ln -s zookeeper-3.4.10 zookeeper
配置
cd zookeeper
$ mkdir tmp
$ cp conf/zoo_sample.cfg conf/zoo.cfg
$ mkdir -p /home/zookeeper/data/zookeeper
$ mkdir -p /home/zookeeper/logs/zookeeper
$ vim conf/zoo.cfg
tickTime=2000
dataDir=/home/erick/data/zookeeper
dataLogDir=/home/erick/logs/zookeeper
clientPort=2181
initLimit=10
syncLimit=5
server.1=A:2888:3888
server.2=B:2888:3888
server.3=C:2888:3888
然后在 dataDir目录新建myid文件,将相应的id写入到其中:
echo 1 > myid
echo 2 > myid
echo 3 > myid
1.最后启动
./zkServer.sh start
./zkServer.sh status
操作使用(java)
新建maven工程
org.apache.zookeeper
zookeeper
3.4.6
package LIHAO;
/**
* Created by Administrator on 2017/12/5.
*/
import java.io.IOException;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
public class Test {
// 会话超时时间,设置为与系统默认时间一致
private static final int SESSION_TIMEOUT = 30 * 1000;
// 创建 ZooKeeper 实例
private ZooKeeper zk;
// 创建 Watcher 实例
private Watcher wh = new Watcher() {
/**
* Watched事件
*/
public void process(WatchedEvent event) {
System.out.println("WatchedEvent >>> " + event.toString());
}
};
// 初始化 ZooKeeper 实例
private void createZKInstance() throws IOException {
// 连接到ZK服务,多个可以用逗号分割写
zk = new ZooKeeper("A:2181,B:2182,C:2183", Test.SESSION_TIMEOUT, this.wh);
}
private void ZKOperations() throws IOException, InterruptedException, KeeperException {
System.out.println("\n1. 创建 ZooKeeper 节点 (znode : zoo2, 数据: myData2 ,权限: OPEN_ACL_UNSAFE ,节点类型: Persistent");
zk.create("/zoo2", "myData2".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println("\n2. 查看是否创建成功: ");
System.out.println(new String(zk.getData("/zoo2", this.wh, null)));// 添加Watch
// 前面一行我们添加了对/zoo2节点的监视,所以这里对/zoo2进行修改的时候,会触发Watch事件。
System.out.println("\n3. 修改节点数据 ");
zk.setData("/zoo2", "shanhy20160310".getBytes(), -1);
// 这里再次进行修改,则不会触发Watch事件,这就是我们验证ZK的一个特性“一次性触发”,也就是说设置一次监视,只会对下次操作起一次作用。
System.out.println("\n3-1. 再次修改节点数据 ");
zk.setData("/zoo2", "shanhy20160310-ABCD".getBytes(), -1);
System.out.println("\n4. 查看是否修改成功: ");
System.out.println(new String(zk.getData("/zoo2", false, null)));
System.out.println("\n5. 删除节点 ");
zk.delete("/zoo2", -1);
System.out.println("\n6. 查看节点是否被删除: ");
System.out.println(" 节点状态: [" + zk.exists("/zoo2", false) + "]");
}
private void ZKClose() throws InterruptedException {
zk.close();
}
public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
Test dm = new Test();
dm.createZKInstance();
dm.ZKOperations();
dm.ZKClose();
}
}
客户端操作
性能测试
jdk安装
$ chmod +x install/jdk-7u80-linux-x64.rpm
$ sudo rpm -ivh install/jdk-7u80-linux-x64.rpm
$ java -version
java version "1.7.0_80"
Java(TM) SE Runtime Environment (build 1.7.0_80-b15)
Java HotSpot(TM) 64-Bit Server VM (build 24.80-b11, mixed mode)
$ which java
/usr/bin/java
$ ln -s /usr/java/jdk1.7.0_80 software/jdk1.7.0_80
$ ln -s /home/eagle/software/jdk1.7.0_80 software/java
$ vim ~/.bash_profile
# User specific environment and startup programs
export JAVA_HOME=/home/eagle/software/java
export CLASSPATH=.:$JAVA_HOME/lib/tools.jar$JAVA_HOME/lib/dt.jar
export PATH=$JAVA_HOME/bin:$PATH
$ source ~/.bash_profile
zookeeper选举
这篇主要分析leader的选择机制,zookeeper提供了三种方式:
LeaderElection AuthFastLeaderElection FastLeaderElection 默认的算法是FastLeaderElection,所以这篇主要分析它的选举机制。
三个核心选举原则:
(1)Zookeeper集群中只有超过半数以上的服务器启动,集群才能正常工作;
(2)在集群正常工作之前,myid小的服务器给myid大的服务器投票,直到集群正常工作,选出Leader;
(3)选出Leader之后,之前的服务器状态由Looking改变为Following,以后的服务器都是Follower。
下面以一个简单的例子来说明整个选举的过程:
假设有五台服务器组成的Zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的。
假设这些服务器从id1-5,依序启动:
因为一共5台服务器,只有超过半数以上,即最少启动3台服务器,集群才能正常工作。
(1)服务器1启动,发起一次选举。
服务器1投自己一票。此时服务器1票数一票,不够半数以上(3票),选举无法完成;
服务器1状态保持为LOOKING;
(2)服务器2启动,再发起一次选举。
服务器1和2分别投自己一票,此时服务器1发现服务器2的id比自己大,更改选票投给服务器2;
此时服务器1票数0票,服务器2票数2票,不够半数以上(3票),选举无法完成;
服务器1,2状态保持LOOKING;
(3)服务器3启动,发起一次选举。
与上面过程一样,服务器1和2先投自己一票,然后因为服务器3id最大,两者更改选票投给为服务器3;
此次投票结果:服务器1为0票,服务器2为0票,服务器3为3票。此时服务器3的票数已经超过半数(3票),服务器3当选Leader。
服务器1,2更改状态为FOLLOWING,服务器3更改状态为LEADING;
(4)服务器4启动,发起一次选举。
此时服务器1,2,3已经不是LOOKING状态,不会更改选票信息。交换选票信息结果:服务器3为3票,服务器4为1票。
此时服务器4服从多数,更改选票信息为服务器3;
服务器4并更改状态为FOLLOWING;
(5)服务器5启动,同4一样投票给3,此时服务器3一共5票,服务器5为0票;
服务器5并更改状态为FOLLOWING;
最终Leader是服务器3,状态为LEADING;
其余服务器是Follower,状态为FOLLOWING。