简述
ZooKeeper 是 Apache 的一个顶级项目,为分布式应用提供高效、高可用的分布式协调服务。
ZooKeeper本质上是一个分布式的小文件存储系统。提供类似于文件系统目录树方式的数据存储,并且可以对书中的节点进行有效管理。从而用来维护和监控存储的数据的状态变化,通过监控这些数据状态的变化,实现基于数据的集群管理。
运行模式
ZooKeeper 运行模式有三种:单机模式、伪集群模式、集群模式
单机模式: ZooKeeper 只运行一台服务器上面,这种模式一般用于开发测试环境,用于节省机器数量,加上开发调试不需要特别好的稳定性
伪集群模式: 这是一种特殊的集群模式,即一台服务器上面部署多个ZooKeeper实例,当然这个时候就需要你这台服务器性能比较好。在这种情况下,我们需要通过不同的端口来启动ZooKeeper实例,以此来通过集群的方式对外提供服务。
这种模式下,我们只需要修改zoo.cfg下的同一个服务器不同端口连接地址即可
server.1=ip1:2888:3888
server.2=ip1:2889:3889
server.3=ip1:2890:3890
集群模式: Zookeeper集群 运行在一组机器上,一般三台以上的机器就可以组成集群了,组成ZooKeeper集群的每一台机器都会在内存中维护当前服务的状态,机器之间也会互相保持通信。
只要集群中过半的服务存活,就能正常对外提供服务,如果说当我们的leader挂掉了,在选举过程中是无法提供服务的,直到leader选举完成!
这种模式下,我们只需要修改zoo.cfg下的不同服务器的连接地址即可
server.1=ip1:2888:3888
server.2=ip2:2888:3888
server.3=ip3:2888:3888
Zookeeper集群有什么用
ZooKeeper 实现了高性能,高可靠性和有序的访问。高性能保证了ZooKeeper能应用在大型的分布式系统上,高可靠性保证它不会由于单一节点的故障而造成任何问题。有序的访问能保证客户端可以实现较为复杂的同步操作。
负载均衡
这里说的负载均衡是指软负载均衡。在分布式环境中,为了保证高可用性,通常同一个应用或同一个服务的提供方都会部署多份,来达到高可用。
命名服务
在分布式系统中,通过使用命名服务,客户端应用能够根据指定名字来获取资源或者服务的地址,提供者等信息。被命名的实体通常可以是集群中的机器,提供的服务地址、远程对象等这些我们可以统称为Name,其中比较常见的就是一些分布式服务框架中的服务地址列表。通过调用ZooKeeper提供创建节点的API,能够很容易创建一个全局唯一的Path,这个Path可以作为一个名称。
阿里巴巴集团开源的分布式服务框架Dubbo中使用ZooKeeper来作为其命名服务,维护全局的服务地址列表,点击这里查看Dubbo开源项目。
分布式协调
ZooKeeper中特有的Watcher注册与异步通知机制,能够实现分布式环境下不同系统之间的通知与协调,实现对数据变更的及时处理,使用方法通常是不同系统都对ZooKeeper同一个Znode进行注册,监听Znode的变化。
如果其中一个系统更新了Znode,那么另外系统也能够收到通知,并做出相应的处理。
集群管理
集群管理主要是包含其中两点:服务状态监听(退出和加入)、master选举。
服务状态监听: 所有机器在父目录下创建临时目录节点,监听父目录节点的子节点变化消息,如果有机器挂掉,这个机器与ZooKeeper的连接断开,这个创建的临时目录节点就会被删除,其他机器收到消息,某个服务下的节点目录被删除,就知道这个某个节点宕机。
如果有新的机器或者服务加入,会在该父目录节点下创建一个临时子节点,所有服务就会收到通知,有新的目录产生。
master选举: master选举是ZooKeeper中最为经典的应用场景了,在分布式环境中,相同的业务应用分布在不同的机器上,有的业务逻辑,通常只需要其中一台服务完成,然后其他服务共享,这样可以大幅度减少重复劳动,提高服务性能,比如 HDFS 中 Active NameNode 的选举。
通常情况下,我们可以选择常见的关系型数据库中的主键特性来实现,在成为Master的机器都想数据库中插入一条相同主键ID的记录,数据库会帮我们进行主键冲突检查,也就是说,只有一台机器能够插入成功,那么我们就认为向数据库中插入数据的机器就是Master
但是当我们的Master机器挂掉了,那么谁能够告诉我们Master挂掉了,关系型数据库是无法通知我们这个事情的,但是ZooKeeper可以做到。
ZooKeeper能够保证在分布式高并发情况下节点的创建一定能够保证全局唯一性,ZooKeeper将会保证客户端无法创建一个已经存在的数据单元节点。也就是说,如果同时有多个客户端请求创建同一个临时节点,那么最终一定只有一个客户端请求能够创建成功。利用这个特性,就能很容易的在分布式环境中进行Master选举了,成功创建该节点的客户端所在的机器就成为了Master,同时企业没有成功创建该节点的客户端,都会在该节点上注册一个子节点变更的Watcher,用于监控当前的Master机器是否存活,一旦发现当前的Master挂了,那么其他客户端将会重新进行Master选举,这样就实现了Master的动态选举。
ZooKeeper集群必须是奇数?
一个ZooKeeper集群通常由一组机器组成,一般是3台以上就可以组成一个可用的ZooKeeper集群了。只要集群中存在超过一半的机器能够正常工作,那么ZooKeeper集群就能正常对外提供服务。
在这里,有一个误区,就是为了让 ZooKeeper 群能够正确的选举出 leader 我们必须要把 ZooKeeper 集群服务器的数量设置为奇数,其实任意台的ZooKeeper都可以正常选举出Leader和运行。
关于集群服务数量中,ZooKeeper官方也给出了奇数的建议,而且基于ZooKeeper 过半以上存活服务可用 的特性,如果ZooKeeper需要对外提供服务,那么至少要保证有过半存活的机器能够正常工作,如果我们想要搭建一台允许挂点一定数量(N)的集群机器,那我们至少要部署 2*N+1
台服务器来搭建ZooKeeper集群。
容错率
从容错率来讲,我们要保证 过半以上存活的特性
如果我们允许挂掉1台服务,那我们至少要搭建(2*1+1
)台服务器,也是就3台服务器(3的半数为1.5,默认向下取整为1,半数以上那就是2)
如果我们允许挂掉2台服务,那我们至少要搭建(2*1+1
)台服务器,也是就5台服务器(5的半数为2.5,默认向下取整为2,半数以上那就是3)
同样我们部署六台机器,那么我们遵循过半以上存活服务可用的特性,同样也只能挂掉2台服务器,因为如果挂掉3台,无法遵循服务过半的特性
因此,我们可以从上面条件中看到,对于一个由6台服务器构成的ZooKeeper集群来说,和一个用5台服务器构成的ZooKeeper集群,在容灾能力上没有任何的显著优势,所以ZooKeeper集群 通常会设置成奇数台服务器即可
下载
下载地址:https://zookeeper.apache.org/releases.html
安装
ZooKeeper安装首先需要安装JDK,ZooKeeper的安装步骤在上一篇文章中介绍过,大家感兴趣的可以看一下:https://muxiaonong.blog.csdn.net/article/details/120543298
[centos@us-prod-sre-zookeeper-1 app]$ cd /data/app/ [centos@us-prod-sre-zookeeper-1 ~]$ mkdir -p /data/zookeeper [centos@us-prod-sre-zookeeper-2 app]$ cd /data/app/ [centos@us-prod-sre-zookeeper-2 ~]$ mkdir -p /data/zookeeper [centos@us-prod-sre-zookeeper-3 app]$ cd /data/app/ [centos@us-prod-sre-zookeeper-3 ~]$ mkdir -p /data/zookeeper [centos@us-prod-sre-zookeeper-1 app]$ tar zxf apache-zookeeper-3.5.7-bin.tar.gz [centos@us-prod-sre-zookeeper-2 app]$ tar zxf apache-zookeeper-3.5.7-bin.tar.gz [centos@us-prod-sre-zookeeper-3 app]$ tar zxf apache-zookeeper-3.5.7-bin.tar.gz [centos@us-prod-sre-zookeeper-1 app]$ mv apache-zookeeper-3.5.7-bin zookeeper [centos@us-prod-sre-zookeeper-2 app]$ mv apache-zookeeper-3.5.7-bin zookeeper [centos@us-prod-sre-zookeeper-3 app]$ mv apache-zookeeper-3.5.7-bin zookeeper
修改配置
配置主节点
- 当我们将conf下的 zoo_sample.cfg 文件复制并重命名为 zoo.cfg 文件后,通过 vim zoo.cfg命令对这个文件进行修改
[centos@us-prod-sre-zookeeper-1 conf]$ pwd /data/app/zookeeper/conf [centos@us-prod-sre-zookeeper-1 conf]$ cp zoo_sample.cfg zoo.cfg [centos@us-prod-sre-zookeeper-1 conf]$ grep -v "^$" zoo.cfg | grep -v "^#" tickTime=2000 initLimit=10 syncLimit=5 dataDir=/data/zookeeper clientPort=2181 server.1=10.0.3.113:2888:3888 server.2=10.0.3.121:2888:3888 server.3=10.0.3.217:2888:3888
- 在节点配置的dataDir指定的目录下面,创建一个myid文件,里面内容为一个数字,用来标识当前主机,$ZOOKEEPER_HOME/conf/zoo.cfg文件中配置的server.X,则myid文件中就输入这个数字X。(即在每个节点上新建并设置文件myid,其内容与zoo.cfg中的id相对应)这里master节点为 1
[centos@us-prod-sre-zookeeper-1 conf]$ mkdir -p /data/zookeeper [centos@us-prod-sre-zookeeper-1 conf]$ cd /data/zookeeper [centos@us-prod-sre-zookeeper-1 zookeeper]$ touch myid [centos@us-prod-sre-zookeeper-1 zookeeper]$ echo "1" > myid
- 设置日志(改为---每天一个log日志文件,而不是在同一个log文件中递增日志)
[centos@us-prod-sre-zookeeper-1 conf]$ pwd /data/app/zookeeper/conf [centos@us-prod-sre-zookeeper-1 conf]$ vim log4j.properties zookeeper.root.logger=INFO, CONSOLE 改为 zookeeper.root.logger=INFO, ROLLINGFILE log4j.appender.ROLLINGFILE=org.apache.log4j.RollingFileAppender 改为 log4j.appender.ROLLINGFILE=org.apache.log4j.DailyRollingFileAppender
- 修改脚本
[centos@us-prod-sre-zookeeper-1 bin]$ pwd /data/app/zookeeper/bin [centos@us-prod-sre-zookeeper-1 bin]$ vim zkEnv.sh ZOO_LOG_DIR="$ZOOKEEPER_PREFIX/logs" 改为 ZOO_LOG_DIR="$ZOOKEEPER_PREFIX/../logs" ZOO_LOG4J_PROP="INFO,CONSOLE" 改为 ZOO_LOG4J_PROP="INFO,ROLLINGFILE"
配置第二个节点
centos@us-prod-sre-zookeeper-2 ~]$ cd /data/zookeeper [centos@us-prod-sre-zookeeper-2 zookeeper]$ touch myid [centos@us-prod-sre-zookeeper-2 zookeeper]$ echo "2" > myid [centos@us-prod-sre-zookeeper-2 ~]$ cd /data/app/zookeeper/conf/ [centos@us-prod-sre-zookeeper-2 conf]$ vim zoo.cfg tickTime=2000 initLimit=10 syncLimit=5 dataDir=/data/zookeeper clientPort=2181 server.1=10.0.3.113:2888:3888 server.2=10.0.3.121:2888:3888 server.3=10.0.3.217:2888:3888
- 启动脚本和日志参考第一个节点设置
配置第三个节点
[centos@us-prod-sre-zookeeper-3 data]$ cd /data/zookeeper [centos@us-prod-sre-zookeeper-3 zookeeper]$ touch myid [centos@us-prod-sre-zookeeper-3 zookeeper]$ echo "3" > myid [centos@us-prod-sre-zookeeper-3 ~]$ cd /data/app/zookeeper/conf/ [centos@us-prod-sre-zookeeper-3 conf]$ vim zoo.cfg tickTime=2000 initLimit=10 syncLimit=5 dataDir=/data/zookeeper clientPort=2181 server.1=10.0.3.113:2888:3888 server.2=10.0.3.121:2888:3888 server.3=10.0.3.217:2888:3888
- 启动脚本和日志参考第一个节点设置
启动服务
- 在每个节点上$ZOOKEEPER_HOME目录下,运行 (这里的启动顺序为 master > slave1 > slave2 )
[centos@us-prod-sre-zookeeper-1 ~]$ cd /data/app/zookeeper/ [centos@us-prod-sre-zookeeper-1 zookeeper]$ bin/zkServer.sh start ZooKeeper JMX enabled by default Using config: /data/app/zookeeper/bin/../conf/zoo.cfg Starting zookeeper ... STARTED [centos@us-prod-sre-zookeeper-2 bin]$ cd /data/app/zookeeper/ [centos@us-prod-sre-zookeeper-2 zookeeper]$ bin/zkServer.sh start ZooKeeper JMX enabled by default Using config: /data/app/zookeeper/bin/../conf/zoo.cfg Starting zookeeper ... STARTED [centos@us-prod-sre-zookeeper-3 bin]$ cd /data/app/zookeeper/ [centos@us-prod-sre-zookeeper-3 zookeeper]$ bin/zkServer.sh start ZooKeeper JMX enabled by default Using config: /data/app/zookeeper/bin/../conf/zoo.cfg Starting zookeeper ... STARTED
-
查看启动状态,有一台leader,两台follower,表示启动成功。
[centos@us-prod-sre-zookeeper-1 zookeeper]$ bin/zkServer.sh status ZooKeeper JMX enabled by default Using config: /data/app/zookeeper/bin/../conf/zoo.cfg Client port found: 2181. Client address: localhost. Mode: follower [centos@us-prod-sre-zookeeper-2 zookeeper]$ bin/zkServer.sh status ZooKeeper JMX enabled by default Using config: /data/app/zookeeper/bin/../conf/zoo.cfg Client port found: 2181. Client address: localhost. Mode: leader [centos@us-prod-sre-zookeeper-3 zookeeper]$ bin/zkServer.sh status ZooKeeper JMX enabled by default Using config: /data/app/zookeeper/bin/../conf/zoo.cfg Client port found: 2181. Client address: localhost. Mode: follower
- 查看端口
[centos@us-prod-sre-zookeeper-1 ~]$ netstat -natp | egrep '(2888|3888)' (Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.) tcp6 0 0 10.0.3.113:3888 :::* LISTEN 11482/java tcp6 0 0 10.0.3.113:3888 10.0.3.121:62867 ESTABLISHED 11482/java tcp6 0 0 10.0.3.113:19417 10.0.3.121:2888 ESTABLISHED 11482/java tcp6 0 0 10.0.3.113:3888 10.0.3.217:49103 ESTABLISHED 11482/java [centos@us-prod-sre-zookeeper-2 ~]$ netstat -natp | egrep '(2888|3888)' (Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.) tcp6 0 0 10.0.3.121:2888 :::* LISTEN 13490/java tcp6 0 0 10.0.3.121:3888 :::* LISTEN 13490/java tcp6 0 0 10.0.3.121:62867 10.0.3.113:3888 ESTABLISHED 13490/java tcp6 0 0 10.0.3.121:2888 10.0.3.217:19021 ESTABLISHED 13490/java tcp6 0 0 10.0.3.121:2888 10.0.3.113:19417 ESTABLISHED 13490/java tcp6 0 0 10.0.3.121:3888 10.0.3.217:32301 ESTABLISHED 13490/java [centos@us-prod-sre-zookeeper-3 ~]$ netstat -natp | egrep '(2888|3888)' (Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.) tcp6 0 0 10.0.3.217:3888 :::* LISTEN 24942/java tcp6 0 0 10.0.3.217:32301 10.0.3.121:3888 ESTABLISHED 24942/java tcp6 0 0 10.0.3.217:49103 10.0.3.113:3888 ESTABLISHED 24942/java tcp6 0 0 10.0.3.217:19021 10.0.3.121:2888 ESTABLISHED 24942/java
端口说明
3888:是选举用的
2888:是leader接受write请求
评论