如何启动ZooKeeper

如何启动ZooKeeper,第1张

Zookeeper的启动入口在orgapachezookeeperserverquorumQuorumPeerMain。
在这个类的main方法里进入了zookeeper的启动过程,首先我们会解析配置文件,即zoocfg和myid。
这样我们就知道了dataDir和dataLogDir指向哪儿了,然后就可以启动日志清理任务了(如果配置了的话)。
DatadirCleanupManager purgeMgr = new DatadirCleanupManager(config
getDataDir(), configgetDataLogDir(), config
getSnapRetainCount(), configgetPurgeInterval());
purgeMgrstart();
接下来会初始化ServerCnxnFactory,这个是用来接收来自客户端的连接的,也就是这里启动的是一个tcp server。在Zookeeper里提供两种tcp server的实现,一个是使用java原生NIO的方式,另外一个是使用Netty。默认是java nio的方式,一个典型的Reactor模型。因为java nio编程并不是本文的重点,所以在这里就只是简单的介绍一下。
//首先根据配置创建对应factory的实例:NIOServerCnxnFactory 或者 NettyServerCnxnFactory
ServerCnxnFactory cnxnFactory = ServerCnxnFactorycreateFactory();
//初始化配置
cnxnFactoryconfigure(configgetClientPortAddress(),configgetMaxClientCnxns());
创建几个SelectorThread处理具体的数据读取和写出。
先是创建ServerSocketChannel,bind等
thisss = ServerSocketChannelopen();
sssocket()setReuseAddress(true);
sssocket()bind(addr);
ssconfigureBlocking(false);
然后创建一个AcceptThread线程来接收客户端的连接。
这一部分就是处理客户端请求的模块了,如果遇到有客户端请求的问题可以看看这部分。
接下来就进入初始化的主要部分了,首先会创建一个QuorumPeer实例,这个类就是表示zookeeper集群中的一个节点。初始化QuorumPeer的时候有这么几个关键点:
1 初始化FileTxnSnapLog,这个类主要管理Zookeeper中的 *** 作日志(WAL)和snapshot。
2 初始化ZKDatabase,这个类就是Zookeeper的目录结构在内存中的表示,所有的 *** 作最后都会映射到这个类上面来。
3 初始化决议validator(QuorumVerifier->QuorumMaj) (其实这一步,是在配置)。这一步是从zoocfg的servern这一部分初始化出集群的成员出来,有哪些需要参与投票(follower),有哪些只是observer。还有决定half是多少等,这些都是zookeeper的核心。在这一步,对于每个节点会初始化一个QuorumServer对象,并且放到allMembers,votingMembers,observingMembers这几个map里。而且这里也对参与者的个数进行了一些判断。
4 leader选举 这一步非常重要,也是zookeeper里最复杂而最精华的一部分。

按照 docker搭建zookeeper集群 中步骤,安装完docker,配置好三台容器后,启动zookeeper环境。发现两台正常,一台报Notification timeout的日志。
而异常的原因是cannot assign requested address。该问题要么ip、port不通要么就是开启监听的server地址和发送消息的地址不对。

查看源码位置,发现在QuorumCnxManagerjava文件中抛的异常

找到异常,去上下看看是否有迹可循
然后,去日志看下绑定的ip、port是什么。发现Slave1的日志里打印出了信息

2018-06-15 01:28:53,612 [myid:3] - INFO [Slave2/1721704:3890:QuorumCnxManager$Listener@534] - My election bind port: Slave2/1721704:3890

我的zoocfg server配置如下

server1=Master:2888:3888

server2=Slave1:2889:3889

server3=Slave2:2890:3890

参考“艾伦蓝”的博客介绍了

serverA=B:C:D: 其中 A 是一个数字,表示这个是第几号服务器; B 是这个服务器的 ip 地址;C 表示的是这个服务器与集群中的 Leader 服务器交换信息的端口;D 表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,而这个端口就是用来执行选举时服务器相互通信的端口。 如果是伪集群的配置方式,由于 B 都是一样,所以不同的 Zookeeper 实例通信端口号不能一样,所以要给它们分配不同的端口号。

也就是说我本地绑定的端口是server3的端口。(看日志感觉应该起的server2的3889才对!)

剩下的工作就是看看zookeeper配置文件如何加载,为什么解析的不正确!

回到刚才的源码,获取addr的地方:

