初衷
Flink快照机制以Chandy&Lamport的经典分布式算法为理论基础。算法原文地址:https://lamport.azurewebsites.net/pubs/chandy.pdf
该算法的结论很简单,不少同行进行过翻译/解读。详看原文的动机是自己立了个内部培训的Flag,结果原文看了近一个星期才达到可培训的程度。时隔数月,记忆稍显模糊,那就再梳理一次吧。主要依据行文结构进行总结,不直译原文。
结构
咱们完全依照原文结构来总结,这个结构也很有意思,很严谨。
简介篇
简介篇主要说明了在分布式环境下形成全局状态的困难:
- 模型限制,各节点都只能自己记录自己的状态,只能通过通信传递信息形成全局状态。
- 时钟不同步,各节点时钟是不可能完全一致的。普通的机器的晶体震动频率有偏差的,完全同步不存在的。
- 计算不能停,全局状态的确定过程不能影响到数据计算,不能Stop-The-World
全局状态的典型应用场景:
- 系统死锁
- 计算中止
- 令牌环网中的令牌用完
第二种其实更加典型,比如一个事务的结束(别杠ACID)。原文将其定义为Stable Property的检测,在某个计算过程中,一旦该属性稳定下来,后续值不变。参考上面的三个例子。
系统模型篇
用“顶点”和“边”对整个系统进行定义,顶点表示一个处理节点/进程,边表示数据传输的Channel。几个符号的定义:
- p:处理进程,对应于顶点;
- e:p上发生的一次事件,别想着数据处理,对应的是数据的接收/发送;
- M:e涉及的数据;
- s:p的状态,每个p都会有一个状态;
- s’:e发生后p的状态;
- S:大S哈,全局状态;
OK,紧接着是用上面的符号表述了两个常见的模型:
- 单令牌传递系统,两个process(p、q)通过两个单向channel(c、c’)传递token;
- 非确定型模型,这个非确定性体现在不像模型1,要么p发送消息,要么q发送消息。系统里面只有一个token,大家轮着发。模型2中有两个消息(M、M’),“p发送M”和“q发送M’” 可能是同时进行的。
算法
Motivation for The Steps of the Algorithm
将状态的记录者分为三个角色:
- 消息的发送者;
- 消息通道(单向);
- 消息的接收者;
消息的发送者同时也可以是消息的接收者,实际过程中消息通道也可能是双向的,都不响应算法描述。接下来原文通过对模型篇中描述的两个模型进行案例分析, 讲了两个道理:
-
发送者record状态时,已发送的消息数 = channel Record时已经接收消息数。道理不难,场景:A村上午09:00找个拖拉机把大米拉到B存去。
- 假设1:8:50时,拖拉机司机在小本本上写了一句:“车上没米”;9:01分大米上车,然后A村在自己的小本本上记录了“米已经送离我村”。将两个小本本合起来一看,MD,大米呢。很显然,大米送上车后,拖拉机上的小本本必须得更新了。
- 同理,A村如果08:59分记小本本,拖拉机09:01分记小本本,就会出现两个小本本上都写着此处有大米了。
-
同理,接收者record状态时,已经接收的消息数 = channel Record状态时已经被消费的消息数。
Global-State-Detection Algorithm Outline
直接给出了一个满足上述条件的算法。有一个重要的前提,大家Record状态的时机是自发的、随机的。具体方式是:
- 对发送者p:在p记录状态后,发送其他消息前,发送一个marker;
- 对于接收者q,在其接收到marker时:
- 如果q未record状态,就记录当前状态,记录channel的状态为空;
- 如果q已经record了状态,就记录channel的状为当前收到的数据 - q record时已经收到的数据。嘛意思?可以理解为q Record时channel状态的补充记录。
初次看原文的时候,其实觉得这个结论来的有点懵,后来又觉得没毛病:
- Channel本身是没有程序载体的,也就是说它不可能记录自己的状态;
- 谁能轻松的、准确的 Record Channel的状态呢?必然是接收者,如果用发送者,还得有个机制知道下游消费到哪了不是?这种机制一般还会耦合业务。
- 用Marker来协调发送者和接收者,是利用了发送者和接收者之前必然存在的因果关系,只有数据发送了,接收者才能收到,并且保序。
- Channel状态记录的时机虽然是随机的,但是可以通过Marker收到后进行补充,达到满足前一节的两个相等条件。
- 并不是Record后全局状态就形成了,然是要marker消息走完数据处理全链路之后才会形成。
Termination of Algorithm
这里主要说的是算法的有限性:
- marker不会永远的留在channel中;
- 和自发record的process可达的任何process都一定会收到marker,必然会触发record,不可达的可以自发record;
- marker的处理在有限时间内完成;
上面几条基本保证了整个处理链路会在有限的时间内完成一次全局状态的记录。觉得还有一个关键点如果处理链路有环怎么办? 可能需要使一些手段避免marker一直循环吧。
未完待续。。。