[问答体]计算机论文阅读笔记

325 阅读1小时+

介绍

本文介绍了一些我读过的论文和心得体会,以对话体编写,主要求个生动有趣。

本文长期更新,除非到达10万字(我会开第二期),欢迎关注,常来看看。

更新记录

  • 2024-04-24 整理好以往的内容,发布出来
  • 2024-04-30 整理了写作技术文档的必要
  • 2024-05-03 整理了samza论文的阅读过程

目录

  • 技术文档写作的必要
  • 如何阅读论文
  • Raft论文阅读笔记
  • Kafka论文阅读笔记

Raft论文阅读笔记

对话阅读

论文介绍

1 为什么要读读raft论文?

答: 一致性协议是分布式系统绕不开的话题, 而raft则是非常流行的一个一致性协议.

一致性协议问题,研究的是不同的副本如何保持一致的问题。

为什么要有不同的副本呢?因为副本可以备份,提高系统的容灾能力。

副本还可以提供查询功能,实现负载分摊,比如只读副本。

2 讲一下raft协议的背景?

答: 据说是因为paxos协议太难了,然后为了教学和简化学习难度, 斯坦福大学某CS大佬研究出了raft, 大致是这样吧. 翻译过来是竹筏,竹筏确实很简洁.

3 有中文翻译的原稿吗?

答:有的. www.infoq.cn/article/raf… 这篇文章翻译的不错,第一眼感觉, 它是把论文完整的翻译了一遍. Github上还有一篇,maemual/raft-zh_cn: Raft一致性算法论文的中文翻译 (github.com)

4 英文原稿的篇幅介绍一下?

答: 英文原稿有18页,非常的长,相比 kafka论文而言, 同学说, 现在的论文越来越长,越来越细节. 论文的名字是: In search of an Understandable consensus Algorithm(Extended Version), 作者 Deigo Ongaro, John Ousterhout, Stanford University.

5 摘要了讲了什么?

答: 摘要了讲了, raft 设计的目的是为了基于paxos更简单,为了教学.论文中证明了怎么有利于教学的,这是一个很新奇的地方,让人怀疑这是一篇教育领域相关的论文了都. 摘要提了几点一致性协议相关的东西, 比如,选主,操作日志记录,多数派共识等等.

6 其余部分呢?

答: 有十几个标题,大致分别如下: 1 introduction 2 replicated state machine 3 what's wrong with paxos? 4 如何体现可理解性 5 details of raft design(核心部分)(page3-page10) 6 cluster membership 7 log compaction 日志压缩 8 客户端交互 9 实现和评估 10 相关工作 11 结论

大家看,第5章是本文的核心,从篇幅可以看出来, 关于6,7,8 三部分是第5部分的延伸,而2,3 则可以归为 相关工作或者说背景介绍.

读论文不必从最难最重要的部分开始,不妨从一个最简单最容易有成就感的部分开始,我选择第3部分开始. 先见识一下paxos是什么,这是我第一次看paxos的解释,不妨挖个坑, 以后再写一篇关于 paxos 论文的解读.

背景知识

7 请你讲一下paxos有什么问题?

答: Raft文章中说了,paxos有几个毛病,首要的就是太复杂了。第二个毛病就是设计过于理论而难以落地实践,很多系统参考paxos开始设计,然后发现这个理论很容易证明,但是很难实现,实现起来成本过高,最后弃之不用,另开新路,费时费力。paxos协议 几乎是等同于一致性协议,而且总是被用来教学,然而实际应用却比较艰难. 作者举chubby ,一个google家的分布式锁, 的评论说, paxos的理论和实际的需要截然不同,实际实现的系统仍然是基于没有被证明的理论。

7.1 你的意思是作者说paxos是个绣花枕头?

答: 差不多意思. 作者说, paxos协议 几乎是等同于一致性协议,而且总是被用来教学,然而实际应用却比较艰难. 作者举chubby ,一个google家的分布式锁, 的评论说, paxos的理论和实际的需要截然不同,实际实现的系统仍然是基于没有被证明的理论. 也许是这篇论文的缘故吧,我们不能否则它为了批评而批评, 但是可以继续看下去.

8 接下来应该看什么地方呢?

答: 看第2部分, 备份状态机器. 这块我看了下, 第一感觉是头晕目眩,因此借助中文翻译来看一下, 其中涉及了一个有趣的概念,叫拜占庭将军问题.

借用百度百科,在此科普一下:

拜占庭位于如今的土耳其的伊斯坦布尔,是东罗马帝国的首都。由于当时拜占庭罗马帝国国土辽阔,为了达到防御目的,每个军队都分隔很远,将军与将军之间只能靠信差传消息。在战争的时候,拜占庭军队内所有将军和副官必须达成一致的共识,决定是否有赢的机会才去攻打敌人的阵营。但是,在军队内有可能存有叛徒和敌军的间谍,左右将军们的决定又扰乱整体军队的秩序。在进行共识时,结果并不代表大多数人的意见。这时候,在已知有成员谋反的情况下,其余忠诚的将军在不受叛徒的影响下如何达成一致的协议,拜占庭问题就此形成。

咱们看一下, 拜占庭将军是借用一个历史典故, 说必须一致决定才能做一件事,然而现实条件不允许,因此怎么办呢? 这就引出了一致性协议的问题, 有趣. 当然,这个故事也是在 paxos论文里提出来的, 由该论文的作者提出.

事实是拜占庭帝国的将军不可能这么傻, 只是作者自己简化问题, 以此举个例子. 也许将军之间的通信和达成一致的问题没有办法完美的解决,但是绝对会想出一个务实的方式,而非等到21世纪一群研究计算机的人来给出答案.

一般的一致性算法忽略拜占庭将军问题,认为各个节点都是诚实的,没有破坏性的,包括Raft在内。

8.1 备份状态机如何理解?

答: 有一个事实我必须告诉你. 任何英文词翻译过来,硬生生翻译过来必然会给他们蒙上神秘的色彩,不是因为别的, 而是因为生硬和陌生. 举个例子吧, 我们习以为常的老干妈, 西方人会怎么翻译? 神秘东方辣酱? 什么是老干吗? old dry mother? old god mother?都是不准确的. Replicated state machine 也是如此. 翻译成复制状态机,备份状态机, 很正常也很合理,但是总是让人感觉有点奇怪, 翻译中为了效率难以做到信达雅.

备份状态机的出发点是,如果每个操作的输入一定,那么输出也一定是相同的,就像简单的函数一样确定.所以只要一台机器记录顺序操作, 把这个操作顺序放到其他机器上面执行一遍, 那么其他机器肯定也是一样的状态. 一致性协议研究的就是如何实现这个问题,因为总会遇到很多奇怪的难题.

8.2 一致性算法到底研究的是什么问题?

答: 这个问题是这篇论文的出发点和落脚点, 也是一致性算法的核心所在,它到底研究什么问题呢?在第二部分中,也就是备份状态机中, 大致说了一致性算法研究以下几点:

  1. 复杂环境下的容灾(网络断开,数据丢失等等)
  2. 以多数可用为基础,比如5台机器可以允许坏掉任意两台.
  3. 时间顺序不能作为保证一致性的依据,因为存在网络时延等情况.
  4. 如果一个rpc调用被多数服务器响应了,那么就算通过了.

其实一致性协议最后也许研究的是,如何在半数一样通过和所有人(机器)保持一致之间形成一个微妙的平衡.

我们人类社会也是,很难说所有人都同意一件事情,简单情况下,只要多数人同意,那么这事就算过了. 但是不同的组织对多数的定义不一样,美国的上下议院就很多事情通过的标准不一样, 弹劾总统2/3可能,通过一项法案可能要过1/2,等等.

  1. 现在应该看哪一部分呢?

答: 现在我看introduction部分. 当我看了后面几部分,再回过头来看 第一部分introduction的时候,发现确实简单了很多. 总而言之, 第一部分详细的介绍了为什么要设计Raft的原因,以及核心设计原则: 可理解性, 以及为了实现可理解的两个具体手段:拆分和简化设计.

9.1 为什么你不用中文标点符号,这样很不规范啊?

