分布式系统的一致性与共识算法(三)

顺序一致性(Sequential Consistency)

ZooKeeper

一种说法是ZooKeeper是最终一致性,因为由于多副本、以及保证大多数成功的ZAB协议,当一个客户端进程写入一个新值,另外一个客户端进程不能保证马上就能读到这个值,但是能保证最终能读取到这个值。另外一种说法是ZooKeeper的ZAB协议类似于Paxos,提供了强一致性。但这两种说法都不准确,ZooKeeper文档中明确写明它的一致性是Sequential Consitency即顺序一致。ZooKeeper中针对同一个FollowerA提交的写请求request1、request2,某些Follower虽然可能不能在提交成功后立即看到(也就是强一致性),但经过自身与Leader之间的同步后,这些Follower在看到这连个请求时,一定是先看到request1,request2,两个请求之间不会乱序,即顺序一致性。
其实,实现ZooKeeper的一致性更复杂一些,ZooKeeper的读操作是sequential consistency的,ZooKeeper的写操作是linearizability的,关于这个说法,ZooKeeper的官方文档中没有写出来,但是在社区的邮件组有详细的讨论。ZooKeeper的论文《Modular Composition of Coordination Services》中也有提到这个观点。

总结一下,可以这么理解ZooKeeper:从整体(read操作 + write操作)上来说是sequential consistency,写操作实现了Linearizability

线性一致性(Linearizability)

线性一致性又被称为强一致性、严格一致性、原子一致性。是程序能实现的最高的一致性模型,也是分布式系统用户最期望的一致性。CAP中的C一般就指它。顺序一致性中进程只关心大家认同的顺序一样就行,不需要与全局时钟一致,线性就更严格,从这种偏序(partial order)要达到全序(total order)要求是:

  • 1.任何一次读都能读到某个数据的最近一次写的数据
  • 2.系统中的所有进程,看到的操作顺序,都与全局时钟下的顺序一致。

以前面讲的例3继续讨论:

B1看到X的新值,C1反而看到的是旧值,即对用户来说,x的值发生了回跳

在线性一致的系统中,如果B1看到的x值为1,则C1看到的值也一定为1。任何操作在该系统生效的时刻都对应时间轴上的一个点。如果我们把这些时刻连接起来,如图中紫线所示,则这条线会一致沿时间轴向前,不会反向回跳。所以任何操作都需要互相比较决定,谁发生在前,谁发生在后。例如B1发生在A0之前,C1发生在A0之后,而在前面顺序一致性模型中,我们无法比较诸如B1和A0的先后关系。线性一致性的理论在软件上有哪些体现呢?
在这里插入图片描述

etcd与raft

上面提到ZooKeeper的写是线性一致性,读是顺序一致性。而etecd读写都做了线性一致,即etcd是标准的强一致性保证。
etcd是基于raft来实现的,raft是共识算法,虽然共识和一致性的关系很微妙,经常一起讨论,但共识算法只是提供基础,要实现线性一致还需要在算法之上做出更多的努力如库封装,代码实现等。如Raft中对于一致性读给出了两种方案,来保证处理这次读请求的一定是Leader:

  • 1.ReadIndex
  • 2.LeaseRead
    基于Raft的软件有很多,如etcd、tidb、SOFAJRaft等,这些软件在实现一致读时都是基于这两种方式。这里对ReadIndex和Lease Read做下解释,即etcd中线性一致性读的具体实现。由于在Raft算法中,写操作成功仅仅意味着日志达成了一致(已经落盘),而并不能确保当前状态机也已经apply了日志。状态机apply日志的行为在大多数Raft算法的实现中都是异步的,所以此时读取状态机并不能准确反映数据的状态,很可能会读到过期数据。
    基于以上这个原因,要想实现线性一致性读,一个交为简单通用的策略就是:每次读操作的时候记录此时集群的committed index,当状态机的apply index大于或等于committed index时才读取数据并返回。由于此时状态机已经把度请求发起时的已提交日志进行了apply动作,所以此时状态机的状态就可以响应度请求发起时的状态,符合线性一致性读的要求。这便是ReadIndex算法。
    那如何准确获取集群的committed index?如果获取到的committed index不准确,那么以不准确的committed index为基准的ReadIndex算法讲可能拿到过期数据。为了确保committed index的准确,我们需要:
  • 1.让leader来处理读请求
  • 2.如果follower收到读请求,将请求forward给leader
  • 3.确保当前leader仍然是leader
    leader会发起一次广播请求,如果还能收到大多数节点的应答,则说明此时leader还是leader.这点非常关键,如果没有这个环节,leader有可能因网络分区等原因已不再是leader,度请求依然由过期的leader处理,那么久将有可能读到过去的数。这样,我们从leader获取的committed index久作为此次读请求的ReadIndex.

以网络分区为例:

