Paxos,发音近似 帕克索斯。
并发的定义(来自《深入理解计算机系统》):
如果逻辑控制流在时间上重叠,那么他们就是并发的。
本书的并发,指更新操作的并发,即有多个线程同时更新内存中变量的值。
数据复制的延时问题。数据一致性指对一个副本数据进行更新的同时,必须确保也能够更新其他的副本,否则不同副本之间的数据将不再一致。
一致性级别:
集中式架构到分布式架构;
《分布式系统概念与设计》对分布式系统的定义:
硬件或者软件组件发布在不同的网络计算机上,彼此之间仅仅通过消息传递进行通信和协调的系统。
分布式系统的特征:
分布式系统的典型问题:
从ACID到CAP/BASE
标准SQL规范定义四个事务隔离级别:未授权读取、授权读取、可重复读取、串行化;
分布式事务:事务的参与者、支持事务的服务器、资源服务器、以及事务管理器分别位于分布式系统的不同节点上。
二阶段提交(Two-phaseCommit)是指,在计算机网络以及数据库领域内,为了使基于分布式系统架构下的所有节点在进行事务提交时保持原子性和一致性而设计的一种算法。通常,二阶段提交也被称为是一种协议。
在分布式系统中,每个节点虽然可以知晓自己的操作时成功或者失败,却无法知道其他节点的操作的成功或失败。当一个事务跨越多个节点时,为了保持事务的ACID特性,需要引入一个作为协调者的组件来统一掌控所有节点(称作参与者)的操作结果并最终指示这些节点是否要把操作结果进行真正的提交。二阶段提交的算法思路可以概括为:参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情报决定各参与者是否要提交操作还是中止操作。
2.1协议说明:
阶段一:提交事务请求
阶段一也叫投票阶段。
阶段二:执行事务请求
协调者会根据各参与者的反馈情况来决定最终是否可以进行事物提交操作,所以分为以下两种情况:
执行事物提交
当协调者节点从所有参与者节点获得的相应消息都为“YES”时:
中断事物
如果任一参与者节点在第一阶段返回的响应消息为“NO”,或者 协调者节点在第一阶段的询问超时之前无法获取所有参与者节点的响应消息时,那么就会中断事物。
不管最后结果如何,第二阶段都会结束当前事务。
流程图如下:
简单来看:二阶段提交将一个事物的处理过程分为了投票和执行阶段,是一个先尝试再提交的过程,是一个强一致性的算法。
2.2优缺点:
优点:原理简单,实现方便。
缺点:
三、三阶段提交(3PC)
三阶段提交(Three-phase commit),也叫三阶段提交协议(Three-phase commit protocol),是二阶段提交(2PC)的改进版本。
3.1协议说明
将二阶段提交协议的“提交事务请求”一分为二,形成了CanCommit、PreCommit、DoCommit三个阶段。示意图如下:
3.1.1CanCommit阶段
3PC的CanCommit阶段其实和2PC的准备阶段很像。协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。
1.事务询问
协调者向参与者发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应。
2.响应反馈
参与者接到CanCommit请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态。否则反馈No
3.1.2PreCommit阶段
协调者根据参与者的反应情况来决定是否可以记性事务的PreCommit操作。根据响应情况,有以下两种可能。
执行事务预提交
假如协调者从所有的参与者获得的反馈都是Yes响应,那么就会执行事务的预执行。
1.发送预提交请求 协调者向参与者发送PreCommit请求,并进入Prepared阶段。
2.事务预提交 参与者接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中。
3.响应反馈 如果参与者成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令。
中断事物
假如有任何一个参与者向协调者发送No响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。
1.发送中断请求 协调者向所有参与者发送abort请求。
2.中断事务 参与者收到来自协调者的abort请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断。
3.1.3docommit阶段
该阶段进行真正的事务提交,也可以分为以下两种情况。
执行提交
中断事务
协调者没有接收到参与者发送的ACK响应(可能是接受者发送的不是ACK响应,也可能响应超时),那么就会执行中断事务。
1.发送中断请求 协调者向所有参与者发送abort请求
2.事务回滚 参与者接收到abort请求之后,利用其在阶段二记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源。
3.反馈结果 参与者完成事务回滚之后,向协调者发送ACK消息
4.中断事务 协调者接收到参与者反馈的ACK消息之后,执行事务的中断。
注意:
阶段三,可能会出现:协调者出现问题,协调者和参与者网络出现故障。无论哪种异常都会导致参与者无法及时接收到来自协调者的doCommit或者rebort请求时,参与者会在等待超时之后,会继续进行事务的提交。
3.2优缺点:
优点:3PC主要解决的单点故障问题,并减少阻塞范围,因为一旦参与者无法及时收到来自协调者的信息之后,他会默认执行commit。而不会一直持有事务资源并处于阻塞状态。
缺点:引入新问题,如果出现网络分区,协调者发送的abort响应没有及时被参与者接收到,那么参与者在等待超时之后执行了commit操作。这样就和其他接到abort命令并执行回滚的参与者之间存在数据不一致的情况。
对于2PC、3PC无法彻底解决分布式一致性问题后,就是paxos。
zookeeper提供分布式协调服务,提供诸如统一命名服务、配置管理和分布式锁、分布式消息等分布式的基础服务。zookeeper的zab(zookeeper atomic broadCast),是paxos的一种改进。zookeeper是一个典型的分布式数据一致性的解决方案,分布式应用可以基于zookeeper实现发布\订阅、负载均衡、命名服务、分布式协调\通知、集群管理/master选举、分布式锁、和分布式队列等功能。
zookeeper可以保证各种分布式一致性问题:顺序一致性、原子性、单一视图、可靠性、实时性。
zookeeper的设计目标: 提供简单的数据模型、可以构建集群、顺序访问、高性能。
简单的数据模型:zookeeper提供了一个共享的、树型结构的命名空间来进行相互协调,这些数据结构都存在内存中,可以提高吞吐量。
构建分布式集群:
顺序访问:来自于client的事务,zookeeper都会分配一个全局唯一的递增ID,这个ID反应了客户端执行的顺序。
高性能:zookeeper将全部数据结构存在内存中,并直接服务于客户端的非事务请求。
zookeeper概念:
集群角色
在分布式系统中,典型的应用是master/slave 主从模式的架构,提供全局写操作的节点为master,通过异步复制的节点叫做slave。在zookeeper中,提出了leader、Follower、Observer。follower选举产生leader,observer提供读服务,所以zookeeper适用于读多写少的服务。
回话角色:
回话(session):当zookeeper客户端启动的时候,会与zookeeper建立一个长连接,zookeeper能够通过向client发送心跳检测client的状态,通过zookeeper管理zookeeper的client(zookeeper的client为分布式应用的各个节点)。
数据节点:
在分布式应用中,一个是zookeeper管理的节点即为应用节点-机器节点,另一个节点类型为数据节点-znode,管理zookeeper数据模型的数据单元(zookeeper管理节点的数据)。zookeeper为树型数据模型(Znode Tree) , 通过/分割的路径就是一个ZNode,比如/foo/path1 , 为一个ZNode节点,保存数据内容和属性信息。
版本:
zookeeper存放znode的版本。
watcher:
zookeeper允许用户注册事件,在某个时候触发事件,分配给合适的client执行事件,watcher机制是zookeeper实现分布式协调服务的重要特征。
ACL机制:
zookeeper提供类似linux的权限控制机制。
部署:单机模式,伪分布模式和分布式集群模式;
客户端脚本,zkCli.sh,命令:
Java客户端工具
zookeeper的客户端和服务端会话建立是一个异步的过程;
create()方法有同步和异步两种,都不支持递归创建节点,节点内容只支持字节数组byte[]类型,即不负责序列化工作,可以使用Hessian或者Kryo等专门的序列化工具;异步和同步的区别,异步方式下节点的创建过程(包括网络通信和服务端节点创建过程)是异步的,在使用同步接口时需要注意可能抛出的异常,但是异步接口本身不会抛出异常,所有的异常都是在回调函数中通过ResultCode响应码来体现。
delete,同样有同步和异步之分;
getChildren,zk客户端在获取到指定节点的子节点列表之后,还需要订阅这个子节点列表的变化通知,通过注册watcher来实现。当有子节点被添加或者是删除时,服务端会向客户端发送一个EventType.NodeChildrenChanged类型的事件通知(只发送一次,watcher会失效,故客户端需要反复注册watcher),此时客户端需要主动重新去获取列表才能获取到最新的列表。子节点列表都是数据节点的相对节点路径;
getData,节点的数据内容或者是节点的数据版本变化,都是节点的变化;
setData,CAS:对于值V,每次更新前都会比对其值是否是预期值A,只有符合预期,才会将V值原子化地更新到新值B。
exists;
权限控制,zk提供的几种权限控制模式scheme:world、auth、digest、ip&super。当客户端对一个数据节点添加权限信息后,对于删除操作而言,其作用范围是其子节点。
开源客户端:ZkClient & Curator
ZkClient,提供Session超时重连,watcher反复注册;使用listener来实现watcher的反复注册,注册一次一直有效;deleteRecursive接口,提供递归删除子节点功能;
Curator
fluent风格,提供各种应用场景(共享锁服务,master选举,分布式计算器)的抽象封装;重试策略ExponentialBackoffRetry;zk所有的非叶子节点必须是持久节点;BackgroundCallback接口,用来处理异步接口调用之后服务端返回的结果信息;CuratorEventType:CREATE、DELETE、EXISTS、GET_DATA/SET_DATA、CHILDREN、SYNC/GET_ACL/WATCHED、CLOSING等。响应码,KeeperException.Code类,0(OK)、-4(ConnectionLoss)、 -100(NodeExists) 、 -112(SessionExpired);
典型使用场景
引入依赖curator-recipes;
主要包括:数据发布/订阅、负载均衡、命名服务、分布式协调/通知(注册功能)、集群管理、master选举、分布式锁、分布式消息队列。
zk实现数据发布/订阅服务:
发布/订阅通常有两种模式:推模式push/拉模式pull。推模式之后,服务端主动将数据更新发送给所有订阅的客户端;拉模式,客户端主动发起请求去获取最新数据,定时轮询拉取。zookeeper是推拉结合的方式:客户端向服务端注册自己需要关注的节点,一旦该节点的数据发生变更,则服务端就会向相应的客户端发送watcher事件通知,客户端接收到消息通知之后,需要主动去服务端获取最新数据。主要应用于分布式中,配置文件的全局通知、更新。
全局配置信息的3个特性:
数据量比较小;数据内容在运行时发生动态变化;集群内各机器共享,配置一致。
配置获取:在机器启动过程中,zookeeper的客户端会获取到其他客户端配置文件的改变。zk客户端通过向zk注册一个watcher监听,监听到客户端配置文件改变时,通知其他客户端信息改变。
配置更新:在系统运行过程中,当客户端系统配置文件改变时,zk通知其他注册的客户端,客户端在收到变更通知后,更新获取的数据。
zk的负载均衡:
负载均衡主要有硬件负载均衡和软件负载均衡,通过负载均衡达到计算机集群cpu、内存、网络连接、I/O进行资源配置。zookeeper主要通过软件进行负载均衡,zookeeper通过域名配置的功能,为IP配置相应的域名。
DNS系统可以看做一个超大规模的分布式映射表,域名和IP之间一一映射,向域名注册服务商申请域名注册,缺陷在于只能注册有限的域名;实际开发中,往往使用本地host文件绑定来实现域名解析的工作,缺陷在于:当应用的机器规模扩大之后,需要到每个机器上去逐个进行变更,需要消耗大量时间,不能保证实时性。
域名配置:
域名解析:
域名变更:
问题在于:
升级版——自动化的DNS服务
域名注册:
域名解析:
域名探测:
命名服务:
zk提供的命名服务功能和JNDI技术比较相似,通过一个资源引用的方式来实现对资源的定位和使用。分布式环境下,上层应用仅仅需要一个全局唯一的名字,通过这个唯一主键来定位资源。UUID的缺点:1. 长度过长;2. 含义不明。
分布式协调服务:
在分布式系统中,通过引入分布式系统协调者来控制整个分布式应用的运行,比如分布式任务的执行、分布式机器的协调工作。一般的做法是通过多个client在一个watcher上注册(dubbo使用zk的注册功能。),当client上数据发生变化时,所有watcher的订阅者会收到相应的数据变化通知。
Master选举:
分布式锁:
zk通过分布式锁控制客户端对于共享资源的访问,当访问共享资源时,需要分布式锁保证资源的一致性。
分布式队列:
zk配置参数:
四字命令
使用有两种方式:1. 使用telnet命令登录zk的对外服务端口,直接使用四字命令;2.使用nc命令:echo conf | nc localhost 2181
。
命令概览:
JMX
四字命令仅仅用于监控,但实际上侧重于监,不能用于控制;想要实现控制,需要JMX支持,zk3.3.0以上版本,使用标准JMX来对外提供运行时数据信息和管控接口;zk默认开启JMX功能。
找到zkServer.sh文件,找到zoomain配置信息,可以考虑修改authenticate=false(本地测试开发时)
ZOOMAIN=" -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=$JMXPORT -Dcom.sun.management.jmxremote.authenticate=$JMXAUTH -Dcom.sun.management.jmxremote.ssl=$JMXSSL -Dzookeeper.jmx.log4j.disable=$JMXLOG4J org.apache.zookeeper.server.quorum.QuorumPeerMain"
第二种方式,通过JConsole连接zk
JConsole基于JMX,图形化界面,需要多摸索摸索即可;TODO
Leader服务器对外提供四个操作:
followerInfo:获取所有follower的运行时信息;
resetLatency:重置所有与客户端请求处理延时相关的统计信息;
resetMaxLatency:重置客户端请求处理的最大延时统计;
resetStatistics:重置所有客户端请求处理延时统计,以及所有客户端数据包发送与接收的统计信息。
InMemoryDataTree,zk服务器的内存数据库。
监控:实时监控与数据统计
构建高可用集群
容灾和扩容两方面,5台机器与6台机器构成的zk集群,容灾能力没有差别,基于此,zk集群一般是奇数个节点。容灾主要就是面对单点问题,单点的不仅仅是一个服务器,有可能是一个机房。故而有三机房部署与两机房部署方案(略);至于扩容和缩容,实际上就是zk集群的重启问题,两种方式:1. 全部重启,不推荐;2. 逐台重启;
日常运维
java -cp zookeeper-3.4.5.jar :lib/slf4j-api-1.6.1.jar:lib/slf4j-log4j12-1.6.1.jar:lib/log4j-1.2.15.jar:conf org.apache.zookeeper.server.PurgeTxnLog /home/admin/taokeeper/zk_data /home/admin/taokeeper/zk_data -n 15
,至多保留15个文件。3. 使用清理脚本zkCleanup.sh,基于PurgeTxnLog。自动清理机制,zk3.4.0版本之后,配置参数autoperge.snapRetainCount和autoperge.purgeInterval。附脚本:
#!/bin/bash
#snapshot file dir
dataDir=/home/nileader/taokeeper/zk_data/version-2
# tran log dir
dataLogDir=/home/nileader/taokeeper/zk_log/version-2
#zk log dir
logDir=/home/nileader/taokeeper/logs
# leave 60 files
count=60
count=$[$count+1]
ls -t $dataLogDir/log.* | tail -n +$count | xargs rm -f
ls -t $dataDir/snapshot.* | tail -n +$count | xargs rm -f
ls -t $logDir/zookeeper.log.* | tail -n +$count | xargs rm -f
Windows平台安装zk及部署集群;
源码构建;
源码阅读:src/java/generated目录是实体类和协议层类;zookeeperMain主类;jute组件进行序列化和反序列化;网络通信的客户端类:ClientCnxn和ClientCnxnSocket和ClientCnxnSocketNIO,服务端四个类:NIOServerCnxn、NIOServerCnxnFactory、NettyServerCnxn、NettyServerCnxnFactory;权限认证:digest,IP和SASL;