答: 因为我经常写代码的时候,需要注释, 因为周围的同事习惯了使用中文注释, 我也就跟着写中文注释了, 因此中文注释和英文代码之间来回切换很麻烦, 我就选择,当中文输入法的时候, 也是用英文标点符号, 虽然不是那么纯粹,但是效率很高, 尤其是要中文和英文混着输入的时候.

10 接下来是什么部分?

答: 第四部分,为了理解而设计.

10.1 第四部分说了什么?

答:第四部分的题目是为了可理解性. 一个系统的设计需要考虑很多因素,都要兼顾,但是有些特点是矛盾的,因此需要取一个平衡值.比如: 实现起来很容易, 兼容主流操作系统等等, 而raft的原则主要是, 简单可理解,符合直觉.

其实我觉得这个原则的确实是非常正确的,简单的东西具有极强的生命力, 简单的设计需要花费极大的心血才能从蹩脚的设计中慢慢演化和诞生.这事我深有体会.

raft的设计者为了提高可理解性,使用了两个方法, 分别是:1.拆分,也就是把复杂问题拆成简单的小问题,其次,就是, 讨论几种问题,简化可能出现的情况.

raft的思路值得我们学习.

11 第10部分讲了啥?

答:第10部分讲了Relate Work,这么认为吧, 就是第十部分对比了一些 raft 和 其他系统不一样的地方, 讲了一些论文,一些系统. 我没法细看,因为我对raft不熟悉, 对这些论文和系统页不熟悉,我只能大致知道一些,有个大概的印象,待会回过头来看. 然后截止目前为之,简单的部分已经基本上被我看完了.

选主

12 第5部分是篇幅最长的,具体内容都有哪些?

答: 从第5部分的介绍来看,它讲了3部分: 选主, 复制日志,安全. 听上去挺抽象的, 复制日志又叫分发日志,也就是master如何把不同机器上的操作汇总并且分发到全部机器上面去,让他们保持一致, 就像古代皇帝下发政令到各个地方统一执行一样. 安全,就是如何保证日志完全一样, 其实是第二部分的延伸和保障.

13 读第5部分第2节选主都讲了些啥?

答: 讲了怎么选主.但是我吐槽,我读英语太慢了,什么时候能像读母语那样快呢? 很多词语你都看得懂,但是在论文中好像会用到平常用不到的意思,大大增加了阅读干扰和时长. 有点烦. 比如term这个词吧, term啥意思你说说?

选主,讲的就是如何选出一个主节点. 这个过程采用一个随机的过期时间(150-300ms)之间,如果收到了半数以上的投票就当选. 当选成功以后要定期给所有的其他节点发心跳,告诉大家,我是主节点,否则其他节点会在主节点心跳超时时发起重新选主的流程. 如果出现几个节点都发起选主的过程, 那么大家会比较一个选主的数据结构的值的大小, 论文中管这个词语叫 Term? 我不知道怎么翻译. 这个Term怎么产生的也没说. 反正就是这么一个流程.

13.1 问你一个问题,如何发出心跳?

答: 发出心跳,最简单的就是定期发出一个请求吧, 我觉得 Http也能当心跳, ip包也能当心跳, 只是一般大家用rpc, 我对rpc其实比较陌生, 我写过http的服务器,但是没有编写过 rpc的服务器, 但是应该都是一种格式,底层还是字节流. 因此应该没没啥大不了的吧. 其实我特别好奇, 如何能自己编写一个rpc服务器呢? 在之前 http服务器的基础上改造一个?

13.2 如果你改造成功,你会拿它来干什么有意思的事情?

答:我会组建一个rpc集群, 比如5个rpc服务,然后让他们提供彼此之间的服务. 做一个简单的小demo.

13.3 第5部分第1节讲了哪几部分?

答: 第5部分讲了一些基础的部分,比如给我讲清楚了 term这个词是什么意思, term在这里不是条款也不是术语的意思,是任期的意思. 也就是说, master大家轮着做的潜意思吗? 总之, term就是一段时间, 它以选举开始,以master fail 为终止, 就像换届一样, 如果一个选举在一个过期时间内, 顺利收到多半投票, 那么它就是新的master了, 它就会广而告之,大家开始新的一轮分布式生活,平淡而又枯燥.

13.4 什么时候开始一个选举过程呢?

答: 是这样的, 任何一个server都可以发起选举过程,如果它认为主节点心跳停止了, 它就可以发起了(可能要等待一段时间, 作为等待窗口期,万一主节点又挣扎着活过来了),如果在它发起之前, 收到了其他server 发起的选主, 然而它认为旧的master心跳该没有到期,该怎么办呢? 到底是等待旧的心跳, 还是响应新的选举呢? 你们要造反?我是跟着呢, 还是继续等着呢? 论文没有说, 在这一节里没有说, 我会继续读下去.

15 选举的冲突为什么会发生?

答: 13.4已经说了,当旧的server停止心跳之后, 出现了场面一度混乱,这个时候就有人站起来说, 我要当头, 你们跟我走吧. 然后这个时候, 可能不止一个人这么做, 所以就会选举冲突.

15.2 如何平息这种冲突?

答: 谁的选举号码大谁就保持, 选举号码其实是一种时间戳类似的东西, 单调递增, 先发起的选举号码比后发起的选举号码小, 如果先发起的还没来得及赢下过半数量的投票(等待其他节点回应它, 其他节点只能一次选一个候选人,不能8面玲珑,谁都投一票), 就有更新的其他选举被其他节点发起投票并且传达给这个候选人, 那么按照现有的机制, 先发起的应该该怎么办呢, 比如我的结果还没出来呢?

有两种消息, 一种是 拉选票的消息, 一种是心跳消息, 只有获得多数投票才能发起心跳信息, 心跳消息是主节点才有资格发起的, 而候选人身份只能发起拉选票的消息.

如果一个候选人收到了其他的候选人的拉选票的消息,肯定是不理会的, 在这个拉选票截止时间之内是必然不理会的.其他的投票人也一样,不能说你收到一个拉选票消息就改投这个人. 这样是永远选不出主节点的.

如果一个候选人在等待其他候选人的投票信息的时候, 收到了一个心跳消息, 如果这个心跳信息中携带的选举号(我们暂且叫选举号吧,就是它当选成功时候的选举号,作为它的主节点身份)比当前候选人收到的最后一次心跳消息的选举号更新,那么说明这是一个新的主机诶单, 自己放弃候选人身份.

什么时候一个投票人可以投其他人呢? 任何选举都有一个不定长的到期时间, 如果过了这个到期时间还没有收到来自这个节点的心跳消息, 那么就可以投别的节点了.

如果一个候选人到他选举结束之前还没有收到多数票的响应, 也没有收到其他更新的心跳消息, 那么就继续发起新的投票.

整个过程是非常直观和符合人类选举的规则的.

有一些细节是论文没说,我自己脑补的, 可能有不准确的地方, 还望指正.

15.3 选举算法为什么设计成这个样子?

答: 论文中又说,选举算法的设计, 反复的修改, 最后才变成这个样子, 是经过一番考量和试验的, 不排除拍脑袋决策的可能, 未必是最佳的算法, 但是是比较实用的算法, 这就是选择的智慧. 最后一段,有几句话我没看懂.

日志复制

16 日志复制都说了什么?

答: 日志备份可能是最长最难的部分. 请做好战斗准备. 日志复制中说了几个事, raft如何保障节点之间的日志一致的的机制, 如果不一致该怎么办. 首先,它说了复制日志的RPC消息的结构, 以及为什么要这些结构来保障日志的一致性的. 当然, 最先它说了日志的格式, 日志的格式, 论文里画了一张图. 大概包括以下几个核心内容: (1)日志的下标,假设从0开始吧,就是跟数组的下标一样. (2)日志产生的Term, 就姑且翻译为选举时期吧, 举个简单的例子,比如唐明皇的开元年间,天宝年间,清朝皇帝的康熙年间(他们皇帝换年号不是很勤快,一辈子就用一个), 雍正年间等等,就是一个产生的时期. (3)命令的具体内容.

