请求 client.io-42 在第三圈超过了 client.io-17!

前阵子在思考在 Ceph 里面为什么要顺序执行读写。简单说,和 CPU 的顺序执行模型一样,这个模型更容易理解和使用。顺便跑题一下,对于"人工智能是什么"一直有个争论。其中有两派:

  • 弱人工智能,即表现上的人工智能。 中文房间 中文房间和 图灵测试 就是两个比较有名的测试,通过它们就是一定程度上的弱人工智能。这种人工智能能解决一个特定问题领域上的问题。 现在说的机器学习就是一种弱人工智能。

  • 强人工智能,即机理上的人工智能,或者说通用人工智能。这种人工智能需要具有知识表示,推理,规划,学习,自然语言处理等等能力,并把它们整合起来。强人工智能和弱人工智能比起来要难很多。前年看的 The Book of Why: The New Science of Cause and Effect 说明了因果关系和推理在人工智能的重要地位。

和人工智能一样,存储系统的顺序性也有两种

  • 表现出来是顺序的

  • 严格在执行层面上就是顺序的

当然,限制越多,性能越不好。所以在实现 crimson 的时候,每当要求顺序执行的时候,我都会多问几次"为什么"。Ceph 集群里面,一个读写请求在一生中,至少有下面几个阶段

  1. 从客户端到 primary OSD

  2. 从 primary OSD 分配到对应的 PG

  3. 生成事务,并写入本地磁盘。事务包含 pglog 和对应的用户数据。

  4. replica OSD 也回应了请求,确认持久化完成。

客户端请求就像方程式赛车一样,

  • 必须遵守一定的规则,比如只有在持有要求的 osdmap 的时候才能开始处理它,不能依据老版本的 osdmap 行事。

  • 需要跑完一定的圈数,

  • 而且,对于 Ceph 来说,特定客户端发来的多个请求必须顺序完成。好像来自一个车队的选手必须按照出场顺序完赛一样。

在 crimson 里面,满足前两个要求都比较简单直接。问题在于第三个。如果 object store 能保证先进先出,那么是不是只要保证发送请求到 object store 的顺序满足第三个要求就行了呢?

答案是不行。在中间有的阶段需要有 write barrier,比如,为了保证 osd 在恢复时有个参考,pglog 保存了 PG 最近的一系列操作,它们保存在 pglog 里面。在构造 transaction 的时候,会和封装用户数据的 journal 一起刷到磁盘上。但是 pglog 是一个链表,链表上每个环节都是一次对 PG 的修改操作。为了逻辑上简单一些,我们需要 pglog 上的操作序列也按照按照客户请求的顺序安排。这样在副本不一致的时候,就可以按照顺序恢复了。不用担心因为乱序执行带来的数据依赖的问题。所以在生成 pglog 的时候,需要保证顺序。

类似的,在写磁盘的时候也需要保证顺序,因为相同的读写操作以不同顺序发送到后端存储,得到的结果是不一样的。这个道理和之前《多核和顺序》一文中讨论的问题类似。所以在写磁盘的时候也需要保序。我们使用流水线的设计解决这个问题。