Jepsen对etcd 3.4.3测试的最新结果
- 2020 年 2 月 20 日
- 笔记
作者:Xiang Li
Jepsen对etcd 3.4.3进行了测试和分析,得到了良好的结果和有用的反馈。
etcd设计的一个关键部分是跨分布式键值存储的强一致性保证。Kubernetes、Rook、OpenStack和无数其他重要的软件项目都依赖于etcd,部分原因是etcd项目注重可靠性和正确性。
多年来,etcd团队在构建测试和混沌工程框架方面付出了巨大的努力。我们觉得我们已经改进了我们的一致性,并要求Jepsen进行验证。
https://coreos.com/blog/testing-distributed-systems-in-go.html
https://coreos.com/blog/new-functional-testing-in-etcd.html
Jepsen是测试开源分布式系统以检查它们是否满足其一致性保证的领先公司。他们首次测试etcd是在0.4.1版本(五年前),从那时起我们就一直使用这些发现来改进我们的一致性。在这篇博文中,我们分享了etcd v3.4.3的Jepsen分析的总体积极结果,以及我们解决分析中发现的问题的计划。
Jepsen测试工作的资金由托管etcd的CNCF提供。
有哪些进行得很顺利
在Jepsen针对etcd集群创建的众多故障案例中,它继续按设计运行。从分析中,Jepsen的作者说:
- "etcd 3.4.3 lived up to its claims for key-value operations: we observed nothing but strict-serializable consistency for reads, writes, and even multi-key transactions, during process pauses, crashes, clock skew, network partitions, and membership changes. Strict serializable behavior was the default for key-value operations."
- "Watches appear correct, at least over single keys. So long as compaction does not destroy historical data while a watch isn't running, watches appear to deliver every update to a key in order."
由于Jepsen从不“通过”软件,而是报告不存在禁止的问题,因此这是一个很好的结果。一般来说,它比迄今为止测试的其他分布式数据库要好得多。
https://jepsen.io/analyses
我们认为,有两个因素促成了这个积极的严格分析结果:
1. 一个简单的核心
一个简单的解决方案通常会产生一个健壮的系统。例如,etcd的Raft实现是开源中最简单的实现之一。它关注于Raft的核心状态机,避免了核心库中的wall-time和I/O处理。在它的API中,etcd支持多键事务,但是采用了简单的事务模型来保持系统更容易理解。
2. 严格的测试实践
在etcd开发周期的早期,我们设定了一个目标,在诸如Raft和MVCC存储引擎等核心组件上实现80%和90的单元测试线覆盖率。随着项目的进展,我们努力通过引入故障点来确保核心组件的逻辑路径覆盖。为了满足时间、操作系统调度和异步网络I/ OS的随机性,我们还开发了连续集成测试,24×7运行,尝试在运行的系统上以单元测试无法做到的方式产生问题。这些试验显著提高了etcd的质量。
https://github.com/etcd-io/etcd/issues/1467
确定的问题
当然,没有哪个系统在没有报告某些可能更好的地方的情况下进行Jepsen测试。etcd有一些:
锁的问题
在测试期间发现了一个锁实现问题,其中etcd未能在挂起的锁API调用返回之前检查锁的所有权。
在etcd中,锁获取者与会话相关联;获取者持有锁,直到会话结束。当第一次尝试获取锁时,它可能被其他人持有。在这种情况下,etcd服务器将获取者放入一个队列,它必须在队列中等待,直到其他锁持有者释放锁。问题是,获取者的交易可能会在这段等待时间内终止。这种提前过期的结果是etcd服务器必须在返回API调用之前再次检查会话的存在性。
文档的问题
Jepsen分析不仅包括软件正确性,还验证了文档声明。Jepsen的作者发现了etcd的文档问题和误导性用例。以前的etcd文档中关于一致性(consistency)和隔离(isolation)的内容不清楚,可能会引起混淆。
我们的文档描述了基于Wikipedia定义的一致性模型,这也是一些etcd工程师在大学里学到的分类。它还将隔离级别与一致性级别分开,因为对于如何将两者定义在一起没有普遍的共识。
Jepsen的作者建议etcd文档采用最初由Herlihy和Wing发表的线性化论文中定义的术语“严格的串行化(strict serializability)”。在阅读了关于其他开源项目的文档,以及听取用户的反馈之后,etcd团队同意Jepsen作者的观点,即建议的模型和术语更清晰、更容易理解。
接下来,lock API用例示例具有误导性,可能会导致运行时问题。
与任何其他分布式锁系统一样,etcd锁提供的保证与本地线程级锁不同。具体来说,etcd锁只在etcd自己的密钥空间和带有修订检查的事务中安全地保证互斥。当访问依赖于时间的外部资源时,它提供了较弱的保证。使用分布式锁很难防止死锁和锁定失效,因为分布式锁不能保护同一进程甚至同一机器中的资源。为了解决这个问题,分布式锁通常依赖于租约和心跳机制来检测断开连接的锁持有者并使锁失效。当一个锁持有者断开连接或在没有使用修订检查(etcd中的隔离令牌实现)的情况下暂停时,它可能会与新的锁持有者同时访问受保护的资源。更多细节可以在Kleppmann的博客中找到。
https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html
etcd锁文档没有指出这种区别,并提供了使用锁的不准确示例。我们同意Jepsen团队的观点,即问题必须得到解决,etcd用户应该被告知准确的声明。
问题的处理
etcd团队和Jepsen团队正在处理上面提到的所有问题。以下是问题和修复的列表。我们感谢社区对这些问题的反馈,并帮助etcd项目变得更好。

未来
Jepsen分析不是一次性的工作。在分析过程中,Jepsen团队专门为etcd项目建立了一个广泛的测试框架。它还使etcd团队和社区能够随时运行这些测试并在将来捕获问题。
我们很乐意看到etcd社区中有人将etcd Jepsen测试直接集成到现有的etcd发行流水线中。我们希望确保所有etcd的未来版本都通过了Jepsen测试。
除了Jepsen分析之外,etcd社区总是欢迎与正确性和可靠性相关的贡献。我们对这次测试的结果感到兴奋,并将保持警惕,同时建立一个良好的工程和正确的产品。
要了解更多,请阅读Jepsen给etcd 3.4.3的完整报告。
https://jepsen.io/analyses/etcd-3.4.3