那么复制日志的RPC消息体又是什么样的呢, 它包含以下内容: (1)命令的具体内容 (2)日志Term (3)主节点本条被复值的日志的下标 (4)主节点前一条日志的Term和下标.

第(4)个是保证一致性的关键, 如果每次发送复制日志的消息的时候都, 从节点都检查一下当前的消息里的前一条日志的Term和下标是否一致,如果一致, 就说明前面所有的日志是一样的(为什么这么说, 你自己理解递归是什么意思吧),因此就是一致的,就接受这条日志并且赋值到自己的状态机里面, 如果根据RPC消息里前一条日志的Term和下标没有在自己的日志序列(注意是序列,讲究顺序的)找到对应的日志,那么说明从节点的日志要么多了,要么少了,反正就是不一致了, 从结点就拒绝这条日志的复制. 然后主节点就开始不停的向这个从结点发RPC, 是把前一条日志的Term和下标换成更早一个日志, 如此往复, 直到找到第一条相同的日志为止, 后面所有的不同的日志都会被主节点接下来的日志覆盖.

16.1 为什么会出现日志不一致的情况?

答:因为主节点不能保证把所有的日志都复制到所有的节点上去, 只能保证多数节点有这条日志.

16.2 我举个例子, 如果有ABCDE五台机器, A是主节点, A一条日志复制到了BC和自己身上,这就是多数了, 如果A因为网络故障而掉线了,那么重新选举的时候,如果D或者E当选为主节点, 很显然他们的日志是不全的, 那么这个时候如果按你说的, 岂不是要把那一条日志删掉呢?

答: 是的. 所以说这样的机制不完善,我们会打补丁, 起码, A是主节点,它会尽力把所有的日志都复制到所有的机器上去, 如果DE掉线了, 等他们联机上来, A会联系他们并且把日志复制到他们上去. 如果恰好是DE重连之前, A掉线了, DE也开始选举自己为主节点了, 这叫新兵蛋子, 应该说是不配被选举为主节点的, 所以选主这块应该会控制,不会把刚刚掉线然后重连的机器选为主节点的.

节点架构

17 突然跳转到底8部分, 第8部分Raft都讲了什么?

答: 讲了客户端和服务器交互的事情.

17.1 具体来说?

答: raft集群中的客户端如何找到服务端的事, 以及如何实现顺序执行(这块有点不明白). 客户端首先会随机找一个服务器, 如果这个服务器不是服务器中的主节点(下文我们管它叫从节点), 它就会回应, 别找我, 找那个谁. 如果客户端找服务器主节点, 如果主节点超时, 客户端会过一会重新随机发起一个请求, 最终找到正常工作的主节点.

17.2 为什么是主节点服务,而其他节点不能服务?

答: 这确实是费解的, 设置那么多备用的, 只让一个上, 真的是家大业大啊, 资源浪费啊.

17.3 是不是说, 其他的结点用来读, 而主节点用来写?

答: 也不是, 读也是从主节点读的, 跟节点没关系, 从节点一直处于幕后待命状态,就是为了备份用. 待会会讲为啥从节点不是读取用的.

17.4 如果主节点同时负责读写请求, 那和单机的有什么区别?

答: 一时竟无法反驳, 区别是这样的集群, 主节点挂了也没事.

17.5 raft如何实现所有命令顺序执行?

答: 给所有的来自客户端的请求编号, 并且记录执行状态(成功还是失败), 保证其中的命令只被执行一次. 如果有相同编号的命令被重复请求, 那说明第一次相应没有到达, 因此客户端发起来重试.

17.6 但是你还是没有说,如何保持不同客户端的之间命令保证顺序执行呢?

答: 论文没有说, 或者我没Get到.

18 读是如何被处理的?

答: 读请求不会改变服务器的状态,但是也不能返回陈旧的信息. 因为主节点可能不再是真正的主节点了, 比如它曾经是, 客户端也认为它是, 后来它崩溃了, 集群选了新的主节点, 它又复活了, 这个时候如果客户端继续请求它, 它返回的就是陈旧的信息了. 因此raft通过某些措施保证.

18.1 raft如何保证读也是最新的消息?

答: 关键就在于确认它是否是主节点, 因为读不涉及写入多数节点的过程,相对比较快, 因此每次处理读请求, 都要取向其他节点确认一下身份, 我最后写入的消息是XXX,你看你们也是不是? 如果是, 那我还是主节点. 一个新选举的主节点如何确保它的所有日志信息都被复制到多数节点去了呢? 它也要向其他节点发出一个校验请求, 是当选后的第一步.

19 继续返回第5部分, 第5部分都讲了些啥?

答: 就讲了如何选主,复制日志. 自从日志复制部分 5.3 内容结束之后, 还没继续往下看, 请跳转到第16条看进度. 先复习一下第5.3 部分关于日志复制部分.

安全

19.1 复习日志复制有什么新的发现吗?

答: 日志复制, 主节点如果收到一条日志, 那么它会发给所有从节点, 让他们也复制一份, 如果这条日志被安全的复制了, 那么就(1)执行这条日志包含的命令到自己的状态机上, (2)响应给客户端. (3)如果 几台从节点没有响应, 即使这条日志已经复制给多数机器并且这些机器都响应了,那么也应该继续有耐心的给这些没有回信的从节点继续发, 毕竟是主节点, 要有担当的.

(1)的过程后,这条对应的日志被称为提交状态.

19.2 什么是被安全的复制了?

答: 所谓的安全复制就是指被一条日志被包含着自己在内和其他从节点成功复制这条日志并且有回信, 这些节点数量加起来数量过半.

19.3 什么时候把一条日志应用到状态机?

答: 成功复制过半并且从节点都有回信. 这日志记为已提交日志?

19.4 一条日志被提交, 下标小的日志可以被跳过吗?

答: 不行, 比他下标小的日志都会被提交.

19.5 raft如何保证日志的一致性?

答: 返回16条, 一个日志有两个字段确保其一致性, 下标和任期值, Term Value, 对于raft里所有的节点上的日志, 如果一个日志的下标和产生任期值相同, 那么这条日志必然相同.

19.6 日志不一致产生的时机是什么?

答: 主节点复制日志到一半崩溃了, 从节点掉线了, 这两种情况.

19.7 如何处理这种不一致?

答: 会看第16条问答, 里面有说.

19.8 请继续从上次的进度说起, raft如何保证安全的选主和日志复制的?

答: 是的, 剩下的5.4节名字叫 safety. 也即是边缘条件或者特殊条件, raft的设计机制, 如何保证选主和日志复制. 它补充了细节.

20 raft 如何保证安全选主的?

答: 正如我 16.2 问答所说, 它是有细节的. raft和其他的分布式算法不一样, 它的不一样之处在于日志只从主节点往从节点复制, 没有从节点往主节点复制这个方向, 所以当选主节点条件严苛, 首先在它还是候选人身份的时候, 它拉选票的时候, 它要向其他从节点证明, 我包含最新最全的日志, 所以请你选我.

20.1 它是如何证明的?

答: 它向其他从节点看它最后一条日志的索引和 产生任期号Term, 因为这些都是单调递增的, 所以大家都知道它是不是包含比自己还多的日志, 最起码要一样多, 才会投票选. 谁会选一个比还落后的节点呢?

21 raft说, 一个主节点要分发日志, 这种日志有可能不是自己当前的任期内产生的, 这是怎么回事?

答: 一个主节点当选后, 有可能发现遗产. 所谓的遗产就是一个日志被复制到其他节点上去了, 但是未必或者到多数节点上去了, 或者即使被复制到多数节点, 还没来得及收到回信就崩溃了. 当新的节点当选后, 它要做的就是处理这个"遗产", 完成这个复制过程.

21.1 那么针对这种情况, 新任的从节点如何保证自己完成任务了呢?

答: 复制前任主节点产生的日志到其他所有节点并不难,只要发请求就行了,但是为了保证状态机的安全, 正如我21.2 所讲的情形, 前任主节点产生的日志不能因为复制到多数机器, 就立即提交到状态机, 只有本任期内的日志才可以, 从而捎带提交了前任主节点产生的日志.

