参考:
https://www.jianshu.com/p/01388f06e75d
https://www.cnblogs.com/iforever/p/9095095.html
1.zookeeper是什么
分布式应用程序的分布式协调服务。分布式应用程序可以基于它实现同步服务,配置维护和命名服务等。
1.1角色
2.解决什么
当在一个集群规模的环境中,多台同类型的应用使用同样的配置文件,为了避免登陆每台机器修改配置,为了减少人为的修改导致配置不一致,为了实现配置文件的统一管理、版本控制,那么就有必要实现一个配置管理中心的应用。
3.用途及设计目的
数据发布与订阅(配置中心)
负载均衡
命名服务(Naming Service)
分布式通知/协调
集群管理与Master选举
分布式锁
分布式队列
1.最终一致性:client不论连接到哪个Server,展示给它都是同一个视图,这是zookeeper最重要的性能。
2 .可靠性:具有简单、健壮、良好的性能,如果消息m被到一台服务器接受,那么它将被所有的服务器接受。
3 .实时性:Zookeeper保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息。但由于网络延时等原因,Zookeeper不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口。
4 .等待无关(wait-free):慢的或者失效的client不得干预快速的client的请求,使得每个client都能有效的等待。
5.原子性:更新只能成功或者失败,没有中间状态。
6 .顺序性:包括全局有序和偏序两种:全局有序是指如果在一台服务器上消息a在消息b前发布,则在所有Server上消息a都将在消息b前被发布;偏序是指如果一个消息b在消息a后被同一个发送者发布,a必将排在b前面。
4.担保
ZooKeeper非常快速而且非常简单。但是,由于其目标是构建更复杂的服务(如同步)的基础,
因此它提供了一系列保证:
顺序一致性 - 客户端的更新将按发送顺序应用。
原子性 - 更新成功或失败。没有部分结果。
单系统映像 - 无论服务器连接到哪个服务器,客户端都将看到相同的服务视图。
可靠性 - 一旦应用了更新,它将从那时起持续到客户端覆盖更新。
及时性 - 系统的客户视图保证在特定时间范围内是最新的。
5.部署
linux:https://www.cnblogs.com/wrong5566/p/6056788.html,https://blog.51cto.com/ityunwei2017/2131509
windows:https://blog.csdn.net/shengqianfeng/article/details/79297171
6.配置管理
6.1实现了哪些功能
0. 标准的key value的配置文件几个
1. 基于web页面的配置文件的增删改查
2. 同一个app下多个配置文件
3. 版本管理,当前版本,历史版本管理
4. 数据持久化保存
5. 非标准的key value配置文件的管理
6. 客户端watcher的实现
6.2同类型的配置方案
1. 王阿晶,邹仕洪: [基于ZooKeeper的配置信息存储方案的设计与实现](http://wenku.baidu.com/view/ee86ca90daef5ef7ba0d3c7d.html)
2. 淘宝diamod实现:[http://code.taobao.org/p/diamond/src/](http://code.taobao.org/p/diamond/src/), 2012
3. disconf github: [https://github.com/knightliao/disconf](https://github.com/knightliao/disconf), 2014
4. [百度BJF配置中心](http://wiki.babel.baidu.com/twiki/bin/view/Main/CAP-CC#%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%831.0%E5%BF%AB%E9%80%9F%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97.pptx), 2014
6.3原理
zookeeper提供了节点watch的功能,zookeeper的client(对外提供服务的server)监控zookeeper上的节点(znode),当节点变动的时候,client会收到变动事件和变动后的内容,基于zookeeper的这个特性,我们可以给服务器集群中的所有机器(client)都注册watch事件,监控特定znode,节点中存储部署代码的配置信息,需要更新代码的时候,修改znode中的值,服务器集群中的每一台server都会收到代码更新事件,然后触发调用,更新目标代码。也可以很容易的横向扩展,可以随意的增删机器,机器启动的时候注册监控节点事件即可。
配合上git的hook机制,可以做一个完整的系统,当代码有更新的时候更新保存代码信息znode上的数据,zookeeper push到所有watch这个节点的服务器,服务器更新代码,所有服务器完成一次更新操作。
7.服务发现
7.1原理
注册一个持久节点/service/business/what
,他下面的每个子节点都是一个可用服务,保存了服务的地址端口等信息,服务调用者通过zookeeper获取/service/business/what
所有子节点信息来得到可用的服务。下面的节点都是临时节点,服务器启动的时候会过来注册一个临时节点,服务器挂掉之后或主动关闭之后,临时节点会自动移除,这样就可以保证使用者获取的what服务都是可用的,而且可以动态的扩容缩容。
除此之外,还可以在从zookeeper获取可用服务列表的时候加一层缓存,提高性能,额外一个进程watch/service/business/what
的子节点变动,当有子节点变动的时候,删除缓存,这样就可以做到缓存中的内容'时时'和zookeeper中保持一致了
8.zk在kafka中的作用
在kafka中,zookeeper负责的是存储kafka中的元数据信息,队列的数据是不会存储到zookeeper的,kafka是分布式的,zookeeper协调broker、producer、consumer之间的关系,当有新的角色加入的时候,更新zookeeper中的数据,其他角色就可以得到通知,并作出相应的调整,不需要停机更新配置,做到动态扩容。下图来自互联网,比较清晰的展示了zookeeper中存储的kafka元信息数据。
9.zookeeper如何实现负载均衡的?
zookeeper 的数据存储类似于liunx的目录结构。首先建立servers节点,并建立监听器监视servers子节点的状态(用于在服务器增添时及时同步当前集群中服务器列表)。在每个服务器启动时,在servers节点下建立子节点worker server(可以用服务器地址命名),并在对应的字节点下存入服务器的相关信息。这样,我们在zookeeper服务器上可以获取当前集群中的服务器列表及相关信息,可以自定义一个负载均衡算法,在每个请求过来时从zookeeper服务器中获取当前集群服务器列表,根据算法选出其中一个服务器来处理请求。
参考:
https://blog.csdn.net/u010523770/article/details/63685353
https://blog.csdn.net/justry_deng/article/details/84790782
https://blog.csdn.net/dshf_1/article/details/81087447
服务器负载均衡有三大基本特征:负载均衡算法,健康检查和会话保持,这三个特征是保证负载均衡正常工作的基本要素。
9.1负载均衡算法
Ø 轮询(RoundRobin)将请求顺序循环地发到每个服务器。当其中某个服务器发生故障,AX就把其从顺序循环队列中拿出,不参加下一次的轮询,直到其恢复正常。
Ø 比率(Ratio):给每个服务器分配一个加权值为比例,根椐这个比例,把用户的请求分配到每个服务器。当其中某个服务器发生故障,AX就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。
Ø 优先权(Priority):给所有服务器分组,给每个组定义优先权,将用户的请求分配给优先级最高的服务器组(在同一组内,采用预先设定的轮询或比率算法,分配用户的请求);当最高优先级中所有服务器或者指定数量的服务器出现故障,AX将把请求送给次优先级的服务器组。这种方式,实际为用户提供一种热备份的方式。
Ø 最少连接数(LeastConnection):AX会记录当前每台服务器或者服务端口上的连接数,新的连接将传递给连接数最少的服务器。当其中某个服务器发生故障,AX就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。
Ø 最快响应时间(Fast Reponse time):新的连接传递给那些响应最快的服务器。当其中某个服务器发生故障,AX就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。
以上为通用的负载均衡算法,还有一些算法根据不同的需求也可能会用到,例如:
Ø 哈希算法( hash): 将客户端的源地址,端口进行哈希运算,根据运算的结果转发给一台服务器进行处理,当其中某个服务器发生故障,就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。
Ø 基于策略的负载均衡:针对不同的数据流设置导向规则,用户可自行编辑流量分配策略,利用这些策略对通过的数据流实施导向控制。
Ø 基于数据包的内容分发:例如判断HTTP的URL,如果URL中带有.jpg的扩展名,就把数据包转发到指定的服务器。
9.2健康检查
健康检查用于检查服务器开放的各种服务的可用状态。创建健康检查时可以设定检查的间隔时间和尝试次数,例如设定间隔时间为5秒,尝试次数为3,那么负载均衡设备每隔5秒发起一次健康检查,如果检查失败,则尝试3次,如果3次都检查失败,则把该服务标记为DOWN,然后服务器仍然会每隔5秒对DOWN的服务器进行检查,当某个时刻发现该服务器健康检查又成功了,则把该服务器重新标记为UP。健康检查的间隔时间和尝试次数要根据综合情况来设置,原则是既不会对业务产生影响,又不会对负载均衡设备造成较大负担。
9.3会话保持
会话保持用于保持会话的连续性和一致性,由于服务器之间很难做到实时同步用户访问信息,这就要求把用户的前后访问会话保持到一台服务器上来处理。负载均衡设备一般会默认配置一些会话保持的选项,例如源地址的会话保持,Cookie会话保持等,基于不同的应用要配置不同的会话保持,否则会引起负载的不均衡甚至访问异常。
10.zk命名服务
参考:https://blog.csdn.net/weixin_33772645/article/details/87002758
主要两点吧:节点类似于文件系统中的目录结构、可以创建顺序节点
11.zk实现分布式通知/协调
https://blog.csdn.net/en_joker/article/details/78799737
ZooKeeper中特有的Watcher注册与异步通知机制,能够很好的实现分布式环境下不同机器,甚至是不同系统之间的协调与通知,从而实现对数据变更的实时处理。
基于ZooKeeper实现分布式协调与通知功能,从而实现对数据变更的实时处理。基于ZooKeeper实现分布式协调与通知功能,通常的做法是不同的客户端都对ZooKeeper上同一个数据节点进行Watcher注册,监听数据节点的变化(包括数据节点本身及其子节点),如果数据节点发生变化,那么所有订阅的客户端都能够接收到相应的Watcher通知,并做出相应的处理。
12.zk实现分布式锁
https://blog.csdn.net/sunfeizhi/article/details/51926396
12.1分布式锁介绍
分布式锁主要用于在分布式环境中保护跨进程、跨主机、跨网络的共享资源实现互斥访问,以达到保证数据的一致性。
12.2获取分布式锁的总体思路
在获取分布式锁的时候在持久节点下创建临时顺序节点,释放锁的时候删除该临时节点。
1.客户端调用createNode方法在持久节点下创建临时顺序节点,
2.然后调用getChildren(“locker”)来获取持久节点下面的所有子节点,注意此时不用设置任何Watcher。客户端获取到所有的子节点path之后,
3.如果发现自己在之前创建的子节点序号最小,那么就认为该客户端获取到了锁。
4.如果发现自己创建的节点并非locker所有子节点中最小的,说明自己还没有获取到锁,此时客户端需要找到比自己小的那个节点,然后对其调用exist()方法,同时对其注册事件监听器。之后,让这个被关注的节点删除,则客户端的Watcher会收到相应通知,此时再次判断自己创建的节点是否是locker子节点中序号最小的,如果是则获取到了锁,如果不是则重复以上步骤继续获取到比自己小的一个节点并注册监听。当前这个过程中还需要许多的逻辑判断。
13.Zookeeper分布式队列的实现
原文:https://blog.csdn.net/evankaka/article/details/70806752
Zookeeper可以处理两种类型的队列:
(1)同步队列
当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达。
思路:在zookeeper中先创建一个根目录 queue_sync,做为队列队列的消费者监视/queue/start节点,刚开始还没有这个节点,所以什么都不会做。入队操作就是在queue_sync下创建子节点,然后计算子节点的总数,看是否和队列的目标数量相同。如果相同,创建/queue_sync/start节点,由于/queue_sync/start这个节点有了状态变化,zookeeper就会通知监视者:队员已经到齐了,监视者得到通知后进行自己的后续流程
(2)先进先出队列
按照FIFO方式进行入队和出队
思路:在zookeeper中先创建一个根目录 queue_fifo,做为队列。入队操作就是在queue_fifo下创建自增序的子节点,并把数据放入节点内。出队操作就是先找到queue_fifo下序号最下的那个节点,取出数据,然后删除此节点。
14工作原理
Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。
为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。
每个Server在工作过程中有三种状态:
-
LOOKING:当前Server不知道leader是谁,正在搜寻
-
LEADING:当前Server即为选举出来的leader
-
FOLLOWING:leader已经选举出来,当前Server与之同步
14.1选主流程
当leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式需要重新选举出一个新的leader,让所有的Server都恢复到一个正确的状态。Zk的选举算法有两种:一种是基于basic paxos实现的,另外一种是基于fast paxos算法实现的。系统默认的选举算法为fast paxos。先介绍basic paxos流程:
-
选举线程由当前Server发起选举的线程担任,其主要功能是对投票结果进行统计,并选出推荐的Server;
-
选举线程首先向所有Server发起一次询问(包括自己);
-
选举线程收到回复后,验证是否是自己发起的询问(验证zxid是否一致),然后获取对方的id(myid),并存储到当前询问对象列表中,最后获取对方提议的leader相关信息(id,zxid),并将这些信息存储到当次选举的投票记录表中;
-
收到所有Server回复以后,就计算出zxid最大的那个Server,并将这个Server相关信息设置成下一次要投票的Server;
-
线程将当前zxid最大的Server设置为当前Server要推荐的Leader,如果此时获胜的Server获得n/2 + 1的Server票数, 设置当前推荐的leader为获胜的Server,将根据获胜的Server相关信息设置自己的状态,否则,继续这个过程,直到leader被选举出来。
通过流程分析我们可以得出:要使Leader获得多数Server的支持,则Server总数必须是奇数2n+1,且存活的Server的数目不得少于n+1.
每个Server启动后都会重复以上流程。在恢复模式下,如果是刚从崩溃状态恢复的或者刚启动的server还会从磁盘快照中恢复数据和会话信息,zk会记录事务日志并定期进行快照,方便在恢复时进行状态恢复。选主的具体流程图如下所示:
fast paxos流程是在选举过程中,某Server首先向所有Server提议自己要成为leader,当其它Server收到提议以后,解决epoch和zxid的冲突,并接受对方的提议,然后向对方发送接受提议完成的消息,重复这个流程,最后一定能选举出Leader。其流程图如下所示:
14.2 同步流程
选完leader以后,zk就进入状态同步过程。
-
leader等待server连接;
-
Follower连接leader,将最大的zxid发送给leader;
-
Leader根据follower的zxid确定同步点;
-
完成同步后通知follower 已经成为uptodate状态;
-
Follower收到uptodate消息后,又可以重新接受client的请求进行服务了。
流程图如下所示:
14.3 Leader工作流程
Leader主要有三个功能:
-
恢复数据;
-
维持与Learner的心跳,接收Learner请求并判断Learner的请求消息类型;
-
Learner的消息类型主要有PING消息、REQUEST消息、ACK消息、REVALIDATE消息,根据不同的消息类型,进行不同的处理。
PING消息是指Learner的心跳信息;REQUEST消息是Follower发送的提议信息,包括写请求及同步请求;ACK消息是Follower的对提议的回复,超过半数的Follower通过,则commit该提议;REVALIDATE消息是用来延长SESSION有效时间。
Leader的工作流程简图如下所示,在实际实现中,流程要比下图复杂得多,启动了三个线程来实现功能。
14.4 Follower工作流程
Follower主要有四个功能:
-
1. 向Leader发送请求(PING消息、REQUEST消息、ACK消息、REVALIDATE消息);
-
2 .接收Leader消息并进行处理;
-
3 .接收Client的请求,如果为写请求,发送给Leader进行投票;
-
4 .返回Client结果。
Follower的消息循环处理如下几种来自Leader的消息:
-
1 .PING消息: 心跳消息;
-
2 .PROPOSAL消息:Leader发起的提案,要求Follower投票;
-
3 .COMMIT消息:服务器端最新一次提案的信息;
-
4 .UPTODATE消息:表明同步完成;
-
5 .REVALIDATE消息:根据Leader的REVALIDATE结果,关闭待revalidate的session还是允许其接受消息;
-
6 .SYNC消息:返回SYNC结果到客户端,这个消息最初由客户端发起,用来强制得到最新的更新。
Follower的工作流程简图如下所示,在实际实现中,Follower是通过5个线程来实现功能的。
对于observer的流程不再叙述,observer流程和Follower的唯一不同的地方就是observer不会参加leader发起的投票。