addr = selfquorumPeersget(selfgetId())electionAddr;

查看QuorumPeerConfigjava发现quorumPeers存的是server1,2,3的信息。那id是哪来的?

public long getId() {

        return myid;

    }

myid又是从哪里来的?
这个myid是解析myid的文件来的。

莫非是这个myid还要和server#的值必须匹配起来?

server2的myid必须是2。

查看Slave1和Slave2的myid文件,果然Slave1 写的3,Slave2写的2。

以上!得出结论修改Slave1和Slave2的myid文件为2,3。

问题解决!!

发现ZooKeeper重启,并且在选主,主成功选出来之后,集群显示正常,但数秒之后,又开始重启,进入上述现象的循环。

查看ZK日志后,发现选举出的leader节点,loadsnapshot的时候,报Java堆内存不足的错误: javalangOutOfMemory: Java heap space

与此同时,follower节点报错: Unexpected exception causing shutdown while sock Follower is ahead of the leader

查看ZK data目录/var/lib/zookeeper/version-2,发现snapshot文件超过3G

ZK的java堆内存设置的是4G,load 3G的snapshot,在内存展开之后,超出内存上限。导致出错。

1 增大ZK堆内存大小

2 将所有ZK节点上的version-2目录重命名后,创建一个空的version-2目录,重新启动并初始化

需分析snapshot为何突然增大,ZK空间,大部分被Hive任务创建的节点占用。需要找到存在问题的Hive SQL,并禁止业务提交不合理的SQL(如导致笛卡尔积的SQL)。

Zookeeper 的视图结构是一个树形结构,树上的每个节点称之为数据节点(即 ZNode),每个ZNode 上都可以保存数据,同时还可以挂载子节点。并且Zookeeper的根节点为 "/"。

在 Zookeeper 中,每个数据节点都是有生命周期的,其生命周期的长短取决于数据节点的节点类型。在 Zookeeper 中有如下几类节点:

每个数据节点中除了存储了数据内容之外,还存储了数据节点本身的一些状态信息(State)。

在Zookeeper 中,事务是指能够改变 Zookeeper 服务器状态的 *** 作,我们也称之为事务 *** 作或更新 *** 作,一般包括数据节点创建与删除、数据节点内容更新和客户端会话创建与失效等 *** 作。对于每一个事务请求,Zookeeper 都会为其分配一个全局唯一的事务ID,用 ZXID 来表示,通常是一个 64 位的数字。每一个 ZXID 对应一次更新 *** 作,从这些 ZXID 中可以间接地识别出 Zookeeper 处理这些更新 *** 作请求的全局顺序。

ZXID 是一个 64 位的数字,其中低 32 位可以看作是一个简单的单调递增的计数器,针对客户端的每一个事务请求,Leader 服务器在产生一个新的事务 Proposal 的时候,都会对该计数器进行加 1 *** 作;而高 32 位则代表了 Leader 周期 epoch 的编号,每当选举产生一个新的 Leader 服务器,就会从这个 Leader 服务器上取出其本地日志中最大事务 Proposal 的 ZXID,并从该 ZXID 中解析出对应的 epoch 值,然后再对其进行加 1 *** 作,之后就会以此编号作为新的 epoch,并将低 32 位置 0 来开始生成新的 ZXID。

Zookeeper 中为数据节点引入了版本的概念,每个数据节点都具有三种类型的版本信息(在上面的状态信息中已经介绍了三种版本信息代表的意思),对数据节点的任何更新 *** 作都会引起版本号的变化。其中我们以 dataVersion 为例来说明。在一个数据节点被创建完毕之后,节点的dataVersion 值是 0,表示的含义是 ”当前节点自从创建之后,被更新过 0 次“。如果现在对该节点的数据内容进行更新 *** 作,那么随后,dataVersion 的值就会变成 1。即表示的是对数据节点的数据内容的变更次数。

版本的作用是用来实现乐观锁机制中的 “写入校验” 的。例如,当要修改数据节点的数据内容时,带上版本号,如果数据节点的版本号与传入的版本号相等,就进行修改,否则修改失败。