21.2 什么情况下, 复制到多数节点的日志会被覆盖?

答: 复制到多数节点但是没有成功提交, 而这个任期比较旧, 而一个拥有新任期的日志当选为主节点,则会把最新任期的日志复制到所有其他节点, 覆盖了这个日志.

22 为什么主节点的日志是完整的?

答: 什么叫做主节点的日志是完整的?

22.1 主节点上的所有提交日志是提交到所有的节点的状态机上的,主节点的日志是最新最全的.

答: 这个就是主节点的权威性保证, 5.4.3 有内容, 采用反证法论述, 我就不细说了. 反正你记住, 一个主节点能当上主节点, 必定是有资格的, 是有机制保证的.

网络

23 从节点和候选人节点崩溃了该怎么办?

答: 他们不是主节点, 他们都是不重要的角色, 在raft看来. 如果一个从节点或者候选人节点崩溃了, 其他节点发送给它的请求或者相应会一直重试下去, 直到他们重启成功. (实际实现的时候应该会设置一个重试次数, 毕竟发请求是有成本的)

24 时间和保证可访问性(可靠性之一,有请求必然有响应)?

答: raft的设计思想是, 不因为一个行为太慢或者太快而导致表明它是成功或者失败. 慢或者快不影响结果. 举个例子吧, 一个孩子5岁了还不说话, raft认为他并不是哑巴, 也许10岁他会说话了呢? 再或者20岁? 30岁, 死之前突然会说话了那都不算哑巴.

24.1 你说这话什么意思? 难道一个请求超过5分钟不响应也算正常?

答: raft认为是正常的, 你可以继续请求, 直到有返回为止. 但是超过5分钟不响应说明可访问行不行, 响应太慢, 系统就是有改进的空间. 关键在于制定一个合适的响应时间上限.

24.2 所以说超时还是算失败喽?

答: 超时只能说它很有可能失败, 但不是一定失败了, 现实的原因很多, 不要妄加揣测. 只能说很有可能.

24.3 废话少说, raft的超时时间是怎么样的?

答: 超时时间取决于网络广播时间和 MTBF. MTBF 是 mean time between failures, 也即是一个节点平均失败的间隔. 一般也就是几个月? 如果经常出问题, 那说明这个节点自身有问题.

一般网络广播时间取决于网络本身好不好, 如果网路很差, 超时时间就要设置大一点. 超时时间一定要大于广播消息的时间,小于MTBF, 你想想看, 如果广播消息还没完成, 也就是所有节点收到请求并且相应的时间, 你就判超时了, 那有什么意义呢?

25 第6部分 节点关系变化说了什么?

答: 第6部分不打算看了, 第7部分也不打算看了. 暂时不看, raft的精髓已经学到了, 第6部分讲的是加入和退出集群, 也就是节点数量的动态变化, 这个部分应该还是很有趣的, 但是短期没啥用. 第7部分, 日志压缩, 侧重于工程实践, 应该也没啥用, 因为目前也用不上. 有需要了再看.

论文之外

26 采访一下, 全程看完有什么感受?

答: 全程历时大约2周, 中间有很多事情耽误了,大约花费了7*2小时吧, 最大的感受是, (1)英语论文看起来很长,但是说东西本质不多, 但是要把这些东西说清楚, 却有很多细节, 你要不厌其烦的说, 因此它的篇幅就很长. 这也是老外了不起的地方, 越是细节越有必要, 因为细节决定着到底有无可能是实现. (2)阅读英语磕磕绊绊的, 有很多生词, 很容易阅读疲劳, 因此阅读论文不要线性阅读, 从最有趣的地方开始阅读是最好的. (3) 读完了raft的论文核心部分其实目前够用, 剩下的细节随着以后实践的增加而可以逐步返回来再阅读.

27 读完具体对你有什么提升?

答: 本事没长, 但是可以和人能聊分布式话题了, 也算是半只脚跨入其中. 关于读论文, 其实时间有限, 不能一一读完, 尽量挑核心部分消化就可. 读了论文也不能说你就会什么了, 没有实践啥都不是, 所以还是要实践起来.

28 所以分布式的raft算法到底能干啥?

答: 我也在思考这个问题, 我为此搜索了一下互联网上的消息. 有以下几个收获:

  1. 分布式公司 PingCAP 家的 TiDB, 是基于 Raft 做的. 文章网址如下: cloud.tencent.com/developer/a…
  2. Curve, 一个网易公司开源的分布式存储数据库, 使用了Raft协议, 介绍如下, cloud.tencent.com/developer/a…
  3. 华为云的基于Raft协议的分布式数据库, 介绍地址如下: cloud.tencent.com/developer/a…
  4. raft 在百度云的实践: time.geekbang.org/dailylesson…
  5. RocketMQ 有使用到Raft协议来更新自己的设计: RocketMQ, RocketMQ现在已经升级为Apache开源项目, 以前是阿里开发的, 大概介绍地址如下: www.infoq.cn/article/7xe…*GDZOFS6

基本可以认为Raft的用处就是设计分布式数据库、分布式锁、协调服务用的。

29 所以这个东西都是分布式存储用到了?

答: 有很多一致性协议,raft不是唯一的。

30 所以好像对我没什么用吗?

答: 学习其设计思想, 跟人装B可以说... 认真的回答是, 分布式, 什么是分布式, 我们常说单机无法解决了才使用分布式, 也就是多机协作, 这个词语说在新人的嘴里有点可笑, 到底什么是分布式? 听过无数次, 又从来没真正接触过, 或者深入的就其中一个问题思考过. 我认为, 分布式, 只有你具体思考过一个问题, 就从问题出发, 参考别人的设计, 真正的解决了自己遇到的问题, 那才是真正理解什么是分布式了. 现在的人张口闭口就是, 分布式,大数据, 可是真正的问题解决又有几个? 只有去实践中真正解决问题, 才能算把这个问题搞明白, 看论文或者看课程, 啃砖一样的书, 是没有用的.

31 最后的最后, 说一句整体的感受?

答: 系统设计, 符合直觉, 简单, 是具有旺盛的生命力的, 是最容易流行起来的, 否则就是一小部分人自High的, 殿堂之上的理论, make it simple and broadcast it.

总结

raft 设计的目的是为了基于paxos更简单,为了教学.论文中证明了怎么有利于教学的。它通过 Leader、Follower、Candidate 三个角色,通过解决 Leader Election、Log Replication 和 Safety 三个问题确保数据在分布式系统中的一致性.

怎么选主

选主,讲的就是如何选出一个主节点. 这个过程采用一个随机的过期时间(150-300ms)之间,如果收到了半数以上的投票就当选. 当选成功以后要定期给所有的其他节点发心跳,告诉大家,我是主节点,否则其他节点会在主节点心跳超时时发起重新选主的流程. 如果出现几个节点都发起选主的过程, 那么大家会比较一个选主的数据结构的值的大小, 论文中管这个词语叫 Term,翻译过来是任期的意思,就是一个主节点当选后的全部跨度.

任何一个server都可以发起选举过程,如果它认为主节点心跳停止了, 它就可以发起了(可能要等待一段时间, 作为等待窗口期,万一主节点又挣扎着活过来了),如果在它发起之前, 收到了其他server 发起的选主, 然而它认为旧的master心跳该没有到期,该怎么办呢? 到底是等待旧的心跳, 还是响应新的选举呢? 你们要造反?我是跟着呢, 还是继续等着呢? 此处存疑。这种情况在网络不好的情况下可能会频频出现。

选举的冲突

当旧的server停止心跳之后, 出现了场面一度混乱,这个时候就有人站起来说, 我要当头, 你们跟我走吧. 然后这个时候, 可能不止一个人这么做, 所以就会选举冲突.

谁的选举号码大谁就保持, 选举号码其实是一种时间戳类似的东西, 单调递增, 先发起的选举号码比后发起的选举号码小, 如果先发起的还没来得及赢下过半数量的投票(等待其他节点回应它, 其他节点只能一次选一个候选人,不能八面玲珑,谁都投一票), 就收到其他节点发起拉票行为并且传达给这个候选人, 即竞争对手来砸馆子来了, 那么按照现有的机制, 先发起的应该怎么办呢, 比如我的结果还没出来呢?

