Zookeeper是Hadoop的分布式协调服务,用于构建一般的分布式应用。
首先介绍一下分布式应用的主要困难:部分失败
这可以有多种情况:当一条消息在网络中两个节点之间传输,如果出现网络错误,发送者无法知道接受者是否已经收到这条消息。接受者可能在网络出现错误之前就已经收到这条消息,也可能没有收到,或者收到接受者的进程已经死掉。而发送者的唯一途径就是重新连接接受者,并向它发出询问。
而Zookeeper可以提供一组工具,使你在构建分布式应用时能够对部分失败进行正确处理。
zookeeper的特点:
1、简单,zookeeper核心是一个精简的文件系统,提供简单操作和额外抽象操作;
2、富有表现力,其基本操作是一组丰富的“构建”,用于实现多种协调数据结构和协议,包括:分布式队列、分布式锁、一组节点中“领导者选举”;
3、高可用性,运行在一组机器上,具有高可用性,应用程序完全依赖它,可以帮助系统出现单点故障;
4、松耦合交互方式,交互过程中,参与者不需要彼此了解;
5、资源库,其提供了一个通用协调模式实现方法的开源共享库,所有人都可以对这个资源库进行添加和改进,免于写这类通用协议;
6、高性能,对于以读写操作为主的工作负载吞吐量高。
zookeeper组成员关系:
将zookeeper看作一个具有高可用性特征的文件系统。
其中统一使用“节点”的概念,znode。
znode既可以作为保存数据的容器(文件),也可以作为保存其他znode的容器(目录)。所有的znode构成了一个层次化的命名空间,创建一个以组名为节点名的znode作为父节点,然后以组成员名(服务器名)为节点来创建作为子节点的znode。
zookeeper服务
(模型、操作和实现)
数据模型
zookeeper维护着一个树形层次结构,树中节点被称为znode。
znode可以用于存储数据,有一个与之相关联的ACL。
zook被设计用来实现协调服务(通常使用小数据文件)
zookeeper的数据访问有原子性。读写操作不是成功就是失败,不会出现部分成功部分失败的情况。
znode通过路径被引用。zookeeper中路径必须为绝对路径,每条路径必须从一个斜杠字开始。所有路径表示必须是规范的,每条路径只有唯一一种表示方式,不支持路径解析。
znode有两种类型:短暂的(ephemeral)和持久的(persistent)。
创建znode的客户端断开连接时,无论因为任何原因而终止,短暂znode都会被zookeeper服务删除,持久znode不会被删除。
我们总是希望代表一个组的znode存活的时间应当比创建程序的生命周期要长。
对于那些需要知道特定时刻有哪些分布式资源可用的应用来说,使用短暂znode是一种理想的选择。
顺序号:
顺序znode是指名称中包含zookeeper指定顺序号的znode。
在一个分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端就可以通过顺序号来推断事件的顺序。
观察:
znode以某种方式发生变化时,“观察”(watch)机制可以让客户端得到通知。
但是观察只能够出发一次,为了能够多次收到通知,客户端需要重新注册所需的观察。
操作:
zookeeper中的更新操作是有条件的,使用delete或setData操作时必须提供被更新znode的版本号(可以通过exists操作获得),如果版本号不匹配,则更新操作(非阻塞)失败。
集合:
zookeeper中有一个被称为multi的操作,用于将多个基本操作集合成一个操作单元,并确保这些基本操作同时被成功执行,或者同时失败。
zookeeper的更新操作集合到一个multi操作中可以保证这组更新操作的原子性,也就保证了一对顶点之间不会出现不完整的连接。
API:
同步API
异步API
观察触发器:
在exists、getChildren、getData这些读操作上可以设置观察,这些观察可以被create、delete、setData触发。
ACL相关操作不参与触发任何观察。
ACL列表:
每个znode创建时都会带一个ACL列表,用于决定谁可以对它执行何种操作。
ACL依赖于zookeeper的客户端身份验证机制:
1.digest 通过用户名和密码识别客户端
2.sasl 通过Kerberos来识别客户端
3.ip 通过客户端IP地址识别客户端
zookeeper还支持插入式身份验证机制,如果需要,可以集成第三方的身份验证系统。
实现:
zookeeper服务有两种运行模式:独立模式和复制模式
独立模式只有一个zookeeper服务器,适合于测试环境,不能保证高可用性和可恢复性。
复制模式运行于计算机集群上,集群被称为集合体,只要集合体中半数以上的机器处于可用状态,就能够提供服务。,一般通常包含奇数台机器。
zookeeper需要做的就是确保对znode树的每个修改都会被复制到集合体中超过半数的机器上,最少有一台机器保存最新状态。
使用zab协议,包括两个可以无限重复的阶段。
1.领导者选举
集合体中所有机器通过一个选择过程选出一台 领导者, 其他的是 跟随者,只要半数以上的跟随者与领导者状态同步,则完成。
2.原子广播
所有写请求都会被转发给领导者,再由领导者将更新广播给跟随者。
半数以上跟随者已经将修改持久化之后,领导者才会提交更新,客户端才会收到一个更新成功的响应。(原子性,要么成功,要么失败)
如果领导者出现故障,会重新选出另一个领导者,并和新领导者一起继续提供服务。当之前领导者恢复,则会称为一个跟随者。
3.一致性
每一个对znode树更新都被赋予一个全局唯一的ID,称为zxid(zookeeper Transaction ID)。
zookeeper要求对所有的更新进行编号并排序,其决定了分布式系统的执行顺序,保证了数据的一致性。
1)顺序一致性
任意特定客户端的更新都会按其发送顺序被提交。
2)原子性
每个更新要么成功,要么失败。
3)单一系统映像
一个客户端无论连接到哪一台服务器,看到的都是同样的系统视图。
4)持久性
一个更新一旦成功,其结果就会持久存在并不会撤销。
5)及时性
任何客户端所看到的滞后系统视图都是有限的,不会超过几十秒。
4.会话
每个zookeeper客户端配置中都包含集合体中服务器列表。
启动时,客户端会尝试连接到列表中的一台服务器。
一旦客户端与服务器建立连接,这台服务器就会为该客户端创建一个新的会话。每个会话都有一个超时时间设置(创建会话的应用设定)。如果服务器在超时时间内没有收到请求,则会话过期。过期则无法重新打开,所有与会话关联的短暂znode会丢失。
zookeeper客户端可以自动进行故障切换,换至另一台服务器,切换完之后,所有会话仍然有效。
在故障切换过程中,应用程序将收到断开连接和连接至服务的通知。
当客户端断开连接时,观察通知将无法发送;但当客户端成功恢复连接后,这些延迟的通知还会被发送。当然,在客户端重新连接至另一台服务器的过程中,如果应用程序试图执行一个操作,这个操作将会失败。
5.时间
“滴答”(tick time)定义了zookeeper中的基本时间周期,并被集合体中的服务器用来定义相互交互的时间表。
如会话超时时间不可以小于2个滴答并不可以大于20个滴答。
较短的会话超时设置会较快的检测到机器故障。但要避免将会话超时时间设的太低,因为繁忙的网络会导致数据包传输延迟,从而可能会无意中导致会话过期。这种情况下,机器可能会出现“振动”:很短时间内反复出现离开后又重新加入组的情况。
对于那些创建较复杂暂时状态的应用程序来说,重建代价太大,比较适合设置较长的会话超时。
一般规则是,zookeeper集合体中服务器越多,会话超时设置越大。
6.状态
CONNECTING:一个新建的zookeeper实例处于这个状态。
CONNECTED:一旦建立连接,进入这个状态。
CLOSED:不在活跃,并且不能再用。
锁服务:
分布式锁能够在一组进程之间提供互斥机制,使得在任何时刻只有一个进程可以持有锁。
申请获取锁:
(1)在锁znode 下创建一个名为lock-的短暂顺序znode,并且记住它的实际路径名(create操作的返回值)。
(2)查询锁znode的子节点并设置一个观察。
(3)如果步骤1中所创建的znode在步骤2返回的所有子节点中具有最小的顺序号,则获取到锁,退出。
(4)等待步骤2中所设置观察的通知,转到步骤2。