Zookeeper 提供了分布式数据的发布/订阅功能。一个典型的发布/订阅模型系统定义了一种一对多的订阅关系,能够让多个订阅者同时监听某一个主题对象,当这个主题对象自身状态变化时,会通知所有订阅者,使它们能够做出相应的处理。在 Zookeeper 中,引入了 Watcher 机制来实现这种分布式的通知功能。Zookeeper 允许客户端向服务端注册一个 Watcher 监听,当服务端的一些指定事件触发了这个 Watcher,那么就会向指定客户端发送一个事件通知来实现分布式的通知功能。

从上图可以看出 Zookeeper 的 Watcher 机制主要包括客户端线程、客户端WatchMananger 和 Zookeeper 服务器三部分。在具体工作流程上,简单地讲,客户端在向 Zookeeper 服务器注册 Watcher 的同时,会将 Watcher 对象存储在客户端的 WatchMananger 中。当 Zookeeper 服务器端触发 Watcher 事件后,会向客户端发送通知,客户端线程从 WatchManager 中取出对应的 Watcher 对象来执行回调逻辑。

Watcher是一个接口,任何实现了Watcher接口的类就是一个新的Watcher。Watcher内部包含了两个枚举类:KeeperState、EventType

:客户端接收到的相关事件通知中只包含状态及类型等信息,不包括节点变化前后的具体内容,变化前的数据需业务自身存储,变化后的数据需调用get等方法重新获取;

上面讲到zookeeper客户端连接的状态和zookeeper对znode节点监听的事件类型,下面我们来讲解如何建立zookeeper的watcher监听。在zookeeper中采用zkgetChildren(path, watch)、zkexists(path, watch)、zkgetData(path, watcher, stat)这样的方式为某个znode注册监听。

下表以node-x节点为例,说明调用的注册方法和可监听事件间的关系:

Zookeeper 中提供了一套完善的 ACL(Access Control List)权限控制机制来保障数据的安全。

ACL 由三部分组成,分别是:权限模式(Scheme)、授权对象(ID)和权限(Permission),通常使用“scheme: ​id:permission”来标识一个有效的ACL 信息。下面分别介绍:

174、ACL 超级管理员

zookeeper的权限管理模式有一种叫做super,该模式提供一个超管可以方便的访问任何权限的节点

假设这个超管是:super:admin,需要先为超管生成密码的密文

那么打开zookeeper目录下的/bin/zkServersh服务器脚本文件,找到如下一行:

这就是脚本中启动zookeeper的命令,默认只有以上两个配置项,我们需要加一个超管的配置项

那么修改以后这条完整命令变成了

之后启动zookeeper,输入如下命令添加权限

在服务器集群初始化阶段,我们以 3 台机器组成的服务器集群为例,当有一台服务器server1 启动的时候,它是无法进行 Leader 选举的,当第二台机器 server2 也启动时,此时这两台服务器已经能够进行互相通信,每台机器都试图找到一个 Leader,于是便进入了 Leader 选举流程。

在zookeeper运行期间,leader与非leader服务器各司其职,即便当有非leader服务器宕机或新加入,此时也不会影响leader,但是一旦leader服务器挂了,那么整个集群将暂停对外服务,进入新一轮leader选举,其过程和启动时期的Leader选举过程基本一致。

假设正在运行的有server1、server2、server3三台服务器,当前leader是server2,若某一时刻leader挂了,此时便开始Leader选举。选举过程如下:

observer角色特点:

为了使用observer角色,在任何想变成observer角色的配置文件中加入如下配置:

并在所有server的配置文件中,配置成observer模式的server的那行配置追加:observer,例如:

查看zookeeperout,是否有错误信息。错误信息并不一定输出到屏幕上。
今天我师妹也遇到了这个问题,我执行jps,发现zookeeper并没有启动,于是检查了下out文件发现是配置文件错误。

ZooKeeper 在硬盘满后,无法再次启动,抛出Last transaction was partial
Bug见: >

1、首先需要登陆你的linux服务器,用cd 命令切换到/etc/rcd/initd/目录下。

2、接着用touch zookeeper创建一个文件。

3、然后为这个文件添加可执行权限chmod +x zookeeper。

4、接着用vi zookeeper来编辑这个文件。

5、接着在zookeeper里面输入如下内容。

6、然后保存退出。先按esc,再按:键盘,接这个输入wq即可保存退出。

7、这个时候就可以用service zookeeper 显示start/stop即可查看是否启动停止zookeeper服务了。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/yw/13383203.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-07-25
下一篇 2023-07-25

发表评论

登录后才能评论

评论列表(0条)

保存