有两种消息, 一种是 拉选票的消息, 一种是心跳消息, 只有获得多数投票才能发起心跳信息, 心跳消息是主节点才有资格发起的, 而候选人身份只能发起拉选票的消息.

如果一个候选人收到了其他的候选人的拉选票的消息,肯定是不理会的, 在这个拉选票截止时间之内是必然不理会的.其他的投票人也一样,不能说你收到一个拉选票消息就改投这个人. 这样是永远选不出主节点的.

如果一个候选人在等待其他候选人的投票信息的时候, 收到了一个心跳消息, 如果这个心跳信息中携带的选举号(我们暂且叫选举号吧,就是它当选成功时候的选举号,作为它的主节点身份)比当前候选人收到的最后一次心跳消息的选举号更大,那么说明这是一个新的主机诶单, 自己放弃候选人身份.

什么时候一个投票人可以投其他人呢? 任何选举都有一个不定长的到期时间, 不能一直无限期的等待,如果过了这个到期时间还没有收到来自这个节点的心跳消息, 那么就可以投别的节点了.

如果一个候选人到他选举结束之前还没有收到多数票的响应, 也没有收到其他更新的心跳消息, 那么就继续发起新的投票.

整个过程是非常直观和符合人类选举的规则的.

有一些细节是论文没说,我自己脑补的, 可能有不准确的地方, 还望指正.

日志复制的过程

日志复制中说了几个事, raft如何保障节点之间的日志一致的的机制, 如果不一致该怎么办. 首先,它说了复制日志的RPC消息的结构, 以及为什么要这些结构来保障日志的一致性的.

当然, 最先它说了日志的格式, 日志的格式, 论文里画了一张图. 大概包括以下几个核心内容: (1)日志的下标,假设从0开始吧,就是跟数组的下标一样. (2)日志产生的Term, 就姑且翻译为选举时期吧 (3)命令的具体内容.

那么复制日志的RPC消息体又是什么样的呢, 它包含以下内容: (1)命令的具体内容 (2)主节点本条日志的下标和日志Term (3)主节点前一条日志的Term和下标.

第(3)个是保证一致性的关键, 如果每次发送复制日志的消息的时候都, 从节点都检查一下当前的消息里的前一条日志的Term和下标是否一致,如果一致, 就说明前面所有的日志是一样的(为什么这么说, 你自己理解递归是什么意思吧),因此就是一致的,就接受这条日志并且赋值到自己的状态机里面, 如果根据RPC消息里前一条日志的Term和下标没有在自己的日志序列(注意是序列,讲究顺序的)找到对应的日志,那么说明从节点的日志要么多了,要么少了,反正就是不一致了, 从结点就拒绝这条日志的复制. 然后主节点就开始不停的向这个从结点发RPC, 是把前一条日志的Term和下标换成更早一个日志, 如此往复, 直到找到第一条相同的日志为止, 后面所有的不同的日志都会被主节点接下来的日志覆盖.

整体来看,日志复制, 主节点如果收到一条日志, 那么它会发给所有从节点, 让他们也复制一份, 如果这条日志被安全的复制(多数节点有肯定答复)了, 那么就

(1)执行这条日志包含的命令到自己的状态机上,

(2)响应给客户端.

(3)如果几台从节点没有响应, 即使这条日志已经复制给多数机器并且这些机器都响应了,那么也应该继续有耐心的给这些没有回信的从节点继续发, 毕竟是主节点, 要有担当的.

(1)的过程后,这条对应的日志被称为提交状态.

安全复制就是指被一条日志被包含着自己在内和其他从节点成功复制这条日志并且有回信, 这些节点数量加起来数量过半.

一个主节点当选后, 有可能发现遗产. 所谓的遗产就是一个日志被复制到其他节点上去了, 但是未必或者到多数节点上去了, 或者即使被复制到多数节点, 还没来得及提交这条日志就崩溃了. 当新的节点当选后, 它要做的就是处理这个"遗产", 完成这个复制过程.具体过程TODO

复制到多数节点但是没有成功提交, 而这个任期比较旧, 而一个拥有新任期的日志当选为主节点,则会把最新任期的日志复制到所有其他节点, 覆盖了这个日志.

为什么会出现日志不一致的情况

主节点不能保证把所有的日志都复制到所有的节点上去, 只能保证多数节点有这条日志. 当主节点挂掉的时候,没有来得及把所有的日志复制到其他从节点。

此外,从节点掉线再连上来了, 也会导致日志不一致.

如果有ABCDE五台机器, A是主节点, A一条日志复制到了BC和自己身上,这就是多数了, 如果A因为网络故障而掉线了,那么重新选举的时候,如果D或者E当选为主节点, 很显然他们的日志是不全的, 那么这个时候如果按你说的, 岂不是要把那一条日志删掉呢?

所以说这样的机制不完善,我们会打补丁, 起码, A是主节点,它会尽力把所有的日志都复制到所有的机器上去, 如果DE掉线了, 等他们联机上来, A会联系他们并且把日志复制到他们上去. 如果恰好是DE重连之前, A掉线了, DE也开始选举自己为主节点了, 这叫新兵蛋子, 应该说是不配被选举为主节点的, 所以选主这块应该会控制,不会把刚刚掉线然后重连的机器选为主节点的.

客户端找主节点

raft集群中的客户端如何找到服务端的事, 以及如何实现顺序执行(这块有点不明白). 客户端首先会随机找一个服务器, 如果这个服务器不是服务器中的主节点(下文我们管它叫从节点), 它就会回应, 别找我, 找那个谁. 如果客户端找服务器主节点, 如果主节点超时, 客户端会过一会重新随机发起一个请求, 最终找到正常工作的主节点.

有着一个重定向的说法。

只有一个主节点,其他的都是 standby,不服务,既包括读,也包括写。

raft如何保证读最新

关键就在于确认它是否是主节点, 因为读不涉及写入多数节点的过程,相对比较快, 因此每次处理读请求, 都要取向其他节点确认一下身份, 我最后写入的消息是XXX,你看你们也是不是? 如果是, 那我还是主节点. 一个新选举的主节点如何确保它的所有日志信息都被复制到多数节点去了呢? 它也要向其他节点发出一个校验请求, 是当选后的第一步.

相关工作

benbjohnson在他的网站上[1]使用了一系列生动的动画来描述Raft算法和核心内容,包括选主和日志复制,通过该动画,读者可以很清楚的了解Raft的核心原理。

FullStackPlan在他的博客里[2]翻译了Raft原版英文论文为中文,非常感谢他的工作。

皮拉图斯在他的知乎文章[3]里介绍了Raft的基本原理,Raft开源库的实现,是非常有价值的参考资料。

参考

[1]benbjohnson,Raft动画,thesecretlivesofdata.com/raft/

[2]FullStackPlan,分布式一致性算法:Raft 算法(论文翻译),www.cnblogs.com/linbingdong…

[3]皮拉图斯,raft 协议简介, zhuanlan.zhihu.com/p/148091739

[4]王江,章明星,武永卫,陈康,郑纬民,清华大学计算机科学与技术系, 类Paxos共识算法研究进展, crad.ict.ac.cn/CN/10.7544/…, 计算机研究与发展, 2019年56期

kafka论文阅读笔记

  1. 你为什么要阅读kafka论文呢?

答:因为这个工具很流行,无处不在。

  1. 论文网址在哪?

答:论文网址在这里 notes.stephenholiday.com/Kafka.pdf

  1. 论文重点是哪一章?

答:第三部分。也就是描述整体设计那一部分。

  1. 论文篇幅有多长?

答: 7页纸,而第3部分只有3页纸。个人以为是论文的核心。

  1. 第三部分大致讲了哪几点呢?

答: 3.1 单broker的单分区的结构和设计思路,如何保证分区读写的高效率,3.2 消费者和生产者如何和多个broker交互,broker如何分发消息,3.3, 如何保证消息不丢失,也即是可靠性保证的设计。

