You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

14 KiB

16 | InfluxDB企业版一致性实现剖析他山之石可以攻玉

你好,我是韩健。

学习了前面15讲的内容后我们了解了很多常用的理论和算法比如CAP定理、Raft算法等。是不是理解了这些内容就能够游刃有余地处理实际系统的问题了呢

在我看来,还远远不够,因为理论和实践的中间是存在鸿沟的,比如,你可能有这样的感受,提到编程语言的语法或者分布式算法的论文,你说起来头头是道,但遇到实际系统时,还是无法写程序,开发分布式系统。

而我常说实战是学习的最终目的。为了帮你更好地掌握前面的理论和算法接下来我用5讲的时间分别以InfluxDB企业版一致性实现、Hashicorp Raft、KV系统开发实战为例带你了解如何在实战中使用技术掌握分布式的实战能力。

今天这一讲我就以InfluxDB企业版为例带你看一看系统是如何实现一致性的。有的同学可能会问了为什么是InfluxDB企业版呢因为它是排名第一的时序数据库相比其他分布式系统比如KV存储时序数据库更加复杂因为我们要分别设计2个完全不一样的一致性模型。当你理解了这样一个复杂的系统实现后就能更加得心应手地处理简单系统的问题了。

那么为了帮你达到这个目的。我会先介绍一下时序数据库的背景知识,因为技术是用来解决实际场景的问题的,正如我之前常说的“要根据场景特点,权衡折中来设计系统”。所以当你了解了这些背景知识后,就能更好的理解为什么要这么设计了。

什么是时序数据库?

你可以这么理解时序数据库就是存储时序数据的数据库就像MySQL是存储关系型数据的数据库。而时序数据就是按照时间顺序记录系统、设备状态变化的数据比如CPU利用率、某一时间的环境温度等就像下面的样子

> insert cpu_usage,host=server01,location=cn-sz user=23.0,system=57.0
> select * from cpu_usage
name: cpu_usage
time                host     location system user
----                ----     -------- ------ ----
1557834774258860710 server01 cn-sz    55     25
>

在我看来,时序数据最大的特点是数据量很大,可以不夸张地说是海量。时序数据主要来自监控(监控被称为业务之眼),而且在不影响业务运行的前提下,监控埋点是越多越好,这样才能及时发现问题、复盘故障。

那么作为时序数据库InfluxDB企业版的架构是什么样子呢

你可能已经了解过它是由META节点和DATA节点2个逻辑单元组成的而且这两个节点是2个单独的程序。那你也许会问了为什么不能合成到一个程序呢答案是场景不同。

  • META节点存放的是系统运行的关键元信息比如数据库Database、表Measurement、保留策略Retention policy等。它的特点是一致性敏感但读写访问量不高需要一定的容错能力。
  • DATA节点存放的是具体的时序数据。它有这样几个特点最终一致性、面向业务、性能越高越好除了容错还需要实现水平扩展扩展集群的读写性能。

我想说的是对于META节点来说节点数的多少代表的是容错能力一般3个节点就可以了因为从实际系统运行观察看能容忍一个节点故障就可以了。但对DATA节点而言节点数的多少则代表了读写性能一般而言在一定数量以内比如10个节点越多越好因为节点数越多读写性能也越高但节点数量太多也不行因为查询时就会出现访问节点数过多而延迟大的问题。

所以基于不同场景特点的考虑2个单独程序更合适。如果META节点和DATA节点合并为一个程序因读写性能需要设计了一个10节点的DATA节点集群这就意味着META节点集群Raft集群也是10个节点。在学了Raft算法之后你应该知道这时就会出现消息数多、日志提交慢的问题肯定不行了。对Raft日志复制不了解的同学可以回顾一下08讲

现在你了解时序数据库以及InfluxDB企业版的META节点和DATA节点了吧那么怎么实现META节点和DATA节点的一致性呢

如何实现META节点一致性

你可以这样想象一下META节点存放的是系统运行的关键元信息那么当写操作发生后就要立即读取到最新的数据。比如创建了数据库“telegraf”如果有的DATA节点不能读取到这个最新信息那就会导致相关的时序数据写失败肯定不行。