在这里插入图片描述

  • 1.初始状态时集群有5个节点:A、B、C、D和E,其中A是leader;
  • 2.发生网络隔离,集群被分割成两部分,一个A和B,另外一个是C、D、E。虽然A会持续向其他介个节点发送headerbeat,但由于网络隔离,C、D、E将无法接收到A的heartbeat。默认地,A不处理向follower节点发送heartbeat失败(此处为网络超时)的情况(协议没有明确说明heartbeat是一个必须收到follower ack的双向过程);
  • 3.C、D、E组成的分区在经过一定时间没有收到leader的heartbeat后,触发election timeout,此时C成为leader.此时,原来5节点集群因网络分区分割成两个集群:小集群A和B;大集群C、D、E,C为leader
  • 4.此时客户端进行读写操作。在Raft算法中,客户端无法感知集群的leader变化(更无法感知服务端有网络隔离的事件发生)。客户端在向集群发起读写请求时。如果客户端一开始选择C节点,并成功写入数据(C节点集群已经commit操作日志),然后因客户端某些原因(比如断线重连),选择节点A进行读操作。由于A并不知道另外3个节点已经组成当前集群的大多数并写入了新的数据,所以节点A无法返回准确的数据。此时客户端将读到过期数据。不过相应地,如果此时客户端向节点A发起写操作,那么写操作将失败,因为A因网络隔离无法收到大多数节点的写入响应
  • 5.针对上述情况,其实节点C、D、E组成的新集群才是当前5节点集群中大多数,读写操作应该发生在这个集群中而不是原来的小集群(节点A和B).如果此时节点A能感知它已经不再是集群的leader,那么节点A将不再处理读写请求。于是,我们可以在leader处理读写请求时,发起一次check quorum环节:
    leader向集群的所有节点发起广播。当leader还能收到集群大多数节点的响应,说明leader还是当前集群的有效leader,拥有当前集群完整的数据,否则,读请求失败,将迫使客户端崇训选择新节点进行读写

这样一来,Raft算法久可以保障CAP中的C和P,但无法保障A:网络分区时并不是所有节点都可以响应请求,少数节点的分区将无法进行服务,从而不符合Availablility。因此,Raft算法是CP类型的一致性算法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/13036.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

我的第一个网页:武理天协

1. html代码 1.1 首页.html <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><title>武理天协</title><link rel"stylesheet" href"./style.css"><link rel"stylesh…

【车载开发系列】SID$11服务配置

【车载开发系列】SID$11服务配置 前言 ECUReset(ECU重置),ECU作为Server端,执行Client发送来ECU Reset请求中重启的类型(通过子服务区分)。对于UDS协议关于处理该请求的逻辑,没有强制性定义。 Step1:SID和SubFunction的追加 BasicEditor→Dcm→DcmConfigSet→DcmDs…

vs2019 c++里用 typeid() . name () 与 typeid() . raw_name () 测试数据类型的区别

&#xff08;1&#xff09; 都知道&#xff0c;在 vs2019 里用 typeid 打印的类型不大准&#xff0c;会主动去掉一些修饰符&#xff0c; const 和引用 修饰符会被去掉。但也可以给咱们验证学到的代码知识提供一些参考。那么今天发现其还有 raw_name 成员函数&#xff0c;这个函…

AES分组密码

一、AES明文和密钥位数 RIJNDAEL 算法数据块长度和密钥长度都可独立地选定为大于等于 128 位且小于等于 256 位的 32 位的任意倍数。 而美国颁布 AES 时却规定数据块的长度为 128 位、密钥的长度可分别选择为 128 位&#xff0c; 192 位或 256 位 1.1 状态 中间结果叫做状态…

建模:3dmax

3Dmax 制作模型和动画&#xff08;橘肉&#xff09;&#xff1b; RizomUV 对模型进行展UV&#xff08;橘皮&#xff09;&#xff1b; Substance Painter 纹理手绘&#xff08;给橘皮制定想要的皮肤&#xff09;&#xff1b; 1.基础 1.1可编辑多边形、可编辑样条线 体、面都需要…

Polylang Pro插件下载:多语言网站构建的终极解决方案

在全球化的今天&#xff0c;多语言网站已成为企业拓展国际市场的重要工具。然而&#xff0c;创建和管理一个多语言网站并非易事。幸运的是&#xff0c;Polylang Pro插件的出现&#xff0c;为WordPress用户提供了一个强大的多语言解决方案。本文将深入探讨Polylang Pro插件的功能…

linux上git 使用方法

一、git上新建仓库 在git上新建仓库&#xff0c;并命名 二、本地初始化 //命令行 ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" //ssh查看 cd /root/.ssh/ vim rsa.pub //复制后粘贴进git网页设置里的ssh key //测试设置是否成功 ssh -T gitgithub.com/…

暴力数据结构之二叉树(堆的相关知识)