5.1 看的人晕头转向的?

答:先说几个概念吧,broker,partition,topic, consumer,producer。 所谓的broker就是kafka的核心组成部分,kafka就是broker,topic就是主题,就是频道,就是一组消息的唯一ID,可以认为是分组的概念,consumer就是消息消费者,需要消息的地方, produer就是发消息的。 再说一个大的概念吧,消息,什么是消息?可以这么说,一条日志,一个可以被描述的、含有主谓宾的任何信息都是消息,因为可以被延迟执行,所以有了一个大缓存,这个大缓存很可靠,它可以保留消息很久而不丢失,这个大缓存既能处理实时消息,也能存储大规模的对实时性要求不高的消息,因为它的设计很好,它处理消息很高效,又安全,所以它啥场景都基本能对付,这么一个大缓存就是kafka。

  1. kafka这个名字怎么来的?

答:kafka听上去像一个科学家的名字是吧?这个消息队列是LinkedIn内部开发的,然后开源了出来,鬼知道为什么叫kafka,也许是为了纪念某个人,也许是开发者乱想的,反正它让中国人听起来怪怪的。

  1. 请回到主题上面来,请问kafka的核心部分都讲了什么?

答:核心部分正如我上面所说,分为三部分,分别是3.1单partition的设计,3.2 系统内部交互设计,3.3可靠性保证。他们三部分篇幅不一样,其中3.1和3.2占了第三部分篇幅的80%,而3.3则很短,我先从短的部分说起,这样先拿下一分先。

  1. 那么请问kafka是如何保证可靠性的?

答:在原始论文中,提到了两个概念,“精确的一次发送消息”和“至少一次发送消息”。前者如何做到的呢?肯定我发送给你,你回复我一下,咱们就达成一致,确定我把这个消息送到了,这是可靠性保证。至少一次发送消息就是说,我发给你了,但是可能多次发给你,因为我不确定是否发给你了,就好比你吃药,你忘记是否吃药了,你不记得自己吃一次还是没吃,那么你就再吃一次。这个例子不是很准确,但是确实是这样的。kafka说,请你自己确保你只吃了一次,我可以把药无限次的给你。这和kafka的消息传输机制有关,我待会会讲,这样的设计是考虑到性价比的问题。

8.1 如果kafka消息保存到硬盘上出错了怎么办?

答:问得好,我还没说完。kafka自有办法,它使用了CRC机制。那么你又要问什么是CRC了,在这里,科普一下,如果你学过计算机网络,你可以知道字节传输的时候,01可能会发生变形,0变成1,1变成0,是小概率事件,但是会发生,因此有这么一个检测算法,也就是CRC,具体的思路不讲了,可以简单看看百度百科学习一下, baike.baidu.com/item/CRC/14… ,所以kafka保证了它自身把消息写到硬盘上的时候,有检查机制。

8.2 我有一个问题想问,kafka发送消息严格保证顺序吗?

答:kafka把消息分组成topic,topic又分成partition,为了并发嘛!同一个partition内部的消息是严格按照顺序发送的,但是不同partition之间是没法保证的。这得要应用自己保证。

8.3 等一下,我还想问一下,如果一个kafka机器崩溃了,消息是不是丢失了啊?

答:你是不是想说kafka有没有类似于 GFS之类的机制。遗憾的告诉你,论文里没有说它有冗余备份机制,但是既然作者把设计思路都说了,你应该可以自己实现一下不是吗?

9 那么请你接下来讲一讲一个partition的内部结构?

答:好的。partition 的设计至关重要。kafka首先有topic的概念,一个producer想发布消息,则开辟一个topic,那么为什么有partition的概念呢?一个topic代表的消息可能太多了,所以要存放起来不方便,于是拆分成 partition 分在不同的机器上存放。一个partition,是一个逻辑意义上的日志?(论文里没搞明白为什么这么说。懂的同学请告知一下),partition的体积会越来越大,然后会拆分成一个一个固定体积大小的文件放在硬盘上,比如这个体积是 1GB,这个固定大小的文件,我们管它叫 segement,也就是段。 kafka中的消息是没有一个明确的ID来标识的,而是靠它在这个partition中的逻辑偏移量,什么是逻辑偏移量?假如一个消息第一个放在这个partition中,长度为100Bytes,那么他的逻辑偏移量就是0,第二个消息再放进来,它的逻辑偏移量就是100。也就是说,kafka只能是顺序获取消息,不能随机访问消息。

9.1 举一个例子吧,如果一个请求过来,想找某个partition内部的偏移量为10000的,长度1000KB的消息,那么kafka会怎么做?

答:因为它的消息是不断增加的,所以它会把消息切成很多segement,然后它会在内存中有一个数据结构,类似于一个数组,记录每个segment内部的最开始的消息偏移量。 请求过来,它就会查当前最后一个小于10000的segement,然后从里面取出数据,发送给请求方。

9.2 我问累了,你随便说点什么吧。

答:我也有点疲惫了。说点轻松的吧,关于kafka如何进行高效传输的。

9.3 kafka是如何做到高效传输的呢?

答:答案就是一次多传点。一个传它几十个消息。打个比方,你要去买东西,你会攒几天再去一次超市,而不是每次想买什么就赶紧跑去买对吧,kafka也是这样做的,尽量一次多传多条消息过去。咱刚说了,kafka是一个大缓存,消费是主动拉消息的,生产者是主动推消息的,kafka就是一个消息中转站,生产者和消费者都尽量一次多推和拉消息。

9.4 你说的这个也是平平无奇啊!这个道理赞都懂,需要你讲吗?

答:确实,简单的道理大家都懂,所以也没什么好说的。那我就讲一下kafka不一样的地方吧。

9.5 你说?

答:kafka 自身不设计缓存。一般的应用为了高效的读写,都会设计一个应用内的缓存。经典的比如某些日志库啊,它为了高效的写日志,不会每次生产出一条日志都去写一次磁盘,它会设计一个缓存,等写了很多日志,它才把内容写到磁盘上去。 kafka反其道而行之。按理来说,kafka作为一个大缓存,它有一个应用场景是这样的,很多消费者订阅同一个消息,每个消息他们都要有一份,那么是不是说可以在kafka内部开一个缓存呢?kafka说,不用,我们就用操作系统内部的页缓存就行了,实践证明,kafka使用操作系统缓存确实效果还行,免去了自己再搞一个缓存,节省内存,而且因为kafka纯粹是一个消息分发的东西,它没有复杂的逻辑,基本上消息都是整页整页的直接使用操作系统的内存,所以它不用单独再设计一个缓存。它在论文中是刻意这么强调了的。

9.6 kafka的意思是,其实应用级缓存是个多余的东西?

答:照它的意思,是这样的。

9.7 那么是不是其他的应用也不需要设计应用级缓存,就直接可以用操作系统缓存呢?

答:不可。具体问题具体分析。kafka读取消息都是大块内存读取的,刚好契合操作系统页内存,而且它是线性连续读取的,有的应用的缓存是随机读取的,而且缓存的内容体积各异,有的内容就几个字节,必须得缓存了。

9.8 所以说kafka故意不用应用级缓存是很高明了?

答:能不人云亦云,而且确实有效,怎么能不说是高明呢?

9.9 kafka还有什么高效传输的秘密吗?

答:kafka充分利用了Linux操作系统的一个系统接口,这个接口叫 sendfile,它可以直接把一个硬盘文件加载到 file channnel 的东西里,然后直接把file channel的内容写到一个 socket 文件里面去,也就是说,它充分利用了操作系统内部提供的高性能接口,而免去了在内存中拷贝字节的过程。我们设计底层应用,自然要关注操作系统提供的福利,跟上操作系统进步的步伐,才不至于掉队啊。

9.10 我还看到kafka 是一个无状态的服务?