所以META节点需要强一致性实现CAP中的CP模型对CAP理论不熟悉的同学可以先回顾下02讲)。

那么InfluxDB企业版是如何实现的呢

因为InflxuDB企业版是闭源的商业软件通过官方文档我们可以知道它使用Raft算法实现META节点的一致性一般推荐3节点的集群配置。那么说完META节点的一致性实现之后我接着说一说DATA节点的一致性实现。

如何实现DATA节点一致性

我们刚刚提到DATA节点存放的是具体的时序数据对一致性要求不高实现最终一致性就可以了。但是DATA节点也在同时作为接入层直接面向业务考虑到时序数据的量很大要实现水平扩展所以必须要选用CAP中的AP模型因为AP模型不像CP模型那样采用一个算法比如Raft算法就可以实现了也就是说AP模型更复杂具体有这样几个实现步骤。

自定义副本数

首先,你需要考虑冗余备份,也就是同一份数据可能需要设置为多个副本,当部分节点出问题时,系统仍然能读写数据,正常运行。

那么,该如何设置副本呢?答案是实现自定义副本数。

关于自定义副本数的实现,我们在12讲介绍了在这里就不啰嗦了。不过我想补充一点相比Raft算法节点和副本必须一一对应也就是说集群中有多少个节点就必须有多少个副本你看自定义副本数是不是更灵活呢

学到这里有同学可能已经想到了当集群支持多副本时必然会出现一个节点写远程节点时RPC通讯失败的情况那么怎么处理这个问题呢

Hinted-handoff

我想说的是一个节点接收到写请求时需要将写请求中的数据转发一份到其他副本所在的节点那么在这个过程中远程RPC通讯是可能会失败的比如网络不通了目标节点宕机了等等就像下图的样子。

那么如何处理这种情况呢答案是实现Hinted-handoff。在InfluxDB企业版中Hinted-handoff是这样实现的:

  • 写失败的请求,会缓存到本地硬盘上;
  • 周期性地尝试重传;
  • 相关参数信息,比如缓存空间大小(max-szie)、缓存周期max-age、尝试间隔retry-interval是可配置的。

在这里我想补充一点除了网络故障、节点故障外在实际场景中临时的突发流量也会导致系统过载出现RPC通讯失败的情况这时也需要Hinted-handoff能力。

虽然Hinted-handoff可以通过重传的方式来处理数据不一致的问题但当写失败请求的数据大于本地缓存空间时比如某个节点长期故障写请求的数据还是会丢失的最终的节点的数据还是不一致的那么怎么实现数据的最终一致性呢答案是反熵。

反熵

需要你注意的是时序数据虽然一致性不敏感能容忍短暂的不一致但如果查询的数据长期不一致的话肯定就不行了因为这样就会出现“Flapping Dashboard”的现象也就是说向不同节点查询数据生成的仪表盘视图不一样就像图2和图3的样子。


从上面的2个监控视图中你可以看到同一份数据查询不同的节点生成的视图是不一样的。那么如何实现最终一致性呢

答案就是咱们刚刚说的反熵,而我在11讲以自研InfluxDB系统为例介绍过反熵的实现InfluxDB企业版类似所以在这里就不啰嗦了。

不过有的同学可能会存在这样的疑问,实现反熵是以什么为准来修复数据的不一致呢?我想说的是,时序数据像日志数据一样,创建后就不会再修改了,一直存放在那里,直到被删除。

所以,数据副本之间的数据不一致,是因为数据写失败导致数据丢失了,也就是说,存在的都是合理的,缺失的就是需要修复的。这时我们可以采用两两对比、添加缺失数据的方式,来修复各数据副本的不一致了。

Quorum NWR

最后有同学可能会说了我要在公司官网上展示的监控数据的仪表板Dashboard是不能容忍视图不一致的情况的也就是无法容忍任何“Flapping Dashboard”的现象。那么怎么办呢这时我们就要实现强一致性Werner Vogels提到的强一致性也就是每次读操作都要能读取最新数据不能读到旧数据。

