分布式环境的特点
- 分布性 —> 计算机在空间上随意分布,分布情况会随时变动
- 并发性 —> 程序运行过程中,并发性操作是很常见的。比如同一个分布式系统中的多个节点,同时访问一个共享资源。数据库、分布式存储
- 无序性 —> 进程之间的消息通信,会出现顺序不一致问题(缺乏全局时钟)
- 对等性 —> 计算机没有主/从之分,每个节点都是对等的
- 故障总会发生
布式环境下面临的问题
- 网络通信 —> 网络本身的不可靠性
- 网络分区(脑裂) —> 当网络发生异常导致分布式系统中部分节点之间的网络延时不断增大,最终导致只有部分节点能够正常通信
- 三态 —> 成功、失败、超时
- 分布式事务 —> 怎么保证 ACID(原子性、一致性、隔离性、持久性)
- 中心化和去中心化
- 冷备或者热备
- 集群选举
分布式架构存在的问题
![](https://i-blog.csdnimg.cn/blog_migrate/aed73cd56935e5efb33f0e67da786dbc.jpeg)
-
问题一:数据同步问题
3台服务器都有数据库连接的配置文件,如果配置更改怎么保证每个节点的数据一致性? -
问题二:任务执行顺序问题
三个服务都是相同的,怎么保证一个task任务只在一台服务器(一个节点)上执行? -
问题三: master选举问题
如果其中一个服务器挂了,其他服务器如何发现并接替这个服务器正在执行的任务? -
问题四:事务一致性问题
存在共享资源,对于这个集群每个节点的访问权限是公平的,那么如何保障互斥性、安全性(和多线程安全问题类似)?
CAP/BASE理论
-
CAP
- C 一致性( Consistency): 所有节点上的数据,时刻保持一致
- A 可用性(Availability):每个请求都能够收到一个响应,无论响应成功或者失败
- P 分区容错 (Partition-tolerance):表示系统出现脑裂以后,可能导致某些server与集群中的其他机器失去联系
由于分区容错是一定存在的,所以我们能够达到的状态只有两种 —> CP / AP
CAP理论仅适用于原子读写的Nosql场景,不适用于数据库系统
CAP理论并不适用于数据库事务 ,虽然XA事务可以保证数据库在分布式系统下的ACID特性,但是会带来性能方面的影响(用户能接受的请求响应时间大约5秒左右); -
BASE
- Basically available : 分布式系统出现不可预知故障时,允许损失部分可用性。
例如:- 响应时间上的损失(由于网络故障,响应时间增加1~2秒)
- 功能损失(降级页面)
- Soft-state: 允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体性能,即允许系统不同节点的数据副本之间进行数据同步的过程存在延时
- Eventually consistent: 系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性
- Basically available : 分布式系统出现不可预知故障时,允许损失部分可用性。
-
zookeeper是一个开源的分布式协调服务,也是分布式数据一致性的解决方案
zookeeper能做什么
-
数据的发布/订阅
配置中心 —> 集中式管理和数据的动态更新- 长轮询
- push和pull相结合的方式
- 客户端启动时主动到zookeeper同步数据
- 客户端向服务器端注册自己需要关注的节点。一旦节点数据发生变化,那么服务器端就会向客户端发送watcher事件通知。客户端收到通知后,主动到服务器端获取更新后的数据
-
负载均衡
dubbo利用了zookeeper机制实现负载均衡 -
命名服务
-
master选举
kafka、hadoop、hbase 等 -
分布式队列
- 通过getChildren获取指定根节点下的所有子节点,子节点就是任务
- 确定自己节点在子节点中的顺序
- 如果自己不是最小的子节点,那么监控比自己小的上一个子节点,否则处于等待
- 接收watcher通知,重复流程
-
分布式锁
- redis实现
setNX 如果key存在,则设置value失败,并会返回0;如果 key不存在,则设置成功,并返回 1 - mysql唯一索引实现
create table (id , methodname …) methodname增加唯一索引
insert 一条数据XXX delete 语句删除这条记录 - mysql 锁实现
select * from xxxx where … for update; - zookeeper实现
- 方案一
利用节点名称的唯一性来实现(当锁释放时候所有客户端都被唤醒,但仅仅有一个客户端得到锁,在高并发下有可能会产生惊群效应) - 方案二
利用临时顺序节点实现- 让所有客户端都去/lock目录下创建临时顺序节点,如果创建的客户端发现自身创建节点序列号是/lock/目录下最小的节点,则获得锁。
- 否则,监视比自己创建节点的序列号小的上一个节点进入等待
- 解锁,将自身创建的节点删除
- 方案一
- redis实现
zookeeper的特性
- 顺序一致性
对于来自客户端的每一个更新请求,zookeeper都会分配一个全局唯一的递增编号,这个编号反应了所有事务操作的先后顺序。 - 原子性
所有的事务请求的处理结果在整个集群中的所有机器上的应用情况是一致的,也就是说,要么整个集群中的所有机器都成功应用了某一事务、
要么全都不应用 - 可靠性
一旦服务器成功应用了某一个事务数据,并且对客户端做了响应,那么这个数据在整个集群中一定是同步并且保留下来的 - 实时性
一旦一个事务被成功应用,客户端就能够立即从服务器端读取到事务变更后的最新结果;(zookeeper仅仅保证在一定时间内,近实时) - 单一视图
任意客户端看到的服务器数据模型都是一致的 - 高性能
Zookeeper把所有的节点数据都存储在内存中,并直接服务于客户端所有非事务请求,因此尤其适用于以读操作为主的应用场景。
zookeeper集群角色
-
角色解析
zookeeper集群, 包含三种角色: leader / follower /observer-
Leader
- 处理所有写请求,事务请求的唯一调度者和处理者,保证集群事务处理的顺序性(follower收到的写请求全部转发给leader处理)
- 接受所有follower的提案请求,并统一协调发起提案的投票(写请求的数据是否同步成功需要半数以上follower投票通过,然后返回给客户端事务是否成功)
- 与follower同步数据(将写请求在leader上处理成功的数据分发给follower)
-
Follower
- 处理客户端非事务请求,以及转发事务请求给leader服务器(处理读请求转发写请求)
- 参与事务请求提议(proposal)的投票 (客户端的一个事务请求,需要半数服务器投票通过以后leader才能进行commit; leader会发起一个提案,要求follower投票)
- 参与leader选举的投票(选举新leader)
- 从leader节点同步数据(启动以后自动同步)
-
Observer
- 处理客户端非事务请求
- 不参与投票。 只接收投票结果
- 从leader节点同步数据(启动以后自动同步)
- 可以帮助解决zookeeper的扩展性(如果集群增加follower由于 zookeeper的数据变更需要半数以上服务器投票通过,会造成网络增加投票成本导致zookeeper写性能下降)
-
-
集群角色关系图
-
集群配置
-
在zoo.cfg里面增加
peerType=observer server.1=192.168.11.129:2181:3181:observer server.2=192.168.11.131:2181:3181 server.3=192.168.11.135:2181:3181
server.id=host:port:port
id的取值范围: 1~255; 用id来标识该机器在集群中的机器序号
2181是zookeeper的端口; //3306
3181表示leader选举的端口 -
创建myid
在每一个服务器的dataDir目录下创建一个myid的文件,文件就一行数据,数据内容是每台机器对应的server ID的数字 -
启动zookeeper
sh zkServer.sh {start|start-foreground|stop|restart|status|upgrade|print-cmd}
-
zookeeper客户端连接
sh zkCli.sh -server ip:port
-
zoo.cfg配置文件解析
- tickTime=2000 zookeeper中最小的时间单位长度 (ms)
- initLimit=10 follower节点启动后与leader节点完成数据同步的时间(实际的时间 = tickTime * initLimit)
- syncLimit=5 leader节点和follower节点进行心跳检测的最大延时时间(实际的时间 = tickTime * syncLimit)
- dataDir=/tmp/zookeeper 表示zookeeper服务器存储快照文件的目录
- dataLogDir 表示配置 zookeeper事务日志的存储路径,默认指定在dataDir目录下(不写默认放在dataDir目录下)
- clientPort 表示客户端和服务端建立连接的端口号: 2181
数据模型
zookeeper的数据模型和文件系统类似,每一个节点称为:znode,是zookeeper中的最小数据单元。
每一个znode上都可以保存数据和挂载子节点,从而构成一个层次化的属性结构。
节点特性:
- 持久化节点 : 节点创建后会一直存在zookeeper服务器上,直到主动删除
- 持久化有序节点 :每个节点都会为它的一级子节点维护一个顺序
- 临时节点 : 临时节点的生命周期和客户端的会话保持一致。当客户端会话失效,该节点自动删除(临时节点下不可以创建子节点)
- 临时有序节点 : 在临时节点上多了一个顺序性特性
同一节点下,子节点名称不能相同
回话状态
NOT_CONNECTED —> CONNECTING —> CONNECTED —> CLOSED
Watcher
![](https://i-blog.csdnimg.cn/blog_migrate/7a6a810853fd63f7bcc30e7d533426a3.jpeg)
-
zookeeper提供了分布式数据发布/订阅功能,zookeeper允许客户端向服务器注册一个watcher监听。当服务器端的节点触发指定事件的时候
会触发watcher。服务端会向客户端发送一个事件通知 -
watcher的通知是一次性,一旦触发一次通知后,该watcher就失效,如果需要永久监听,则需要反复注册(第三方框架封装了永久监听的功能)
-
如何注册事件机制 通过这三个操作来绑定事件 :getData、Exists、getChildren
ACL
-
zookeeper提供控制节点访问权限的功能,用于有效的保证zookeeper中数据的安全性
其特性如下:- ZooKeeper的权限控制是基于每个znode节点的,需要对每个节点设置权限
- 每个znode支持设置多种权限控制方案和多个权限
- 子节点不会继承父节点的权限,客户端无权访问某节点,但可能可以访问它的子节点
-
ACL 权限控制,使用:schema:id :permission 来标识(权限方案、授权对象、授权什么),主要涵盖 3 个方面
-
Schema 是权限控制方案,分为四种:
- world —>只有一个用户:anyone,代表所有人(默认)
- ip —> 使用IP地址认证
- auth —> 使用已添加认证的用户认证
- digest —> 使用“用户名:密码”方式认证
-
授权对象ID是指,权限赋予的用户或者一个实体。它的值根据Schema的不同而不同
-
permission指具体权限,分为五种
- CREATE —> 可以创建子节点
- DELETE —> 可以删除子节点(仅下一级节点)
- READ —> 可以读取节点数据及显示子节点列表
- WRITE —> 可以设置节点数据
- ADMIN —> 可以设置节点访问控制列表权限
-
-
命令举例
setAcl /node2 ip:192.168.100.1:cdrwa #设置IP:192.168.100.1 拥有所有权限 create /node10 data10 digest:hylexus:f4Myrgy6YlaWdo4lvv///2jgEDI=:crwad ```zookeeper的命令操作
zookeeper的命令操作
-
创建节点
create [-s] [-e] path data acl
-s 表示节点是否有序
-e 表示是否为临时节点
默认情况下,是持久化节点 -
获得指定 path的信息
get path [watch]
-
修改节点 path对应的data
set path data [version] # version : 版本号,要么不写,要么和上一次查询出的版本号一致 (乐观锁的概念)
-
删除节点
delete path [version] # version : 版本号,要么不写,要么和上一次查询出的版本号一致 (乐观锁的概念)
znode节点状态
cversion = 0 //子节点的版本号
aclVersion = 0 //表示acl的版本号,修改节点权限
dataVersion = 1 //表示的是当前节点数据的版本号
czxid=0x500000015 //节点被创建时的事务ID
mzxid=0x500000016 //节点最后一次被更新的事务ID
pzxid=0x500000015 //当前节点下的子节点最后一次被修改时的事务ID
ephemeralOwner = 0x0 //创建临时节点的时候,会有一个sessionId 。 该值存储的就是这个sessionid
dataLength = 3 //数据值长度
numChildren = 0 //子节点数
ctime = Sat Aug 05 20:48:26 CST 2017 //创建时间
mtime = Sat Aug 05 20:48:50 CST 2017 //修改时间
Zookeeper集群请求原理
-
处理读请求
任意节点都可以去处理读请求不需要转发
-
写请求(事务请求)
会转发给Leader(改进版2pc,过半同意即可)
- 事务请求发送到follower服务器节点(若发送给Leader节点就少了转发这一步)
- 首先会把事务请求转发给leader
- leader 服务器把客户端的写请求转化成一个事务 Proposal(提议),并把这个 Proposal 分发给集群中的所有 Follower 服务器
- 如果过半的follower节点同意(返回ACK)
- Leader 就会再次向所有的Follower 服务器发送 Commit 消息,要求各个 follower 节点对前面的一个 Proposal 进行提交
- 把最后的结果同步给Observer节点
- 把结果返回给客户端
JavaApi
-
zkclient —>zookeeper原生api
-
jar包导入
<dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.8</version> </dependency>
-
API连接状态
- KeeperStat.Expired //在一定时间内客户端没有收到服务器的通知, 则认为当前的会话已经过期了。
- KeeperStat.Disconnected //断开连接的状态
- KeeperStat.SyncConnected //客户端和服务器端在某一个节点上建立连接,并且完成一次version、zxid同步
- KeeperStat.authFailed //授权失败
-
事件类型
- NodeCreated //当节点被创建的时候,触发
- NodeChildrenChanged //表示子节点被创建、被删除、子节点数据发生变化
- NodeDataChanged //节点数据发生变化
- NodeDeleted //节点被删除
- None //客户端和服务器端连接状态发生变化的时候,事件类型就是None(比如建立连接)
-
-
curator
-
是Netflix公司开源的zookeeper客户端,提供了各种应用场景的实现封装
-
curator中包含了两个重要模块
- curator-framework 提供了fluent风格api
- curator-replice 提供了实现封装
-
curator连接的重试策略
- ExponentialBackoffRetry() //衰减重试
- RetryNTimes //指定最大重试次数
- RetryOneTime //仅重试一次
- RetryUnitilElapsed //一直重试直到规定的时间
-
curator中有Leader选举、分布式锁、配置中心等各种实现
对于Leader选举提供了两套API
—> LeaderLatch //如果未抢先写入master节点则阻塞等待
—> LeaderSelector //通过写入临时有序节点后判定自己是否为最小节点的方式实现
-
-
另外一个zookeeper Java客户端
<dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.1.8</version> </dependency>
ZAB协议
原子消息广播协议,ZAB(Zookeeper AtomicBroadcast)协议是为分布式协调服务 ZooKeeper 专门设计的一种支持崩溃恢复的原子广播协议。在 ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性。
-
ZAB协议主要有两种模式
- 消息广播模式
- 数据恢复模式
-
ZAB 协议的核心定义
- 当整个集群在启动时,或者当 leader 节点出现网络中断、崩溃等情况时,ZAB 协议就会进入恢复模式并选举产生新的 Leader。
- 当 leader 服务器选举出来后,并且集群中有过半的机器和该 leader 节点完成数据同步后,ZAB 协议就会退出恢复模式。(同步指的是数据同步,用来保证集群中过半的机器能够和 leader 服务器的数据状态保持一致)
- 当集群中已经有过半的 Follower 节点完成了和 Leader 状态同步以后,那么整个集群就进入了消息广播模式。
- 这个时候,在 Leader 节点正常工作时,启动一台新的服务器加入到集群,那这个服务器会直接进入数据恢复模式,和 leader 节点进行数据同步。同步完成后即可正常对外提供非事务请求的处理。
-
消息广播的实现原理
消息广播存在于事务处理过程中(改良版本的2pc):- Leader 接收到消息请求后,将消息赋予一个全局唯一的64 位自增 id,叫:zxid,通过 zxid 的大小比较既可以实现因果有序这个特征;
- Leader 为每个 follower 准备了一个 FIFO 队列将带有 zxid的消息作为一个提案(proposal)分发给所有的follower;
- 当 follower 接收到 proposal,先把 proposal 写到磁盘,写入成功以后再向 leader 回复一个 ack
- 当 leader 接收到合法数量(超过半数节点)的 ACK 后,leader 就会向这些 follower 发送 commit 命令,同时会在本地执行该消息
- 当 follower 收到 commit 命令以后,会提交该消息
-
崩溃恢复
-
ZAB 协议的这个基于原子广播协议的消息广播过程,在正常情况下是没有任何问题的,但是一旦 Leader 节点崩溃,或者由于网络问题导致 Leader 服务器失去了过半的 Follower 节点的联系,那么就 会进入到崩溃恢复模式。
注: 网络问题可能是 leader 节点和 follower 节点之间产生了网络分区,那么此时的 leader 不再是合法的 leader 了 -
进入崩溃恢复模式后集群必须解决如下两个问题
-
已经被处理的消息不能丢失
正常情况: 当 leader 收到合法数量 follower 的 ACKs 后,就向各 follower 广播 COMMIT 命令,同时也会在本地执行 COMMIT 并向连接的客户端返回成功。
异常情况: 如果在各个 follower 在收到 COMMIT 命令前Leader 就挂了,导致剩下的服务器并没有执行这条消息。
Leader 对事务消息发起 commit 操作,该消息在follower1 上执行了,但是 follower2 还没有收到 commit,Leader就已经挂了,而实际上客户端已经收到该事务消息处理成功的回执了。所以在 zab 协议下需要保证所有机器都要执行这个事务消息
。 -
被丢弃的消息不能再次出现
异常情况: 当 leader 接收到消息请求生成 proposal 后就挂了,其他 follower 并没有收到此 proposal,因此经过恢复模式重新选了 leader 后,这条消息是被跳过的。此时,之前挂了的 leader 重新启动并注册成了follower,他保留了被跳过消息的 proposal 状态,与整个系统的状态是不一致的,需要将其删除。
如图:在集群正常运行过程中的某一个时刻,Leader节点先后广播P1,P2,C1,C2
其中当Leader服务器将消息P2提交后,就立即崩溃推出。这种情况下当崩溃的服务器再次连接的时候C1和C2事务将会被抛弃删除。
-
-
leader投票算法
zookeeper 集群在处理事务性请求时是要发起follower投票的。
确保已经被leader 提交的事务 Proposal能够提交、同时丢弃已经被跳过的事务Proposal
-
重要概念
-
SID:服务器ID
用SID来唯一标识Zookeeper集群中的机器,每台机器都不能重复,和myid的值一致。 -
ZXID:事务ID
ZXID是一个事务ID,用来唯一标识一次服务器状态的变更。在某一个时刻,集群中每台机器的ZXID不一定都一致。ZXID由2部分组成总共 64 位,高 32 位是 epoch 编号 低 32 位是counter消息计数器; -
epoch
可以理解为当前集群所处的年代或者周期,每个leader 就像皇帝,都有自己的年号,所以每次改朝换代,leader 变更之后,都会在前一个年代的基础上加 1。这样就算旧的 leader 崩溃恢复之后,也没有人听他的了,因为follower 只听从当前年代的 leader 的命令。 -
counter
消息计数器,每接收到一条事务消息这个值就+1
-
-
示例
当处理事务请求时,会先生成一个事务ID(ZXID)如图,同一个Leader的统治下epoch是相同的,counter消息计数器随着事务的增加而递增,会按照请求顺序转发给Leader,并保存在一个FIFO队列中,这样就可以保证事务的顺序一致性。同时当这个Leader挂了,新选举出的Leader的epoch会+1,这样当这个节点再链接上来的时候,未处理的事务由于epoch过期了全部清除过期的事务。
Zookeeper的leader选举
-
zookeeper集群一般由2n+1台服务器组成(不包括observer)
- 因为集群需要半数以上的投票结果,所以允许挂掉的数目必须保证半数以上的机器存活
- 总共5台,必须最少3台存活;总共6台也必须最少3台存活。6台比5台只是增加了一个投票节点的开销,并没有提高可用性
-
选举算法
- leaderElection
- AuthFastLeaderElection
- FastLeaderElection (默认的选举算法)
-
选举算法的关键参数
- serverid
在配置server集群的时候,给定服务器的标识id(myid) - zxid
服务器在运行时产生的数据ID, zxid的值越大,表示数据越新,在选举算法中数据越新权重越大 - Epoch
投票的次数或者叫逻辑时钟,同一轮投票过程中的逻辑时钟值是相同的。
每投完一次票这个数据就会增加,然后与接收到的其它服务器返回的投票信息中的数值相比,根据不同的值做出不同的判断 - server的状态
- LOOKING,竞选状态。
- FOLLOWING,随从状态,同步leader状态,参与投票。
- OBSERVING,观察状态,同步leader状态,不参与投票。
- LEADING,领导者状态。
- serverid
-
选举过程
-
服务器启动时的 leader 选举
每个节点启动的时候状态都是 LOOKING,处于观望状态,接下来就开始进行选主流程进行 Leader 选举,至少需要两台机器(具体原因前面已经讲过了),我们选取 3 台机器组成的服务器集群为例。在集群初始化阶段,当有一台服务器 Server1 启动时,它本身是无法进行和完成 Leader 选举,当第二台服务器 Server2 启动时,这个时候两台机器可以相互通信,每台机器都试图找到 Leader,于是进入 Leader 选举过程。选举过程如下:- (1) 每个 Server 发出一个投票。由于是初始情况,Server1和 Server2 都会将自己作为 Leader 服务器来进行投票,每次投票会包含所推举的服务器的 myid 和 ZXID、epoch,使用(myid, ZXID,epoch)来表示,此时 Server1的投票为(1, 0),Server2 的投票为(2, 0),然后各自将这个投票发给集群中其他机器。
- (2) 接受来自各个服务器的投票。集群的每个服务器收到投票后,首先判断该投票的有效性,如检查是否是本轮投票(epoch)、是否来自LOOKING状态的服务器。
- (3) 处理投票。针对每一个投票,服务器都需要将别人的投票和自己的投票进行 PK,PK 规则如下
- 优先检查 ZXID,ZXID 比较大的服务器优先作为Leader。如果 leader 选举算法能够保证新选举出来的 Leader 服务器拥有集群中所有机器最高编号(ZXID 最大)的事务Proposal,那么就可以保证这个新选举出来的 Leader 一定具有已经提交的提案。因为所有提案被 COMMIT 之前必须有超过半数的 follower ACK,即必须有超过半数节点的服务器的事务日志上有该提案的 proposal,因此,只要有合法数量的节点正常工作,就必然有一个节点保存了所有被 COMMIT 消息的 proposal 状态。
- 如果 ZXID 相同,那么就比较 myid。myid 较大的服务器作为 Leader 服务器。对于 Server1 而言,它的投票是(1, 0),接收 Server2的投票为(2, 0),首先会比较两者的 ZXID,均为 0,再比较 myid,此时 Server2 的 myid 最大,于是更新自己的投票为(2, 0),然后重新投票,对于 Server2 而言,它不需要更新自己的投票,只是再次向集群中所有机器发出上一次投票信息即可。
- (4) 统计投票。每次投票后,服务器都会统计投票信息,判断是否已经有过半机器接受相同的投票信息,对于 Server1、Server2 而言,都统计出集群中已经有两台机器接受了(2, 0)的投票信息,此时便认为已经选出了 Leader。
- (5) 改变服务器状态。一旦确定了 Leader,每个服务器就会更新自己的状态,如果是 Follower,那么就变更为FOLLOWING,如果是 Leader,就变更为 LEADING。
-
运行过程中的 leader 选举
当集群中的 leader 服务器出现宕机或者不可用的情况时,那么整个集群将无法对外提供服务,而是进入新一轮的Leader 选举,服务器运行期间的 Leader 选举和启动时期的 Leader 选举基本过程是一致的。
- (1) 变更状态。Leader 挂后,余下的非 Observer 服务器都会将自己的服务器状态变更为 LOOKING,然后开始进入 Leader 选举过程。
- (2) 每个 Server 会发出一个投票。在运行期间,每个服务器上的 ZXID 可能不同,此时假定 Server1 的 ZXID 为124,Server3的ZXID为123;在第一轮投票中,Server1和 Server3 都会投自己,产生投票(1, 124),(3, 123),然后各自将投票发送给集群中所有机器。接收来自各个服务器的投票。与启动时过程相同。
- (3) 处理投票。与启动时过程相同,此时,Server1 将会成为 Leader。
- (4) 统计投票。与启动时过程相同。
- (5) 改变服务器的状态。与启动时过程相同。
-
-
Leader选举图例
Zookeeper数据存储
-
zookeeper会定时把数据存储在磁盘上。
-
DataDir = 存储的是数据的快照,存储某一个时刻全量的内存数据内容
-
DataLogDir 存储事务日志 ( log.zxid )
查看事务日志的命令java -cp :/zookeeper-3.4.10/lib/slf4j-api-1.6.1.jar:/zookeeper-3.4.10/zookeeper-3.4.10.jar org.apache.zookeeper.server.LogFormatter log.200000001
-
zookeeper.out //是Zookeeper的运行日志