答:是的,stateless,这个词我们很熟悉了。在 http 设计的时候,我们就知道,http 最亮点的设计就是无状态。http本身没有状态,如何记录状态交给上层的应用本身去做。在很多网站交互中,我们必须知道用户是否登录,这个时候,聪明的IT工程师在无状态的http服务上设计出 cookie和session的概念,证明了无状态的底层服务其实是没啥问题的,设计简单的,可操作的。http 的无状态大放异彩,kafka这个学生也不笨。kafka的设计思路,是把所有的消息都存起来,当然不是存到天荒地老,存个7天以内的消息,然后通过一种机制让消费者保存消费偏移即可,从而实现了记忆消费到哪里。

请我们记住,无状态设计,这个在系统架构级别设计的理念,会时不时的碰到。

10 你刚才讲了3.1的内容,请继续讲3.2的内容吧!

答:好的。3.2讲了kafka和 消费者,生产者之间如何交互的,这个是一个非常精彩的部分,弄懂了基本上kafka就没有什么秘密了。

10.1 那请开始吧!

答:这部分大概讲了 zookeeper,kafka,生产者,消费者。各个实体之间是如何交互的。以及partition和topic的关系,如果围绕着 partition 进行操作的。

10.2 partition和topic的关系是什么?

答:我在上面说,topic的消息会越来越大,一台机器可能会存不下,于是拆分成多个partition存放。那么是不是说,一个topic拆分成多个partition是为了方便存放呢?这里我也不是很清楚。论文里并没有清楚的描述出来。但是它说,一个生产者可以自己选择往哪个partition里写,什么意思呢?如果一个topic有多个partition,那么每个partition都可以接受写入,每个partition之间是没有先后顺序的,也就是说,partition之间是平等的,不是追加写入的。甚至可以这么理解,partition是子topic,是更小的粒度划分。 再说了个通俗易懂的例子吧,topic是一家连锁酒店,partition是很多分店,你想住哪家分店住哪家,但总归你是住进了他家的酒店,就好比一个consumer订阅了一个topic,你是这家酒店的顾客就完了。

10.3 什么是 消费者组?

答:customer group,翻译过来是消费者组。作为消息组的 topic,可以理解,那么消费者组又是什么呢?他存在的意义是什么?我认为论文这块没有讲清楚,实在是太单薄了,后续还需要继续学习一下。

10.4 kafka为什么要使用zookeeper?

答:kafka是一个没有master节点的系统。它说,有master节点就要考虑master节点的容灾,不错。提出一个解决方案就必要提出解决方案本身的问题,然后再去解决解决方案引出的问题,形成一个套娃过程。所以,要master节点是干什么用呢,如果没有master节点,又该如何实现类似的功能呢?其实master节点的作用就是保存元信息,在这里,zookeeper,一个雅虎开源的协作和同步系统,实际上在kafka里扮演了master的角色。kafka的意思是,我是没有中心节点的,其实意思是说,我自己不设计中心节点,我用zookeeper做中心节点。无主设计真的无主吗?其实是相对的,是一种说法而已。

10.5 zookeeper,是怎么在kafka中扮演角色的?

答:zookeeper,动物园管理员,这个名字源于很多大数据的项目都喜欢用动物起名字,于是雅虎内部开发这个系统的时候说,我们该叫什么名字呢?不如就叫动物园管理员吧,我们管理这些动物(项目),一个非常自信和基础的服务。zookeeper怎没用,我这里不细说了,下期有空写关于读zookeeper论文的一些分享。

10.6 请详细讲一下zookeeper都用来干什么吧?

答:zookeepr的作用是:1.监听kafka节点也就是broker的数量, consumer的数量变化, 2. 当数量变化的时候触发负载均衡,3.记录消费者订阅的partition和消费偏移。

每一台机器,包括consumer和broker启动的时候,都要去zookeeper上登记。 broker 登记留下的信息是,它的IP地址和端口号,哪些topic的partition存放在它上面,消费者登记的信息包括,它属于哪个组,它订阅了哪些消息。而consumer group,消费者组作为一个实体也在 zookeeper上 留下了一条登记信息,它所包括的内容有,组内订阅的partition,这个partition的消费偏移。 除了partition的消费便宜是永久保存的之外,其他所有的登记信息都是临时的,会随着它关联的实体的下线而消失。

10.7 论文中大段描述了如何进行负载均衡的,你可以讲一下吗?

答:这块花了我很长的时间,我希望这块可以认真分享一下。想要说清楚所谓的负载均衡,我们必须搞清楚 consumer group ,topic, partition 之间的关系。 首先回答一下 刚才上面的一个疑问,为啥要有consumer group这个东西,consumer group 肯定是一组相似的 consumer 组成的。 然后又有一个设计原则,不同的 partition 只能被一个组内的一个 consumer 所拥有,也就是消费。 partition 是用来给 topic进行负载均衡用的,为了提高topic的并发量,所以要给 topic 下设置很多的 partition。然后一个topic被很多个consumer同时订阅,所以我们会把这个topic下的 partition 一对一的分配给这些个 consumer。我打个比方吧,加入有一地方,这个地方有男有女,我们会给一个男子分配一个女子,这样他们就组成了一对,一个男子不能同时和多个女子保持关系,反之同理。放在这个地方,一个 topic就是一个地方,一个 partition就是一个男或者女,一个consumer就是另外一个性别,爱怎么安排怎么安排吧,一个consumer group 就是一堆待分配的单身集合,反正就是这么一个逐一匹配的道理。每当有不同的 consumer加入或者 broker 加入的时候,数量就会不平衡,那么就会引发新一轮的重新分配的过程。

回到正题,因为网络存在延迟, 一个consumer可能会去消费一个被其他consumer拥有的 partition,那么基于抢占允许的原则,前一个consumer放弃它所拥有的所有 partition, 相当于重置,然后重新加入这个 consumer group,进行新的负载均衡的步骤。

10.8 基于zookeeper的kafka结点之间是如何交互的呢?还需要补充吗?

答:基本上, kafka结点的交互是围绕着zookeeper这个元数据存储工具来展开的,他们的交互是清楚的,简单的。 论文上基本就说了这些内容,没有什么好补充的了。

11 关于kafka你还要说什么?

答:简介的设计才是王道,kafka体现出来了。它实现了个消息队列,可以支持实时低延迟需求,同时它也支持那种批量的数据密集型的任务,得益于它简洁的设计和对性能的追求,kafka成为了最流行的消息队列。我们应该努力学习这种设计思路。kafka的成功还在于它的专注,我们可以看论文第二部分,传统消息队列的问题,就在于什么都想干,什么都未必干得好的事,比较紧的耦合吧,kafka没什么负担。

12 还有吗?

答:没有了,论文呢的解读就到了这里了,希望下次可以继续解读优秀的系统设计论文。下次准备解读 zookeeper,bigtable,raft 等等。

13 等一下,关请问阅读论文过程中,有什么技巧吗?阅读完论文又怎能怎么样呢?

答:技巧就是,硬啃,提高英语水平,合理跳过看不懂的地方,回头再解决疑难问题。论文中总有疏漏,总有讲不清的地方,这个习惯就好了。 读完论文啥都不能干,除非你去阅读一个kafka的源代码实现,对了,kafka本身有几个缺陷待完善,有兴趣可以看每个公司内部的实现源码,应该也是很有趣和挑战的。 学习终归是为了增长知识和应用到实践中,希望可以在实践中去验证这些知识。

samza论文阅读笔记

Apache Samza,一个用于有状态和容错流处理的分布式系统。

背景: 分布式流处理系统需要支持有状态处理,并且能够从故障中快速恢复以继续处理,同时还需要能够快速重新处理整个数据流。 Samza的特点:

  1. 有状态处理: Samza 使用分区本地状态和低开销的背景变更日志机制,这使得它可以扩展到每个应用程序数百TB的大量状态。
  2. 故障恢复: Samza 通过基于主机亲和性(在哪跌倒在哪爬起来,谁出问题谁负责)的重新调度来加速故障恢复。
  3. 处理有限数据集: 除了处理无限事件流之外,Samza 还支持将有限数据集作为流来处理,无论是来自流媒体源(如Kafka)、数据库快照(如Databus)还是文件系统(如HDFS),而无需更改应用程序代码。这与基于Lambda的架构不同,后者需要为批处理和流处理维护单独的代码库。 使用情况: Samza 目前在LinkedIn被数百个生产应用程序使用,拥有超过10,000个容器。它是一个开源的Apache项目,被许多顶级公司采用,如LinkedIn、Uber、Netflix、TripAdvisor等。 实验结果:
  4. 状态处理效率: Samza 在处理状态方面非常高效,与使用远程存储相比,延迟和吞吐量提高了100倍以上。
  5. 恢复时间: Samza 提供的恢复时间与状态大小无关。
  6. 性能扩展: Samza 的性能与容器的数量成线性扩展。
  7. 数据流重新处理: Samza 支持快速重新处理数据流,并且对实时流量的干扰最小。 这些信息表明Samza是一个强大的流处理系统,它通过高效的状态管理和快速的故障恢复,为大规模数据处理提供了高性能和可靠性。同时,Samza的灵活性和易用性使其成为处理有限数据集和无限数据流的理想选择。