1. 堆的基本了解 堆&#xff08;heap&#xff09;是计算机科学中一种特殊的数据结构&#xff0c;通常被视为一个完全二叉树&#xff0c;并且可以用数组来存储。堆的主要应用是在一组变化频繁&#xff08;增删查改的频率较高&#xff09;的数据集中查找最值。堆分为大根堆和小根…

Spring事务的实现原理

Spring事务原理 Spring框架支持对于事务的管理功能&#xff0c;开发人员使用Spring框架能极大的简化对于数据库事务的管理操作&#xff0c;不必进行手动开启事务&#xff0c;提交事务&#xff0c;回滚事务&#xff0c;就是在配置文件或者项目的启动类配置Spring事务相关的注解…

什么是最大路径?什么是极大路径?

最近学习中&#xff0c;在这两个概念上出现了混淆&#xff0c;导致了一些误解&#xff0c;在此厘清。 最大路径 在一个简单图G中&#xff0c;u、v之间的距离 d ( u , v ) min ⁡ { u 到 v 的最短路的长度 } d(u,v) \min \{ u到v的最短路的长度 \} d(u,v)min{u到v的最短路的…

wefaf

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…

使用Bash脚本和Logrotate实现Nginx日志切割

Nginx是一个广泛使用的高性能Web服务器&#xff0c;它能够处理大量的并发连接&#xff0c;但同时也会生成大量的日志文件。为了有效管理这些日志文件并确保系统的正常运行&#xff0c;我们需要定期对Nginx的日志文件进行切割和归档。本文将介绍如何使用Bash脚本和Logrotate来实…

每天Get一个小技巧:用DolphinScheduler实现隔几天调度

转载自tuoluzhe8521 这篇小短文将教会你如何使用Apache DolphinScheduler实现隔几天调度&#xff0c;有此需求的小伙伴学起来&#xff01; 1 场景分析 DolphinScheduler定时器模块-定时调度时每3秒|每3分钟|每3天这种定时&#xff0c;不能够跨分钟&#xff0c;跨小时&#x…

【C++】:string类的基本使用

目录 引言一&#xff0c;string类对象的常见构造二&#xff0c;string类对象的容量操作三&#xff0c;string类对象的访问及遍历操作四&#xff0c;string类对象的修改操作五&#xff0c;string类非成员函数六&#xff0c;整形与字符串的转换 引言 string 就是我们常说的"…

如何对SQL Server中的敏感数据进行加密解密?

为什么需要对敏感数据进行加密&#xff1f; 近几年有不少关于个人数据泄露的新闻&#xff08;个人数据通常包含如姓名、地址、身份证号码、财务信息等&#xff09;&#xff0c;给事发公司和被泄露人都带来了不小的影响。 许多国家和地区都出台了个人数据保护的法律法规&#…

Unity Animation--动画窗口指南(使用动画视图)

Unity Animation--动画窗口指南&#xff08;使用动画视图&#xff09; 使用动画视图 window -> Animation 即可打开窗口 查看GameObject上的动画 window -> Animation -> Animation 默认快捷键 Ctrl 6 动画属性列表 在下面的图像中&#xff0c;“动画”视图&am…

思科模拟器--2.静态路由和默认路由配置24.5.15

首先&#xff0c;创建三个路由器和两个个人电脑。 接着&#xff0c;配置两台电脑的IP&#xff0c;子网掩码和默认网关 对Router 0&#xff0c;进行以下命令&#xff1a; 对Router进行以下命令&#xff1a; 对Router2进行以下命令&#xff1a; 本实验完成。 验证&#xff1a;PC…

Vue3+ts(day06:路由)

学习源码可以看我的个人前端学习笔记 (github.com):qdxzw/frontlearningNotes 觉得有帮助的同学&#xff0c;可以点心心支持一下哈&#xff08;笔记是根据b站上学习的尚硅谷的前端视频【张天禹老师】&#xff0c;记录一下学习笔记&#xff0c;用于自己复盘&#xff0c;有需要学…

【ARMv8/v9 系统寄存器 5 -- ARMv8 Cache 控制寄存器 SCTRL_EL1 使用详细介绍】

关于ARM Cache 详细学习推荐专栏&#xff1a; 【ARM Cache 专栏】 【ARM ACE Bus 与 Cache 专栏】 文章目录 ARMv8/v9 Cache 设置寄存器ARMv8 指令 Cache 使能函数测试代码 ARMv8/v9 Cache 设置寄存器 关于寄存器SCTRL_EL1 的详细介绍见文章&#xff1a;【ARMv8/v9 异常模型入…

纯正英语新闻 5.15

seizing territory &#xff1a;夺取领土 battlefield:战场 shrinking&#xff1a;缩小 paramedic&#xff1a;医护人员 mercilessly destroy&#xff1a;无情地摧残 blown up&#xff1a;炸毁 northern outskirts :北郊 terrified&#xff1a;害怕 shelling&#xff…