极客时间已完结课程限时免费阅读

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

16 | InfluxDB企业版一致性实现剖析:他山之石,可以攻玉-极客时间

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

讲述:于航

时长14:34大小13.34M

你好,我是韩健。
学习了前面 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 通讯是可能会失败的,比如网络不通了,目标节点宕机了,等等,就像下图的样子。
图1
那么如何处理这种情况呢?答案是实现 Hinted-handoff。在 InfluxDB 企业版中,Hinted-handoff 是这样实现的:
写失败的请求,会缓存到本地硬盘上 ;
周期性地尝试重传 ;
相关参数信息,比如缓存空间大小 (max-szie)、缓存周期(max-age)、尝试间隔(retry-interval)等,是可配置的。
在这里我想补充一点,除了网络故障、节点故障外,在实际场景中,临时的突发流量也会导致系统过载,出现 RPC 通讯失败的情况,这时也需要 Hinted-handoff 能力。
虽然 Hinted-handoff 可以通过重传的方式来处理数据不一致的问题,但当写失败请求的数据大于本地缓存空间时,比如某个节点长期故障,写请求的数据还是会丢失的,最终的节点的数据还是不一致的,那么怎么实现数据的最终一致性呢?答案是反熵。

反熵

需要你注意的是,时序数据虽然一致性不敏感,能容忍短暂的不一致,但如果查询的数据长期不一致的话,肯定就不行了,因为这样就会出现“Flapping Dashboard”的现象,也就是说向不同节点查询数据,生成的仪表盘视图不一样,就像图 2 和图 3 的样子。
图2
图3
从上面的 2 个监控视图中你可以看到,同一份数据,查询不同的节点,生成的视图是不一样的。那么,如何实现最终一致性呢?
答案就是咱们刚刚说的反熵,而我在11 讲以自研 InfluxDB 系统为例介绍过反熵的实现,InfluxDB 企业版类似,所以在这里就不啰嗦了。
不过有的同学可能会存在这样的疑问,实现反熵是以什么为准来修复数据的不一致呢?我想说的是,时序数据像日志数据一样,创建后就不会再修改了,一直存放在那里,直到被删除。
所以,数据副本之间的数据不一致,是因为数据写失败导致数据丢失了,也就是说,存在的都是合理的,缺失的就是需要修复的。这时我们可以采用两两对比、添加缺失数据的方式,来修复各数据副本的不一致了。

Quorum NWR

最后,有同学可能会说了,我要在公司官网上展示的监控数据的仪表板(Dashboard),是不能容忍视图不一致的情况的,也就是无法容忍任何“Flapping Dashboard”的现象。那么怎么办呢?这时我们就要实现强一致性(Werner Vogels 提到的强一致性),也就是每次读操作都要能读取最新数据,不能读到旧数据。
那么在一个 AP 型的分布式系统中,如何实现强一致性呢?
答案是实现 Quorum NWR。同样,关于 Quorum NWR 的实现,我们在 12 讲已介绍,在这里也就不啰嗦了。
最后我想说的是,你可以看到,实现 AP 型分布式系统,比实现 CP 型分布式要复杂的。另外,通过上面的内容学习,我希望你能注意到,技术是用来解决场景需求的,没有十全十美的技术,在实际工作中,需要我们深入研究场景特点,提炼场景需求,然后根据场景特点权衡折中,设计出适合该场景特点的分布式系统。

内容小结

本节课我主要带你了解时序数据库、META 节点一致性的实现、DATA 节点一致性的实现。以一个复杂的实际系统为例,带你将前面学习到的理论串联起来,让你知道它们如何在实际场景中使用。我希望你明确的重点如下:
CAP 理论是一把尺子,能辅助我们分析问题、总结归纳问题,指导我们如何做妥协折中。所以,我建议你在实践中多研究多思考,一定不能认为某某技术“真香”,十全十美了,要根据场景特点活学活用技术。
通过 Raft 算法,我们能实现强一致性的分布式系统,能保证写操作完成后,后续所有的读操作,都能读取到最新的数据。
通过自定义副本数、Hinted-handoff、反熵、Quorum NWR 等技术,我们能实现 AP 型分布式系统,还能通过水平扩展,高效扩展集群的读写能力。
最后,我想再强调下,技术是用来解决场景的需求的,只有当你吃透技术,深刻理解场景的需求,才能开发出适合这个场景的分布式系统。另外我还想让你知道的是,InfluxDB 企业版一年的 License 费高达 1.5 万美刀,为什么它值这个价钱?就是因为技术带来的高性能和成本优势。比如:
相比 OpenTSDB,InfluxDB 的写性能是它的 9.96 倍,存储效率是它的 8.69 倍,查询效率是它的 7.38 倍。
相比 Graphite,InfluxDB 的写性能是它的 12 倍,存储效率是 6.3 倍,查询效率是 9 倍。
在这里我想说的是,数倍或者数量级的性能优势其实就是钱,而且业务规模越大,省钱效果越突出。
另外我想说的是,尽管 influxdb-comparisons 的测试比较贴近实际场景,比如它的 DevOps 测试模型,与我们观察到常见的实际场景是一致的。但从实际效果看,InfluxDB 的优势更加明显,成本优势更加突出。因为传统的时序数据库不仅仅是性能低,而且在海量数据场景下,接入和查询的痛点突出。为了缓解这些痛点,引入和堆砌了更多的开源软件。比如:
往往需要引入 Kafka 来缓解,因突发接入流量导致的丢数据问题;
需要引入 Storm、Flink 来缓解,时序数据库计算性能差的问题;
需要做热数据的内存缓存,来解决查询超时的问题。
所以在实施中,除了原有的时序数据库会被替换掉,还有大量的开源软件会被省掉,成本优势突出。在这里我想说的是,从实际实施看(自研 InfluxDB 系统),性能优势和成本优势也是符合这个预期的。
最后我想说的是,我反对堆砌开源软件,建议谨慎引入 Kafka 等缓存中间件。老话说,在计算机中,任何问题都可以通过引入一个中间层来解决。这句话是正确的,但背后的成本是不容忽视的,尤其是在海量系统中。我的建议是直面问题,通过技术手段在代码和架构层面解决它,而不是引入和堆砌更多的开源软件。其实,InfluxDB 团队也是这么做,比如他们两次重构存储引擎。