重点是,什么是有状态的?待会再讲。

1 为什么要读这篇论文?

在腾讯工作的时候,一个大数据框架,就是借鉴了这篇论文,所以读了这篇论文。

2 什么是状态?

举个例子,处理流的时候,拿到了一个用户的ID,那么怎么获取用户的用户名,历史操作记录等,这些是放在数据库里,所以要查询数据库,但是不能太慢!然而大批量的数据流,查数据库肯定慢不了。

在第二部分的开始,详细介绍了什么是状态。比如一个用户的所有字段信息就是状态,流里面的数据的Join操作需要用到状态。状态广义的理解为一种生命周期很长的,跨越单个流对象处理生命周期的存在。

简单摘要一部分原文描述:

Read-Only state: Applications look up “adjunct” read-only data, perhaps for each event, to get the necessary information to process it. Examples of such static state include user digestion settings in EDS or the user profile on each ad view event (accessed to find the user’s field of expertise).

只读状态,比如用户的偏好设置和用户的信息。

Read-Write state: Some state is maintained and updated as the stream events continue to be processed. Examples of this type of state include: state required for joins of streams/tables over a windows, aggregations, buffers, and machine learning models. Some applications of this state include rates/counter over a window of time (used for monitoring ads or detecting Denial of Service attacks) and guaranteeing exactly-once semantics by storing all processed message ids to verify uniqueness of incoming message ids.

可修改的状态,比如用来在一个窗口期用作连接、聚合、统计、去重的数据

samza怎么解决这个问题的,我们接着往下看。

3 samza还有什么特点吗?

重新刷数据。比如模型迭代了,需要重新计算特征了。比如之前有bug,需要重新执行一次。

samza实现了Kappa架构(相对于Lambda架构而言),同时支持批处理和流处理,节省了工程成本。关于什么是批处理和流处理,见我写的另一篇文章。TODO

4 跟别的大数据框架比呢?

论文的经典桥段,也是主体出现的合理性,即samza的特殊之处在于Lambda Less和对标Flink、Spark等大数据架构。(在写论文的时候,它可能这么吹,但是Flink和Spark生态可能已经迭代了好几版,所以这里要注意论文发表的时间)。

在分布式计算和数据处理的上下文中,"Lambda-less"是指一个系统或框架不依赖于Lambda架构来处理数据。Lambda架构是一种流行的数据处理架构,它结合了批处理和流处理来处理大量数据,并且能够提供低延迟的查询结果。 Lambda架构通常包括三个层次:

  1. 批处理层(Batch Layer) :这一层负责处理大量的历史数据,生成批视图(Batch Views)。
  2. 速度层(Speed Layer) :这一层处理最近的数据,通常是实时或近实时的数据流,生成速度视图(Speed Views)。
  3. 服务层(Serving Layer) :这一层将批视图和速度视图合并,以提供一个全面的数据视图给用户。 而"Lambda-less(最终成长为Kappa架构,Kafka的作者Jay Kreps提出)"可能指的是一个系统或框架,它尝试用一个统一的数据处理模型来同时处理批处理和流处理任务,从而避免了Lambda架构中的复杂性和维护两个不同处理路径的需要。这样的系统试图简化数据处理流程,使其更加高效和易于管理。在提到Samza的情况下,"Lambda-less"是指Samza能够使用相同的数据流结构来处理实时数据和批处理数据,而不需要依赖于传统的Lambda架构。

Kappa架构是由Jay Kreps提出的,它是Lambda架构的一种简化版本,旨在提供一个更加统一的数据处理模型,特别是针对实时和批量数据处理。Kappa架构的核心思想是使用相同的处理流水线来处理实时数据和批量数据,从而减少系统的复杂性和维护成本。 在Lambda架构中,实时数据处理和批量数据处理是通过两个不同的路径进行的:速度层(Speed Layer)处理实时数据,而批处理层(Batch Layer)处理历史数据。这种分离导致了需要维护两套逻辑,可能会出现不一致性,并且增加了系统的复杂性。 Kappa架构通过以下方式简化了这一过程:

  1. 单一处理流水线:Kappa架构使用同一套处理逻辑来处理实时数据和批量数据。这意味着,你可以用处理流数据的方式来处理批数据,通常是通过将批数据模拟为流数据来实现的。
  2. 可重放的流处理系统:Kappa架构依赖于一个能够重放历史数据的消息系统,如Apache Kafka。这样,当你需要重新处理数据时(例如,代码更新后需要重新处理历史数据),你可以简单地重放数据流,而不需要单独的批处理系统。
  3. 实时修正:在Kappa架构中,任何对历史数据的修正都可以通过重新处理数据流来实现。这样,系统总是有一个一致的数据视图,因为实时处理逻辑和历史数据重处理逻辑是相同的。 Kappa架构的缺点是,它可能不适合那些需要对历史数据进行复杂分析的场景,因为将大量历史数据模拟为流数据可能会受到性能和资源限制(这个还不是很理解)。此外,Kappa架构通常需要一个能够存储大量数据并支持高效重放的消息系统。 总的来说,Kappa架构提供了一种简化的数据处理模型,特别适合那些需要快速、一致的数据处理,并且能够容忍一定延迟的场景。

5 所谓的状态管理怎么回事?

samza会缓存用过的数据的信息(他们管这个叫状态),尽量保证他们能复用,所以尽量就是保证任务划分的时候,待处理的数据有共同属性或者数据依赖(这个应该不难理解)。怎么划分任务是个技术活,这里我也不知道他们怎么弄的。

此外,samza会缓存状态的增量日志。

6 流批处理一体化的时候,怎么保证互不影响?

在第一部分中,作者描述了三种方案:1.按需调整资源的多少,2.优先保证流式日常作业,限制批处理作业的速率 3.处理冲突和过期数据。

7 samza成熟吗?

Samza在LinkedIn的生产环境中成功运行了4年,跨越多个数据中心,总数据量达到数百TB。这个部署涵盖了200多个应用程序,在超过10,000个容器中处理着每天数万亿的事件。Samza是一个开源项目,包括Uber、Netflix和TripAdvisor在内的超过15家公司目前依赖它。

论文是2017年8月发布的,也就是说2013年已经开始在生产环境运行。到2024年已经10年了。

原文中说,这个系统处理状态非常的高效,比起远程访问数据库等,速度提升了100多倍,可扩展,容易恢复,低延迟,高吞吐量。通过实验性将samaz系统的两种变体(其中一些借鉴了其他现有系统)以及Spark和Hadoop在生产和测试集群中进行了比较。

我很好奇这是怎么比较的。至少得有数据,但是不同的业务场景数据是不一样的,在LinkedIn,就是社交场合的数据吧。

这些数据是没有标准数据集的,工程领域的论文大概就是这么玄学。

在第二章的部分,论文中讲述了说samza在内部应用很广!这个确实不错。另外,我提一嘴就是,把内部的系统写成论文,然后写成论文分享出来这件事,还挺有成就感的。当然,这个也跟企业文化有关,是否鼓励分享等等。不过,说一千道一万,这个东西有一定是好的,为什么?升职加薪一定需要的,不管是在内发表还是在外发表的。所以,一定要会写论文,这种东西对于个人是终身成就,对于部门也是荣誉。

参考

暂无

总结

暂无