数据一致性分析

常见三副本kv存储系统架构介绍

  目前很多常见的分布式存储系统都是基于三副本机制的,如ceph、小米的飞马系统等
  一般由三个部分组成,实现kv存储层(如ceph的osd)、client端(发起io操作)以及mds(metadata server)    
  1. kv存储层实现持久存储和io复制
  2. client实现io分发
  3. mds管理包括kv存储层进程状态、数据分布

数据分布算法

  hash算法根据数据的key将数据映射到物理存储节点上,这种作为在存储节点扩减容时,会导致大量数据迁移。
  一致性hash是将物理节点组成一个环,计算出hash值后,将数据路由到hash值后面最近的一个节点上,这样当一个节点失效时,数据只用迁移到下一个节点上。
  这种物理节点直接参与映射的方式,可能导致数据倾斜,所以引入虚拟节点(ceph中的pg),虚拟节点数目为物理节点的数倍。引入虚拟机节点有两个好处:
  1. 数据是存放在固定虚拟节点上的
  2. 我们管理虚拟节点到物理节点的映射时,可以根据物理节点是否在同一个机架等来影响数据的分布,减小故障域。
  3. 每个虚拟节点组成一个复制组,各虚拟节点之间数据没有关联,这样可以增加并发。

一次写io过程

  1. mds节点管理着虚拟节点到数据副本的映射关系,包括虚拟节点对应的各个数据副本所在存储节点,各副本的状态信息。
  2. client节点缓存着虚拟节点到主副本信息,kv存储层缓存着虚拟节点到主副本信息和虚拟节点的三副本信息。

这些信息都是从mds查询的

  1. client节点根据数据的key计算出虚拟节点,在根据虚拟节点找到主副本物理节点,然后将io发送给主副本节点。
  2. 主副本节点收到请求后,将数据写入本地,同时复制给其他副本,等到副本都写成功后,响应给client。

常见三副本存储系统如何保证数据一致性呢?

  有如下三个要素:
  1. 基于日志复制的方式,保证日志在各副本顺序一致,那么根据日志回放出来的数据,最终状态也将趋于一致。
  2. 主副本会将更新操作发送到各个副本,只有各个副本都回复写成功后,才会响应client端。

如果一切正常,上面两点足够保证数据一致了,因为从client的视角看,各副本是强一致的,发生主副本切换,也不影响数据一致性。

  1. 主副本故障时,mds选新主副本时,必须选状态正常的副本。(领导选举)

这里说的状态正常即新的主与原来的主数据一致。

上面保证了数据在副本之间的一致性,另外还要关注出现网络分区副本之间出现脑裂时,如果保证线性一致性,不会发生stale read

一条条解释

请求ID

主副本对每个更新操作维护一个ReqID,收到更新操作ReqID++

任期

每次主副本切换,看成是一个新的任期,TermID++,ReqID置0

备副本切换,需要更新任期吗??? --- 不需要,TermID只关心主副本
<TermID, ReqID>可以唯一定位一个更新操作

日志顺序一致

日志:记录了更新操作(写、删)的位置、长度、操作类型以及<TermID, ReqID>。可以看到日志中没有记录数据,所以,日志可以增加一个状态,表示数据部分是否以及落盘。注意日志本身也是持久化存储的,可以放在高速ssd或者nvram中。

  1. 主副本收到更新请求,会检查client端发送来的请求TermID是否与自己的相同,相同时,会自增ReqID(也会持久化),并本地记录一条日志(日志为未提交状态);然后触发数据本地落盘和发送给备同时进行

TermID不同时,会触发TermID较小的一方反查映射信息
本地持久化成功后,回调中将日志提交

  1. 备副本收到请求时,首先检查TermID与主副本的是否一致,如果自己的老就反查视图,否则拒绝请求。
    如果TermID一致,会检查自己的ReqID的连续性,如果比收到的主副本的仅仅小1,刚刚好,如果比主副本小很多,说明丢了消息,拒绝;如果不小于收到的,说明是重入消息接受。

等于1的时候 是否要接受??? -- 接受,但不更新本地持久化的reqid

备副本异常

各个副本节点都和mds保持心跳,每秒一次,5次mds将这个副本设置为异常。

  1. 主副本将数据复制到备副本时,有超时重试机制,等待备回复ok
  2. 如果备副本异常了,mds会通知主副本,备已经异常,无需等待这个副本回复。

这里非常重要,是mds通知主副本备异常了,所以如果这个场景,发生切主时,mds一定不会选择这个异常的备

备副本异常恢复

备副本从故障中恢复时,由于有部分io自己没有,这种状态的备会被mds标记为catchup状态,它也没有升主资格。
当这个备catchup完成时,会将自己catchup完成上报给mds,mds将起状态标记为正常,恢复了升主资格。
catchup过程:

  1. 备先根据自己本地log中最新的<TermID, ReqID>去主副本上确认自己缺少哪些数据,然后从主上将这些数据读回来,写到本地
  2. 在第一步的过程中,备副本收到的新io会记录到另一片区域(避免与catchup io发生写覆盖),等第一步完成后,再将这部分数据写到真正的位置上。
  3. 在第一二步都完成后,向mds上报自己catchup完成。

映射关系变更

主副本异常后,会从正常的备中选一个新主;无论是主、备,只有在异常达到一定时间后才会被隔离出集群。
主副本异常与mds心跳断开几秒后,mds会从正常的备中选一个当作新主

从以上介绍中,可以看出mds在备副本是否具有升主资格是绝对可靠的,所以在切主时,一定不会将主切到一个数据与老主不一致的副本上。

一个异常场景

主副本日志状态未提交,备副本数据落盘成功并且日志提交了

  1. 此时全局掉电会发生什么

全局掉电时,各副本所在服务器都挂了,各副本起来之后不会发生切主操作 ? 关注一下这种场景数据怎么恢复的
主还是老主,备进行catch up时,主会将未提交的日志复制给备,备把本地已提交的日志改为未提交 ???

  1. 此时主副本网络闪断会发生什么

切主,之前的写请求,备上已提交,老主恢复后,向新主拿数据,本地未提交的日志会被改为提交??

posted @ 2020-08-01 16:11  holidays  阅读(1308)  评论(0编辑  收藏  举报