Zookeeper安装(本地,伪分布式,集群)
概述
ZooKeeper是一个分布式开源框架,提供了协调分布式应用的基本服务,它向外部应用暴露一组通用服务——分布式同步(Distributed Synchronization)、命名服务(Naming Service)、集群维护(Group Maintenance)等,简化分布式应用协调及其管理的难度,提供高性能的分布式服务。ZooKeeper本身可以以Standalone模式安装运行,不过它的长处在于通过分布式ZooKeeper集群(一个Leader,多个Follower),基于一定的策略来保证ZooKeeper集群的稳定性和可用性,从而实现分布式应用的可靠性。
本地模式安装 :本人linux下的JDK版本是1.8
下载地址:https://mirror.bit.edu.cn/apache/ 找到zookeeper 选择对应版本下载即可。 3.5.5版本开始要下载 bin.tar.gz 的包。
1.下载并解压 zookeeper-3.4.13.tar.gz
tar -zxvf zookeeper-3.4.13.tar.gz -C /mysoft/
2.修改配置文件
cp zoo_sample.cfg zoo.cfg
修改以下参数。将zookeeper的数据存储指定到文件夹,创建文件夹 mkdir zkData
3.启动zookeeper ,停止使用 bin/zkServer.sh stop
bin/zkServer.sh start
查看运行状态
bin/zkServer.sh status
4.启动zookeeper客户端 (可以使用可视化工具 PrettyZoo)
bin/zkCli.sh
退出使用 quit ,连接其他客户端 zkCli.sh -serve 127.0.0.1(IP):2182(port) 这样子来连接
5.zookeeper 配置文件
# The number of milliseconds of each tick # 心跳时间2秒 # 客户端与服务器或者服务器与服务器之间维持心跳, # 也就是每个tickTime时间就会发送一次心跳。 # 通过心跳不仅能够用来监听机器的工作状态, # 还可以通过心跳来控制Flower跟Leader的通信时间, # 默认情况下FL的会话时常是心跳间隔的两倍。 tickTime=2000 # The number of ticks that the initial # synchronization phase can take # 集群中的follower服务器(F)与leader服务器(L)之间 # 初始连接时能容忍的最多心跳数(tickTime的数量)。 # tickTime * 10 =20秒没通讯就认为挂了 initLimit=10 # The number of ticks that can pass between # sending a request and getting an acknowledgement # 集群中flower服务器(F)跟leader(L) # 服务器之间的请求和答应最多能容忍的心跳数。 # tickTime * 5 =10秒没通讯就认为挂了 syncLimit=5 # the directory where the snapshot is stored. # do not use /tmp for storage, /tmp here is just # example sakes. # 数据存放位置 dataDir=/mysoft/zookeeper-3.4.13/zkData # the port at which the clients will connect # 客户端连接的接口,客户端连接zookeeper服务器的端口, # zookeeper会监听这个端口,接收客户端的请求访问!这个端口默认是2181。 clientPort=2181 # the maximum number of client connections. # increase this if you need to handle more clients #maxClientCnxns=60 # # Be sure to read the maintenance section of the # administrator guide before turning on autopurge. # # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance # # The number of snapshots to retain in dataDir #autopurge.snapRetainCount=3 # Purge task interval in hours # Set to "0" to disable auto purge feature #autopurge.purgeInterval=1
zookeeper 日志的配置地址在conf/目录下的log4j.properties文件中,该文件中有一个配置为“zookeeper.log.dir=.”,表示log4j日志文件在与执行程序(zkServer.sh)在同一目录下。当执行zkServer.sh 时,在该文件夹下会产生zookeeper.out日志文件,可以通过日志文件查看运行信息。
伪分布式安装:
1.解压完安装包后,进入zookeeper/conf/目录下,将改目录下的zoo_sample.cfg配置文件拷贝3份,依次 zoo1.cfg zoo2.cfg zoo3.cf。使用vim编辑zoo1.cfg zoo2.cfg zoo3.cfg这三个配置文件。
clientPort = ?, 分别将三个配置文件修改为2181.2182.2183 修改dataDir的路径,分别为zkData1. zkData2. zkData3,并且再对应服务上的zookeeper-3.4.13目录下创建文件夹 dataDir=/mysoft/zookeeper-3.4.13/zkData 文件结尾添加以下信息,我这里是准备部署3台,所以只有3条信息 server.1=IP:2888(数据同步端口):3888(Leader选举端口) server.2=IP:2889:3889 server.3=IP:2890:3890
server.A=B:C:D:其中 A 是一个数字,表示这个是第几号服务器;B 是这个服务器的 ip 地址;C 表示的是这个服务器与集群中的 Leader 服务器交换信息的端口;D 表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,而这个端口就是用来执行选举时服务器相互通信的端口。如果是伪集群的配置方式,由于 B 都是一样,所以不同的 Zookeeper 实例通信端口号不能一样,所以要给它们分配不同的端口号。
2.在各data文件下创建名为myid的文件,文件内容对应服务器编号
touch myid
3.写入服务器编号,也就是1中server.1(2.3)的对应值
echo 1 > zkDdata1/myid echo 2 > zkDdata2/myid echo 3 > zkDdata3/myid
4.依次启动服务,服务按照次序启动,启动时的选举算法是依次投票,这里的leader顺理就是2号配置文件启动的服务。其他的都是fllower,当启动第一台服务器的时候查看状态是不可用的,应为集群中节点未在半数以上。 集群中奇数和偶数对故障的容忍度是一致的....所以建议配置奇数个,并不是必须奇数...
sh zkServer.sh start /mysoft/zookeeper-3.4.13/conf/zoo1.cfg sh zkServer.sh start /mysoft/zookeeper-3.4.13/conf/zoo2.cfg sh kServer.sh start /mysoft/zookeeper-3.4.13/conf/zoo3.cfg
5.查看状态 记得关闭防火墙哦
sh zkServer.sh status /mysoft/zookeeper-3.4.13/conf/zoo1.cfg sh zkServer.sh status /mysoft/zookeeper-3.4.13/conf/zoo2.cfg sh zkServer.sh status /mysoft/zookeeper-3.4.13/conf/zoo3.cfg
启动客户端 sh zkCli.sh -server 127.0.0.1:port
伪分布式安装就是在一台机器上配置多个配置文件,根据不同的配置文件来启动,而真正的分布式下就是将配置文件安装在各自服务器下。要注意server的配置
基于 Java API 初探 zookeeper 的使用:
先来简单看一下API的使用:
public class ConnectionDemo { public static void main(String[] args) { try { final CountDownLatch countDownLatch=new CountDownLatch(1); ZooKeeper zooKeeper= new ZooKeeper("192.168.254.135:2181," + "192.168.254.136:2181,192.168.254.137:2181", 4000, new Watcher() { @Override public void process(WatchedEvent event) { if(Event.KeeperState.SyncConnected==event.getState()){ //如果收到了服务端的响应事件,连接成功 countDownLatch.countDown(); } } }); System.out.println(zooKeeper.getState());//CONNECTING countDownLatch.await(); System.out.println(zooKeeper.getState());//CONNECTED //添加节点 zooKeeper.create("/zk-wuzz","0".getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT); Thread.sleep(1000); Stat stat=new Stat(); //得到当前节点的值 byte[] bytes=zooKeeper.getData("/zk-wuzz",null,stat); System.out.println(new String(bytes)); // 0 //修改节点值 zooKeeper.setData("/zk-wuzz","1".getBytes(),stat.getVersion()); //得到当前节点的值 byte[] bytes1=zooKeeper.getData("/zk-wuzz",null,stat); System.out.println(new String(bytes1)); // 1 zooKeeper.delete("/zk-wuzz",stat.getVersion()); zooKeeper.close(); System.in.read(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (KeeperException e) { e.printStackTrace(); } } }
节点状态信息stat:
节点除了存储数据内容以外,还存储了数据节点本身的一些状态信息,通过get命令可以获得状态信息 的详细内容
版本-保证分布式数据原子性,zookeeper为数据节点引入了版本的概念,每个数据节点都有三类版本信息,对数据节点任何更新操作 都会引起版本号的变化
版本有点和我们经常使用的乐观锁类似。这里有两个概念说一下,一个是乐观锁,一个是悲观锁。version属性就是用来实现乐观锁机制的“写入校验
- 悲观锁:是数据库中一种非常典型且非常严格的并发控制策略。假如一个事务A正在对数据进行处理, 那么在整个处理过程中,都会将数据处于锁定状态,在这期间其他事务无法对数据进行更新操作。
- 乐观锁:乐观锁和悲观锁正好想法,它假定多个事务在处理过程中不会彼此影响,因此在事务处理过程 中不需要进行加锁处理,如果多个事务对同一数据做更改,那么在更新请求提交之前,每个事务都会首 先检查当前事务读取数据后,是否有其他事务对数据进行了修改。如果有修改,则回滚事务
Scheme权限模式:
Zookeeper提供以下权限模式,所谓权限模式,就是使用什么样的方式来进行授权。
- world:默认方式,相当于全部都能访问。
- auth:代表已经认证通过的用户(cli中可以通过addauth digest user:pwd 来添加当前上下文中的 授权用户)
- digest:即用户名:密码这种方式认证,这也是业务系统中最常用的。用 username:password 字符 串来产生一个MD5串,然后该串被用来作为ACL ID。认证是通过明文发送username:password 来 进行的,当用在ACL时,表达式为username:base64 ,base64是password的SHA1摘要的编码。
- ip:通过ip地址来做权限控制,比如 ip:192.168.1.1 表示权限控制都是针对这个ip地址的。也可以 针对网段 ip:192.168.1.1/24,此时addr中的有效位与客户端addr中的有效位进行比对。
ID授权对象:
指权限赋予的用户或一个指定的实体,不同的权限模式下,授权对象不同
- Id ipId1 = new Id("ip", "192.168.190.1");
- Id ANYONE_ID_UNSAFE = new Id("world", "anyone");
Permission权限类型:
指通过权限检查后可以被允许的操作,create /delete /read/write/admin
- Create 允许对子节点Create 操作
- Read 允许对本节点GetChildren 和GetData 操作
- Write 允许对本节点SetData 操作
- Delete 允许对子节点Delete 操作
- Admin 允许对本节点setAcl 操作
权限模式(Schema)和授权对象主要用来确认权限验证过程中使用的验证策略: 比如ip地址、 digest:username:password,匹配到验证策略并验证成功后,再根据权限操作类型来决定当前客户 端的访问权限。
在控制台上实现权限操作:
在Zookeeper中提供了ACL相关的命令如下。
getAcl getAcl <path> 读取ACL权限 setAcl setAcl <path> <acl> 设置ACL权限 addauth addauth <scheme> <auth> 添加认证用户
word 方式:
其中, cdrwa,分别对应 create . delete read write admin
IP 模式:
在ip模式中,首先连接到zkServer的命令需要使用如下方式 :./zkCli.sh -server 192.168.1.101:2181
接着按照IP的方式操作如下
[zk: 192.168.1.101:2181(CONNECTED) 0] create /ip-model Created /ip-model [zk: 192.168.1.101:2181(CONNECTED) 1] setAcl /ip-model ip:127.0.0.1:cdrwa,ip:192.168.1.101:cdrwa [zk: 192.168.1.101:2181(CONNECTED) 2] getAcl /ip-model 'ip,'127.0.0.1 : cdrwa 'ip,'192.168.1.101 : cdrwa [zk: 192.168.1.101:2181(CONNECTED) 3]
Auth 模式:
auth模式的操作如下
[zk: 192.168.1.101:2181(CONNECTED) 3] create /auth Node already exists: /auth [zk: 192.168.1.101:2181(CONNECTED) 4] addauth digest wuzz:123456 # 增加授权用户,明 文用户名和密码,zk会对密码加密 [zk: 192.168.1.101:2181(CONNECTED) 5] setAcl /auth auth:wuzz:cdrwa # 授予权限 [zk: 192.168.1.101:2181(CONNECTED) 6] getAcl /auth 'digest,'wuzz:Fltcg4qLglrVEdzI6xEj0S2T81g= : cdrwa [zk: 192.168.1.101:2181(CONNECTED) 7] [zk: 192.168.1.101:2181(CONNECTED) 7]
当我们退出当前的会话后,再次连接,执行如下操作,会提示没有权限
[zk: 192.168.1.101:2181(CONNECTED) 1] getAcl /auth Insufficient permission : /auth [zk: 192.168.1.101:2181(CONNECTED) 2]
这时候,我们需要重新授权。
Digest 模式:
使用语法,会发现使用方式和Auth模式相同: setAcl /digest digest:用户名:密码:权限
但是有一个不一样的点,密码需要用加密后的,否则无法被识别。 密码: 用户名和密码加密后的字符串。 使用下面程序生成密码
public static void main(String[] args) throws Exception { String up="wuzz:wuzz"; byte[] digest=MessageDigest.getInstance("SHA1").digest(up.getBytes()); String encodeString=Base64.getEncoder().encodeToString(digest); System.out.println(encodeString); }
得到:jedGVhVe3zXQqXeid/w95w5MeCE=
再回到client上进行如下操作
[zk: 192.168.1.101:2181(CONNECTED) 10] [zk: 192.168.1.101:2181(CONNECTED) 10] create /digest Created /digest [zk: 192.168.1.101:2181(CONNECTED) 11] setAcl /digest digest:wuzz:jedGVhVe3zXQqXeid/w95w5MeCE=:cdrwa [zk: 192.168.1.101:2181(CONNECTED) 12] getAcl /digest 'digest,'wuzz:jedGVhVe3zXQqXeid/w95w5MeCE= : cdrwa [zk: 192.168.1.101:2181(CONNECTED) 13]
当退出当前会话后,需要再次授权才能访问/digest节点
[zk: 192.168.1.101:2181(CONNECTED) 2] get /digest Insufficient permission : /digest [zk: 192.168.1.101:2181(CONNECTED) 3] addauth digest wuzz:wuzz [zk: 192.168.1.101:2181(CONNECTED) 4] get /digest null [zk: 192.168.1.101:2181(CONNECTED) 5]