课堂思考

我提到没有十全十美的技术,而是需要根据场景特点,权衡折中,设计出适合场景特点的分布式系统。那么你试着思考一下,假设有这样一个场景,一个存储系统,访问它的写请求不多(比如 1K QPS),但访问它的读请求很多(比如 1M QPS),而且客户端查询时,对数据的一致性敏感,也就是需要实现强一致性,那么我们该如何设计这个系统呢?为什么呢?欢迎在留言区分享你的看法,与我一同讨论。
最后,感谢你的阅读,如果这篇文章让你有所收获,也欢迎你将它分享给更多的朋友。
分享给需要的人,Ta购买本课程,你将得18
生成海报并分享

赞 10

提建议

上一篇
加餐 | TCC如何实现指令执行的原子性?
下一篇
17 | Hashicorp Raft(一):如何跨过理论和代码之间的鸿沟?
 写留言

精选留言(27)

  • Geek_3894f9
    2020-03-18
    课后思考题,答案是QNWR,Wn,R1。wn是因为对写入的时间要求不高,r1是因为可以读取任意一节点,读性能好。

    作者回复: 加一颗星:)。

    共 2 条评论
    21
  • Michael Tesla
    2020-04-06
    我觉得思考题的场景特点是:读多写少,读的性能要求高,数据要保证强一致性。 如果使用 Raft 算法 保证强一致性,那么读写操作都应该在领导者节点上进行。这样的话,读的性能相当于单机,不是很理想。 应该采用 Quorum NWR 技术,设置 W = N,R = 1。每次都要写入全部节点,写操作的性能会比较差。但是,因为写操作比较少,所以这个缺点可以忍受。而读操作只需要读任意一个节点就能返回最新的数据,性能非常高。
    展开

    作者回复: 加一颗星:),这是个解决办法,与这个办法“类似”的二阶段提交协议,也是个办法。

    共 3 条评论
    15
  • 阿卡牛
    2020-03-25
    这个实战太企业了,新手完全无从下门,有没有些入门的课程

    作者回复: 主要感觉哪方面学习起来比较困难呢?能具体说说吗? 看到了反馈,我补充下,其实,技术是一点一点学习的,关键要找到一个点,在深度上进行突破,然后再在广度上扩展开来了,比如,可以先聚焦在实战篇的分布式KV系统,将代码玩起了,吃透分布式系统的架构和开发方法,多玩代码,少想理论。代码玩出了感觉后,聚焦和吃透Raft算法。最后,再聚焦和吃透其他理论。

    共 5 条评论
    8
  • Kvicii.Y
    2020-03-30
    1.META节点是Raft算法实现,那是不是存在这如果节点过多消息同步慢的问题呢?存在的话如何解决呢?(只能减少Raft节点?) 2.思考题使用quorum nwr可以达到最终一致性,这里说的强一致是最终一致的意思吗?

    作者回复: 1. 不推荐节点数过多,一般推荐3个节点,也就是能容错一个节点故障,就可以了。 2. 通过反熵,可以实现最终一致性。通过quorum nwr,可以让业务按需选择一致性级别,比如说,可以是强一致性,也可以是最终一致性。

    4
  • 每天晒白牙
    2020-03-18
    感觉自己对这些知识理解的还是不够,更不能进行实战应用,还得好好学学。 对于思考题,首先要求强一致性,读多写少,那是不是可以像 META 节点一样,采用 Raft 算法实现强一致性。但这样对性能可能就有影响了,不过这个 KV 系统是读多写少,应该也可以 然后就是从性能考虑,可以在 AP 系统中实现强一致性。根据文中提示,可以采用 Quorun NWR 实现
    展开

    作者回复: 加一颗星:),如果直接使用Raft集群,读性能满足不了,可以增加几台内存缓存服务器,来提升读性能。

    共 2 条评论
    3
  • Following U
    2020-07-12
    hello,讲师好,influxdb 企业版你这边的分布式版本的github 地址吗?

    作者回复: https://github.com/freetsdb/freetsdb,现在是Alpha版,还在准备中。项目中一些有意思的技术点和设计,我也会在第一时间和大家分享同步:)。

    3
  • 夜空中最亮的星
    2020-03-18
    喜欢案例,让案例来的更猛烈些吧

    作者回复: 好的,也期待你的更多反馈:)。

    2
  • Heaven
    2020-08-21
    读多写少啊,只需要保证在每次都必须要写入到每一个节点上就可以了,然后读的时候直接去读,自然是最新的

    作者回复: 加一颗星:)

    1
  • hanazawakana
    2020-06-26
    hinted-handoff是直接邮寄的一种实现方式吗

    作者回复: 加一颗星:),可以这么理解,只是“直接邮寄”背后的思想普适、常见,所以,“直接邮寄”很少被提及了。

    1
  • Dylan
    2020-04-09
    可以在AP模型中,引入QNWR

    作者回复: 加一颗星:)

    1
  • 88591
    2020-04-02
    1、存储系统,数据肯定要冗余 2、可以使用WNR 模型 1、写不多 ,全写 2、读多,一个读

    作者回复: 加一颗星:)

    1
  • 欧阳
    2020-03-30
    除了quorum NWR。kfk的分区是不是也是一种思路

    作者回复: 加一颗星:),目标不同,quorum NWR实现的是自定义一致性级别,kfk分区是为了实现水平扩展、负载均衡,提升读写性能。

    共 2 条评论
    2
  • 姜川
    2020-03-26
    老师,raft要实现强一致是不是就需要收到所有节点的ACK才可以,半数以上那种只能是最终一致性吧,因为会有短暂的不一致发生

    作者回复: 加一颗星:),不需要,在领导者节点上执行读操作,可以实现强一致性:)

    2
  • pedro
    2020-03-18
    前面的十几讲都在为这一讲做铺垫,快更新,看看后面的实战部分😃

    作者回复: 加一颗星:),理论的实战总结:)。

    1
  • 核桃
    2022-01-09
    这里关于InfluxDB的副本机制,因为这里的数据是监控数据的话,其实没必要实现主副本那种,但是在其他场景中,例如分布式文件系统里面,就需要了,因为修复数据的难度更大了. 当然这里关于副本数据传输,有一个优化点的,使用两个缓存队列来实现. 第一队列就是正常接受到数据的时候正常串行发送. 如果节点发送Data数据到其他节点上失败了,那么在简单重试后还是失败,就应该放到第二缓存队列中. 在第二队列的任务都是那些有问题的需要不断重试的,这时候可以上报到Meta集群里面了.进行其他的处理. 总的来说,因为本人是做分布式文件系统的,这里真的有很多很多相似的地方,但是文件系统需要考虑修复和数据重平衡等很多很多问题.
    展开
  • nomoshen
    2020-10-19
    关于最后的堆砌开源软件这个观点我其实有点不能认同;的确在influxdb场景上的存储不断的优化是值得鼓励,并且觉得这就是它的门槛和优势;但是在一些时序场景上加入内存数据库、消息队列、流式引擎来解决时序场景上的一些难点我觉得也是可以的;

    作者回复: 加一颗星:),在大数据、海量数据场景,除了设备成本高昂(比如某团队采用类似方案的系统,一年的设备成本,80个Million),效果也不好,多个团队、多个系统,能证明这点,而这个点也是当前的痛点,大家着力解决的。

  • 要努力的兵长
    2020-09-11
    它使用 Raft 算法实现 META 节点的一致性(一般推荐 3 节点的集群配置) ------------ Raft算法 来实现强一致性??? Raft算法不是只可 最终一致性吗?

    作者回复: 加一颗星:),限制读操作只能在领导者节点上执行,可以实现强一致性。实现的是最终一致性还是强一致性,取决于读操作能否在非领导者节点上执行。

  • hanazawakana
    2020-06-01
    请问这个Quorum NWR是influxdb enterprise才有的吗?influxdb 1.0版本和2.0版本没有吗?

    作者回复: 加一颗星:),企业版是分布式系统,支持的。而开源版是单机,不支持的,因为即使实现了,也没有意义。

  • 竹马彦四郎的好朋友影...
    2020-05-06
    "因为查询时就会出现访问节点数过多而延迟大的问题。" 这句话感觉是不是想表达的是如果AP系统包含节点过多,因为要达到最终一致性,会导致同步时间比较长,所以读到最新数据延迟长~

    作者回复: 加一颗星:),查询涉及到不同节点的多个分片时,通讯多,延迟大,比如,如果10节点集群,统计一天的时序记录的count,涉及到了20个分片,分别在10个节点上,这时就可能出现因通讯多而延迟大的问题。

  • 竹马彦四郎的好朋友影...
    2020-05-06
    我觉得这是老师对前面的知识的一个串讲~ 感觉很好~ 赞!

    作者回复: 加一颗星:),实战总结,技术的最终目的,是实战,在实战中才能更好的理解技术,而不会陷入“白马非马”等形而上的争论和纠结中。