导语 | 腾讯云Elasticsearch在腾讯会议中有哪些应用?在大规模海量应用场景下,腾讯云Elasticsearch在高可用和性能方面做了哪些优化?在低成本解决方案中又有哪些独到之处?本文是对腾讯云专家工程师张彬老师在云+社区沙龙online的分享整理,希望与大家一同交流。
点击视频查看完整直播回放
一、腾讯云ES在腾讯会议中的应用腾讯会议于2019年12月底上线,两个月内日活突破1000万,被广泛应用于疫情防控会议、远程办公、师生远程授课等场景,为疫情期间的复工复产提供了重要的远程沟通工具。极速增长的会议需求,让腾讯会议服务质量分析系统经受着巨大的考验。
在会议中偶然会存在会议实时音视频卡顿、音视频不同步等会议质量问题,造成上述问题的可能因素比较多,当前运行的网络有丢包或连接不稳定的情况就是其中一种。
为了帮助会议质量团队快速精准地定位分析问题,需要大量运行时的会议质量数据支撑,如网络相关的入网类型、码率、丢包率、网络切换、ip切换等数据,以及客户端相关的CPU使用率、内存使用率、操作系统版本、产品版本等数据信息。
除了数据的实时上报,另一方面,借助多维分析,我们还可以在实时数据中挖掘出异常情况。如某个地区大面积的卡顿,某个版本出现特定的问题等。通过dashboard或数据报表的形式,帮助会议质量团队及时掌控全局情况,快速发现潜在问题。
随着疫情爆发,腾讯会议快速增长,在100天内迭代了20多个版本,在8天内主机数扩容到了 10w 台,这样的急剧增长量让腾讯会议服务质量分析系统经受高压力,给运营团队及时排查用户问题带来了巨大的挑战。
深究根本原因,是因为服务质量分析系统在如此高压力、高吞吐的场景下,写入性能严重不足导致。腾讯会议和质量分析系统研发团队也一起对问题做了梳理。主要表现在以下四个方面:
下图展示了整个系统的架构图,红线上面部分是原先使用的质量分析系统。腾讯会议的质量数据,由上报接口机采集后到我们自研的接入服务,做数据清洗或转换的ETL过程,最后把数据写入到自研的 lucene 数据存储引擎里,提供数据查询和分析能力。
系统架构图
原来的系统可能会遇到很多问题,首先在可用性方面,原来自研的 lucene 引擎是用 Java 写的,内存使用过多就会 OOM ,导致节点挂掉,进而造成集群的雪崩。这样 SLA 就难以保障,达不到 4 个 9 的要求,质量团队经常面临系统崩溃之后用户问题得不到及时跟进和解决的困扰。
第二个问题在于性能。疫情爆发之后,峰值系统写入量接近 300w/s,这个量是非常大的。由此造成了系统数据同步延迟比较高,大量数据堆积在里面长时间得不到消费。比如我们在前端查询用户的一些实时质量问题的时候,发现时延经常在半小时以上,这肯定无法达到我们的质量要求。
在出现如上问题的时候,大家通常做法可能就是去扩容。由于系统最关键的部分,是一个基于lucene自研的搜索引擎,扩容能力比较差,依赖于研发团队针对业务的优化。在数据量暴涨的背景下,不能进行快速扩容以满足需求。
另外,在新系统选型切换的过程中,我们也要考虑易用性。用户数暴增,留给系统验证切换的时间非常短,这要求我们必须使用一种简单快速的解决方案。需要在一周之内输出适用方案,并进行线上数据的切换。
由于时间紧迫,新的方案需要尽量保留原有架构的大部分基础设施,并做尽量少的代码开发改动。
经过讨论,最终决定把原来这套架构切换成 Elasticsearch 比较经典的 ELK 架构。通过logstash的易用性和强大的生态插件,可以快速替代原有的自研数据接入组件,进行数据的清洗转换等ETL过程。如原有架构中使用的kafka,在logstash中就已经包含了相应的input插件。并且有大量数据格式的解析插件支持,对于数据的一些解析、过滤、清洗等操作可以直接在logstash的pipeline中进行简单的配置即可,基本上是0开发量。
丰富的各语言SDK,方便快速的对服务质量分析平台前后台进行快速切换,实际从代码修改到上线完成只用了一天的时间。
二、 高可用及性能方向的优化
腾讯会议服务质量分析系统,从2月份进行ES架构的方案切换开始,写入吞吐从5w/s不断攀升,现已达到100w+/s。
业务的突发增长有时候来的很突然,并不能在前期做有效的评估。社区中的很多用户也遇到过类似的问题,由于没有预估到业务突发的增长,并且在业务层没有做好服务降级等机制,导致突发的写入查询流量打崩了整个集群。
例如早期我们内部一个日志集群,写入量一天突增 5 倍,集群多个节点 Old GC 卡住脱离集群,集群 RED,写入停止,给我们带来了不小的麻烦。
我们对挂掉的节点做了内存分析,发现大部分内存是被反序列化前后的写入请求占用。我们对
挂掉集群的内存镜像做了一些梳理,发现大量的写入请求其实都是用在反序列化这里,耗内存比较多。
上图展示了ES high level 的写入流程,用户的写入请求先到达其中一个数据节点,我们称之为数据节点。然后由该协调节点将请求转发给主分片所在节点进行写入,主分片写入完毕再由主分片转发给从分片写入,最后返回给客户端写入结果。
右边是更细节的写入流程,而我们从堆栈中看到的写入请求堆积的位置就是在红色框中的接入层,节点挂掉的根因是协调节点的接入层内存被打爆。
针对这种高并发场景,我们的优化方案是服务限流。除了要能控制并发请求数量,还要能精准地控制内存资源,因为内存资源不足是主要的矛盾。另外通用性要强,能作用于各个层级实现全链限流。
在很多数据库使用场景,会采用从业务端或者独立的 proxy 层配置相关的业务规则的限流方案,通过资源预估等方式进行限流。这种方式适应能力弱,运维成本高,而且业务端很难准确预估资源消耗。
ES 原生版本本身有限流策略,是基于请求数的漏桶策略,通过队列加线程池的方式实现。线程池大小决定了处理并发度,处理不完放到队列,队列放不下则拒绝请求。但是单纯地基于请求数的限流不能控制资源使用量,而且只作用于分片级子请求的传输层,对于我们前面分析的接入层无法起到有效的保护作用。原生版本也有内存熔断策略,但是在协调节点接入层并没有做限制。
我们的优化方案是基于内存资源的漏桶策略。我们将节点 JVM 内存作为漏桶的资源,当内存资源足够的时候,请求可以正常处理;当内存使用量到达一定阈值的时候分区间阶梯式平滑限流。例如上图中浅黄色的区间限制写入,深黄色的区间限制查询,底部红色部分作为预留 buffer,预留给处理中的请求、merge 等操作,以保证节点内存的安全性。
对于大聚合的场景,因为系统收拢进来的数据也是有价值的,我们也会经常在上面做一些分析和查询,比如做腾讯会议在全世界各个地区会议质量情况的展示等。在这样聚合的过程当中,有的指标它的分桶数量是比较多的,可能出现上万甚至十万、百万级别。
结合整个查询流程会发现,在协调节点内会把数据节点汇聚到的分析数据再做一次二次汇聚,对分桶分析过滤,包括做一些排序等,在分桶数量比较多的情况下,协调节点的内存使用压力是比较大的,当一个比较大的查询过来时,这个节点可能就会挂掉。
原生 ES 对查询方面的限制也是比较死的,限制最大返回结果桶数,默认是一万,如果超过这个限制则直接拒绝。但分析场景结果桶数十万、百万是常态,默认1万是不够的。另外这个值也是很难精确设置的,调整不灵活,大了内存会崩掉,小了满足不了业务需求,所以我们也要对它进行优化。
第一阶段我们根据当前 JVM 的内存使用情况做查询的预估,通过内存膨胀系数预估在反序列过程当中所要消耗的内存数量,一旦超过阈值则直接熔断。
第二阶段,reduce 过程中流式检查桶数,每增加固定数量的桶就检查一次内存,如果发现超限则直接熔断。比如总量一万桶,每新增 1024 个桶就需要再检查一次内存,如果超过限制,就直接把这个比较大的聚合查询杀掉。
虽然杀掉当前这个大查询可能会牺牲一定的用户体验,但却能保证整个集群的稳定性。我们的这项优化也已经提交给ES官方社区,并且已经在 7.7.0 这个版本发布了。
在更基础的场景下,比如我们的机器、集群,甚至整个机房挂掉,这种情况下的可用性光靠优化是难以彻底解决的。所以为了达到某些客户,比如电商或者金融客户对关键业务的可用性要求,腾讯云 ES 提供了集群的多可用区部署方案。
一个集群可以选择在两个或三个可用区上部署,这样的话每个节点都能被标记可用性属性,当我们开启分片分配可用区的感知之后,一个索引多个分片的副本可以平均分配到各可用区,这样就能保证一个可用区挂掉以后不影响整个集群的数据完整性,可以稳定给业务提供写入读取的能力。并且切换是透明的,业务方面无感知。
在性能方面的优化,首先在数据合并方面。ES 的底层 Lucene 基于 LSM Tree 的数据文件。合并策略业内有几种典型方案,比如按时间序进行合并,比如把当前一小时内的数据进行合并,典型产品有 Cassandra 、HBase 等。但是它只适合时序场景,而且因为每个小时数据写入量不太一样,导致文件合并的大小不太一致,会影响合并的效率。
另外一些产品如 LevenIDB、RocksDB 选择的是分层合并,优点是查询高效,但是写放大较严重,影响 TPS 。
所以我们在原生方案基础上,同时调研了大量开源社区的方案做了新的优化。因为文件之间按创建时间来看是有序的,这里可以取个巧,并不需要真的关注文件的创建时间,而只需要关注这个文件的时间序就行。
在 L0 层我们会通过文件的创建时间对文件进行排序。在分层合并的时候,再按目标文件大小进行合并,比如在 L1 层设置文件大小是 20M,每攒 20 个小文件就做一次合并,这样既保证了数据的连续性,又将文件数量得到了收敛,最终提升了写入场景查询性能。
我们根据目标文件大小这个维度进行合并,可能会漏掉一些比较小的文件。不过没关系,因为我们后面还做了一个冷分片的持续合并,有一些小的分片因为长期没有写入,始终达不到合并目标的要求,这时会有一个冷分片的持续合并策略,发现有一些小的分片超过五分钟没有被更新,就会强制触发它向上合并。
第二个性能方面的优化是在大吞吐写入方面,以腾讯某金融业务的人群画像分析系统为例,这个系统每天晚上执行一次全链导入任务,在白天只有小批量的更新。对于一些体量比较大的客户,每天晚上全量导入数据量是非常大的,甚至高达十几亿,并且需要在夜间那几个小时导入完成,因为第二天就会对这些数据进行量化分析了。
在使用过程中,业务部门经常会发现写入性能不高,且CPU使用率不稳定的问题,资源利用率严重不足。
腾讯云ES内核团队对类似的高压力写入场景进行了追踪及分析,并在同样的场景下进行了多个方案的压力测试,发现ES单节点的压力写入测试与lucene基准的写压力测试有较大的差距:如果这个数据不通过 ES 而是直接通过 Lucene 写入,性能会提升一倍。
所以我们就对腾讯云 ES 的各种写入流程做了一个分析,发现 Lucene 写入就是单纯地写入数据,但 ES 是一个分布式的系统,为了防止内存里面的数据没有及时刷盘,我们会写一个translog,对应数据库里面的binlog机制。
因为不可能在一个文件上面一直持续写,就需要对大量的文件做管理,因为很多已经刷盘的数据是不需要保留的,所以会有一些轮转的机制。我们会不断地去生成新的文件,然后不断地淘汰小的文件。
在这里面就出现了一个问题:因为 ES 一个节点的写入是并发的,可能有很多写入的限制都在持续地对同一个数据文件做写入,但是当前文件只允许一个线程进入临界区,所以这个锁的同步效率是非常低的,因为不管有多少个写入限制,一旦到了切换的时候这个锁会把所有的写入限制都锁住。
所以这里我们也做了两套优化的方案。第一种方案,我们首先想到了把 rollGeneration 做成异步的,两个流程互相不影响,但是改造量是比较大的。通过社区讨论,我们最终确立了一个非常精简的方案,就是每次rollGeneration前做一次刷盘,后面每次写入的时候不需要都去做这个锁的同步。这个方案对流程的改造最轻量优雅,且优化后的写入性能提高了20%以上。
这部分优化的代码经腾讯内部的业务验证后,最终整理提交回馈给了社区。由于这个优化在ES写入的所有场景下均适用,且对性能的提升非常显著,Elastic的创始人对该PR高度赞扬,并给腾讯云总裁发来了公开感谢信。
腾讯云ES在社区开源的内核之上,根据云上的内外部业务的场景案例积累,做了大量的内核优化。除了上面介绍的translog的优化,还有带“_id”的写入操作剪枝优化、查询计划优化等等,满足了客户在性能方面的需要,并积极将一些通用的优化提交至社区,截至目前为止,腾讯云提交的pr约有50+被合并到了主干。
三、低成本解决方案上的优化
腾讯云自身的监控系统也是基于 ES 来做的,特别对于一些大的地域的集群,它的写入速度甚至达到了千万级每秒。面对这样的吞吐量,并且数据量至少要保留半年时间的可空查询,预估整个集群大概需要能承载 14PB 的数据,按照我们内部用的物理机磁盘的规格,需要 1500 台物理机,远远超出成本预算。
我们对监控系统的业务日志做了分析,发现这类数据都是有时序性的,随着时间的推移它的访问频率越来越低。
所以我们首先给用户推出的解决方案就是冷热分离,在一个集群里我们会给用户提供两种不同属性的机型,用户新写入的数据,或者近期频繁访问的数据可以写入到高配置、高 IO 的机型,比如 64 核甚至更高核数,带云盘或者本地盘的机型,可以保证一天之内或者几个小时之内这种热数据的写入性能。
对于一天以后甚至一周以后才访问的冷数据,可以写入到低配置的机型,比如 12 核甚至 4 核的机型以降低成本。
原生 ES 提供了生命周期管理功能,把数据分为 3 个阶段:Hot phrase 、Warm phrase 、Cold phrase ,在每个阶段都可以对数据做管理,比如热阶段可以按天、小时或者我们自己设置的大小来分索引。
大多数查询或者分析都是按小时、天,而在 Warm 阶段我们可以按秒级采集数据,通过降低数据的精度,极大减少数据的总量,并且提升数据查询的效率。
在冷阶段很多数据可能是作为备份,几乎很少被查询,我们可以关闭一些索引,或者做一些数据的备份,甚至如果数据没有必要还可以删掉。
在存储方面,现在包括腾讯云在内的很多云厂商为用户提供的主要还是 CBS 云盘,但是 CBS 云盘在单盘 IO 能力上有限制,最大不超过 260M/S,所以我们为客户提供了多盘策略。
原来一个节点只能带一块硬盘,现在一个节点可以挂多块盘,这样的话一方面能突破 CBS IO能力限制,原来单盘的 260MB/S ,通过挂 4~5 块盘将能力扩充数倍。另外单节点的 IO 提升之后我们就不需要那么多的节点,能够节约大量成本。
ES 的索引数据每个上面其实分了很多的小文件,所以我们做了一个 COS 上传下载的插件,可以在控制台自动触发或者在 ILM 配置触发,把这些底层数据文件直接备份到成本非常低的 COS 上。如果真的某一天系统数据出现了问题,也可以很方便恢复过来。
以上就是我们在存储成本上的优化,腾讯云监控的集群优化之后只需要两三百台机器就可以扛住原来 1500 台机器做的事情,极大降低了我们的成本。
其次是计算成本上的优化,主要是在内存使用率方面。其实我们磁盘使用率并不高,只有30%~40% ,但是我们的堆内存使用率长期处于 70%-80% ,甚至有时候达到90% 这一比较危险的状态。
原因主要在于索引里面的 FST 占用了大量内存,基本维持在 50%-70% ,而且需要常驻内存不能释放。计算发现,大概每 10TP 的磁盘就需要 10G-15G 来存 FST 缓存。
ES 社区对于这个问题也有一些优化方案,比如因为 FST 对内存占用比较多,类似很多这种大数据的组件就把它移到堆外,这里的优化方案其实很简单,就是通过系统 MMmap 的方式,通过 linux 操作系统数据页的淘汰,如果长时间没有访问就淘汰出去。
这种方案优点是实现简单,但是这种淘汰策略比较粗糙,对于一些海量数据场景,可能一个查询过来,原来那些在 Cache 里面的数据就被淘汰掉了,又要重新换一批,而实际上淘汰的那批数据可能是经常要使用的。
所以,我们也对原生方案做了一些优化,做了两层的 Cache ,借助堆外内存,释放堆内存。在GC之前不会过快的释放,在堆外我们也不推荐通过操作系统方式进行管理,因为毕竟控制的粒度比较粗,我们会通过一些 LRU 或者 LFU 的策略,加上通过 Cache 的访问频次进行一些淘汰。
四、 未来展望
未来在可用性方面,我们会加强智能诊断的功能,因为 ES 在很多方面都需要用户来操心。比如索引设置不太好,可能会导致并发性能不高等等。对于 ES 使用不是特别熟的用户可能会有这样的苦恼,感觉集群经常莫名其妙会出现一些问题,当然也可能是自己使用上没有注意。
通过智能诊断功能,它能持续不断帮助用户去做使用方面的监控,比如索引方面分配的策略等,给客户做一些预先的提醒和预警,在业务受到影响之前,把这个问题扼杀在萌芽之中。
另外我们也会提供节点自愈的能力。在性能方面我们会着重于扩展多维分析的能力,因为现在多维分析的场景在 ES 里应用也比较多,包括前文提到的腾讯会议质量数据的这种多维分析,腾讯云一些金融业务的画像分析等等。
成本方面,基于前文提到的备份策略,我们原来备份到 COS 上面的数据其实就是一份冷数据,写入不了也查询不了,万一哪天我们真的有这样的查询需求,还需要把它重新恢复到集群上面,比较麻烦。
所以我们后面会和社区一起完善推出一种可搜索的备份,我们可以容忍这种搜索的延时,比如一分钟甚至五分钟才把结果返回,但是数据仍是可以放到 COS 上,从而节省大量的成本开支。
我们会比较快推出存储资源分配的功能,相当于节点是可以无限扩充,这样对于某一些经常做活动的用户,活动期间流量非常大,需要瞬间扩容节点来扛住这样比较大的查询请求。当做完活动之后很多节点没有用了,可以把它缩掉,但是数据仍然保留,所以这种存储计算分离的成本优化对于这一类用户是非常需要的。
另外我们会完善数据集成的通道,会支持很多导入导出、数据迁徙的插件,我们计划在 Q3 把它引入到腾讯云,作为一个子产品提供给用户这个功能。在 2020 年 Q4 我们也会结合腾讯云数据库 DBS、 Kafka 组件做这种数据通道,让用户通过控制台的简单配置就可以把数据接入进来。其实 ES 和大数据的组件是可以做一些天然融合的,后面我们也会更多的在大数据平台上做一些融合化的研究和演进。
Q&A
Q:1000 w/s 的索引有几个节点?
A:上文提到的腾讯云监控系统,会有千万级每秒的高压力写入场景。经过优化了之后,只需要两三百个节点左右就能扛住压力。
Q:ILM 可以针对索引么?
A:ILM 是索引生命周期管理,其实就是针对索引的。前文提到成本优化的时候,我们发现数据有时间上冷热的属性,在数据热阶段我们可以通过 ILM 做索引的切分管理,比如一天切一个索引,或者按数据量 1G 切一个索引等等,其它如温场景、冷场景也可以针对索引维度做逐级的数据压缩、删除、备份等操作。
Q:COS 冷备份能再详细展开吗?
A:关于这一块,我推荐大家去阅读腾讯云 ES 官网上的文档,上面有比较详细的解释,包括 API 在 ES 里面的 COS 冷备,API 怎么使用,仓库怎么建立等等。会有 ES 相关文档给出比较详细的介绍,大家可以通过我们提供的免费集群实际操作一下。它的成本是比较低的,效率也比较高,使用起来也方便,大概两三条 API 就可以搞定。另外前文提到的 ILM 功能也支持 COS 冷备,直接可以在 ILM 上进行设置。
Q:一个 ES 集群最大节点数能到多少,会有瓶颈么?
A:目前不推荐用户超过一千个节点。在一个集群中存在过多的节点,因每个节点都会需要和其他节点进行通信及保持心跳,节点规模持续的扩大会造成很多问题,建议利用业务做拆分
Q:第三方 ES 如何迁移至腾讯云 ES ?
A:有很多方案,比较简单可以通过 COS,COS 不仅可以做冷备,也可以做数据迁移。因为我们的 COS 插件是开源,可以下载一个到自建的 ES 系统上,把你的数据全量或者增量备份到 COS 上面,再把它恢复到腾讯云ES上是比较快的。另外在架构设计层面也会有一些不停服迁移方案,也可以咨询一下你的架构师。
Q:堆外内存是怎么用 MMmap 方式做的,腾讯云这里是直接改了 Lucene 了吗?
A:我们在内核方面做了大量的修改,有一部分是对 ES 的修改,另外大量的底层数据存储设计更多是对 Lucene 的修改,这些修改基本上都已经回馈给社区。
Q:ELK 日志延迟过大,是如何追平的?
A :前文提到的腾讯会议延迟过大主要就在于写入性能比较慢,所以一直追不上。我们入手的点也是提升集群的写入能力,一方面我们做了一些扩容类的工作,另外在拷贝方面也做了大量写入查询优化,最后推荐大家尽量使用最新版本,比如腾讯云支持的 7.5.1 版本,或者官方的 7.7 版本,最新版本有大量的写入查询优化。
Q:集群的服务器参数,是要定制化调试么,有成型的解决方案么?
A:这个问题很好,对于服务器我们需要做很多操作系统上的调节,我们的 ES 服务器上也做了大量偏向于 ES 应用的调用,我们云+社区专栏也有一篇文章叫做 ES调用实践,感兴趣的同学可以搜索了解一下。对这些参数的调试理解起来可能会有一些技术难度,并且在运维起来如果有一些参数忘了就会对性能产生影响,所以如果有兴趣可以去云+社区的 ES 专栏或者去社区看相关的一些文章。另外如果不想调试的话可以直接使用一些成熟的云产品。