1、zookeeper:
zookeeper的节点组织结构:与标准文件系统的名称空间非常相似
zookeeper的节点包括三种类型:
- 「持久节点」(persistent node)节点会被持久
- 「临时节点」(ephemeral node),客户端断开连接后,ZooKeeper 会自动删除临时节点
- 「顺序节点」(sequential node),每次创建顺序节点时,ZooKeeper 都会在路径后面自动添加上10位的数字,从1开始,最大是2147483647 (2^32-1)
zookeeper的系统架构:
Zookeeper 集群中「Server有三种角色」,Leader、Follower 和 Observer
- 「Leader」:负责投投票的发起与决议,更新系统状态,写数据
- 「Follower」:用于接收客户端请求并用来返回结果,在选主过程中参与投票
- 「Observer」:可以接受客户端连接,将「写请求转发给leader」节点,但是不参与投票过程,只「同步leader状态」,主要存在目的就是「为了提高读取效率」
将 server 分为三种是为了「避免太多的从节点参与过半写」的过程,导致影响性能,这样 Zookeeper 只要使用一个几台机器的小集群就可以实现高性能了,如果要横向扩展的话,只需要增加 Observer 节点即可。
Zookeeper 建议集群节点个数为奇数,只要「超过一半的机器」能够正常提供服务,那么整个集群都是可用的状态。
ZooKeeper 启动时,将从实例中选举一个 leader,「Leader 负责处理数据更新」等操作,一个更新操作成功的标志是当且仅当大多数 Server 在内存中成功修改数据。每个 Server 在内存中存储了一份数据。
zookeeper的leader如果挂了怎么办:
-
1.「变更状态」。Leader 挂后,余下的非 Observer 服务器都会讲自己的服务器状态变更为 LOOKING,然后开始进入 Leader 选举过程。
-
2.每个「非 Observer」 的 Server 会「发出一个投票」。和启动过程一致。
-
3.「接收」来自各个服务器的「投票」。与启动时过程相同。
-
4.「处理投票」。与启动时过程相同。
-
5.「统计投票」。与启动时过程相同。
-
6.「改变服务器的状态」。与启动时过程相同。
Zookeeper 会有数据不一致的情况发生吗?
还是会有的,因为 Zookeeper 采用的是「过半写」机制,意味着「3台服务器只要有两台写成功就代表整个集群写成功」,如果刚好有请求打在这台还「未写的服务器」上就查询不到该数据,就会有数据不一致的情况产生。
zookeeper核心功能是:
1、服务注册发现
2、近似与服务注册发现的配置管理功能
3、稳定实现分布式锁
1、服务注册发现
服务提供方:
a、上线后要通知zookeeper,在"/XXX服务/"下创建临时节点。
b、周期性的不停注册自己,也就是保持和zookeeper的心跳,alive
服务使用方:
a、也需要告诉zookeeper,自己是一个使用方
b、从"/XXX服务/"下创建的临时节点,作为自己使用的服务端
2、其他近似与服务注册发现的配置管理功能:
以管理主从型系统为例:slave注册一个临时节点,master被通知,过一段时间slave挂了,master知道了。
3、稳定实现分布式锁
利用zookeeper的临时顺序节点,每个需求抢占分布式锁的客户端们,都创建自己的临时顺序节点,创建id=1的客户端首先抢到锁,创建id=2的客户端则watch这个id=1的节点的销毁事件,然后以此类推,创建id=n的客户端监听id=n-1节点的销毁事件。
扩展:分布式读写锁
对于需要读的:拉取目录下全部节点,只要自己前边没有写节点,那么就可以读
如果前边有写节点,watch最近的写节点的销毁事件
对于需要写的:拉取目录下全部节点,如果自己是第一个节点(id=1),那么就可以写
否则,watch最近的读或写节点的销毁事件
2、分布式
2.0、分布式的本质:
什么叫去中心化,去中心化不是没有中心了,而是说每个节点都可能可以成为中心。目的是不希望因为某个节点出现问题导致整个系统出现问题,也就是保证高可用。
2.1、分片的方式
一致性hash:
原始的简单一致性hash:
比如我们有三台机器,使用IP地址哈希后在环空间的位置如图:
现在有ObjectA,ObjectB,ObjectC三个数据对象,经过哈希计算后,在环空间上的位置如下:
根据一致性算法,Object A-> NodeA,ObjectB -> NodeB, ObjectC -> NodeC
具体的就是,通过二分查找,找到第一个比object的hash值大的node的hash值。
假设我们的Node C宕机了,我们从图中可以看到,A、B不会受到影响,只有Object C对象被重新定位到Node A。所以我们发现,在一致性Hash算法中,如果一台服务器不可用,受影响的数据仅仅是此服务器到其环空间前一台服务器之间的数据
另外一种情况,现在我们系统增加了一台服务器Node X :
ObjectA、ObjectB没有受到影响,只有Object C重新定位到了新的节点X上
高级一致性hash:
如果服务节点没有那么多,那么会造成大量的请求,去往下一个节点处理,造成下一个节点负载暴增。
解决:引入虚拟节点概念:
图中的A1、A2、B1、B2、C1、C2、D1、D2都是虚拟节点,机器A负载存储A1、A2的数据,机器B负载存储B1、B2的数据,机器C负载存储C1、C2的数据。由于这些虚拟节点数量很多,均匀分布,因此不会造成“雪崩”现象 。
因为当某真实节点崩溃,其原先负载处理的请求,会散列在不同真实节点。
hash槽:
固定的槽位区间和机器节点的关系。Redis cluster的方式。
2.2、raft
Raft是一个用于管理日志一致性的协议。它将分布式一致性分解为多个子问题:Leader选举(Leader election)、日志复制(Log replication)、安全性(Safety)、日志压缩(Log compaction)等。同时,Raft算法使用了更强的假设来减少了需要考虑的状态,使之变的易于理解和实现。Raft将系统中的角色分为领导者(Leader)、跟从者(Follower)和候选者(Candidate):
-
Leader:接受客户端请求,并向Follower同步请求日志,当日志同步到大多数节点上后告诉Follower提交日志。
-
Follower:接受并持久化Leader同步的日志,在Leader告之日志可以提交之后,提交日志。
-
Candidate:Leader选举过程中的临时角色
leader选举完成后,只有leader和follower两种角色了。
重点是日志复制(保证数据一致性):
Leader选出后,就开始接收客户端的请求。Leader把请求作为日志条目(Log entries)加入到它的日志中,然后并行的向其他服务器发起 AppendEntries RPC复制日志条目。当这条日志被复制到大多数服务器上,Leader将这条日志应用到它的状态机并向客户端返回执行结果。
日志由有序编号(log index)的日志条目组成,每个日志条目包含它被创建时的任期号(term)和用于状态机执行的命令。
-
客户端的每一个请求都包含被复制状态机执行的指令。
-
leader把这个指令作为一条新的日志条目添加到日志中,然后并行发起 RPC 给其他的服务器,让他们复制这条信息。
-
假如这条日志被安全的复制,领导人就应用这条日志到自己的状态机中,并返回给客户端。
-
如果 follower 宕机或者运行缓慢或者丢包,leader会不断的重试,直到所有的 follower 最终都复制了所有的日志条目。
Raft数据一致性如何实现:
主要是通过日志复制实现数据一致性,leader将请求指令作为一条新的日志条目添加到日志中,然后发起RPC 给所有的follower,进行日志复制,进而同步数据。
最后的重点是:
-
当leader挂掉后,时钟最先跑完的follower发起重新选举操作,选出一个新的leader。
-
成员变更的时候会发起选举操作。(Rebalance)