那么在一个AP型的分布式系统中如何实现强一致性呢

答案是实现Quorum NWR。同样关于Quorum NWR的实现我们在12讲已介绍在这里也就不啰嗦了。

最后我想说的是你可以看到实现AP型分布式系统比实现CP型分布式要复杂的。另外通过上面的内容学习我希望你能注意到技术是用来解决场景需求的没有十全十美的技术在实际工作中需要我们深入研究场景特点提炼场景需求然后根据场景特点权衡折中设计出适合该场景特点的分布式系统。

内容小结

本节课我主要带你了解时序数据库、META节点一致性的实现、DATA节点一致性的实现。以一个复杂的实际系统为例带你将前面学习到的理论串联起来让你知道它们如何在实际场景中使用。我希望你明确的重点如下

  1. CAP理论是一把尺子能辅助我们分析问题、总结归纳问题指导我们如何做妥协折中。所以我建议你在实践中多研究多思考一定不能认为某某技术“真香”十全十美了要根据场景特点活学活用技术。

  2. 通过Raft算法我们能实现强一致性的分布式系统能保证写操作完成后后续所有的读操作都能读取到最新的数据。

  3. 通过自定义副本数、Hinted-handoff、反熵、Quorum NWR等技术我们能实现AP型分布式系统还能通过水平扩展高效扩展集群的读写能力。

最后我想再强调下技术是用来解决场景的需求的只有当你吃透技术深刻理解场景的需求才能开发出适合这个场景的分布式系统。另外我还想让你知道的是InfluxDB企业版一年的License费高达1.5万美刀,为什么它值这个价钱?就是因为技术带来的高性能和成本优势。比如:

  • 相比OpenTSDBInfluxDB的写性能是它的9.96倍存储效率是它的8.69倍查询效率是它的7.38倍。
  • 相比GraphiteInfluxDB的写性能是它的12倍存储效率是6.3倍查询效率是9倍。

在这里我想说的是,数倍或者数量级的性能优势其实就是钱,而且业务规模越大,省钱效果越突出。

另外我想说的是尽管influxdb-comparisons的测试比较贴近实际场景比如它的DevOps测试模型与我们观察到常见的实际场景是一致的。但从实际效果看InfluxDB的优势更加明显成本优势更加突出。因为传统的时序数据库不仅仅是性能低而且在海量数据场景下接入和查询的痛点突出。为了缓解这些痛点引入和堆砌了更多的开源软件。比如

  • 往往需要引入Kafka来缓解因突发接入流量导致的丢数据问题
  • 需要引入Storm、Flink来缓解时序数据库计算性能差的问题
  • 需要做热数据的内存缓存,来解决查询超时的问题。

所以在实施中除了原有的时序数据库会被替换掉还有大量的开源软件会被省掉成本优势突出。在这里我想说的是从实际实施看自研InfluxDB系统性能优势和成本优势也是符合这个预期的。

最后我想说的是我反对堆砌开源软件建议谨慎引入Kafka等缓存中间件。老话说在计算机中任何问题都可以通过引入一个中间层来解决。这句话是正确的但背后的成本是不容忽视的尤其是在海量系统中。**我的建议是直面问题,通过技术手段在代码和架构层面解决它,而不是引入和堆砌更多的开源软件。**其实InfluxDB团队也是这么做比如他们两次重构存储引擎。

课堂思考

我提到没有十全十美的技术,而是需要根据场景特点,权衡折中,设计出适合场景特点的分布式系统。那么你试着思考一下,假设有这样一个场景,一个存储系统,访问它的写请求不多(比如 1K QPS但访问它的读请求很多比如1M QPS而且客户端查询时对数据的一致性敏感也就是需要实现强一致性那么我们该如何设计这个系统呢为什么呢欢迎在留言区分享你的看法与我一同讨论。

最后,感谢你的阅读,如果这篇文章让你有所收获,也欢迎你将它分享给更多的朋友。