当前位置: 首页 > 科技观察

网易互娱全球监控体系:亿万级指标下,从分钟级到秒级监控的演进

时间:2023-03-18 14:20:18 科技观察

网易互娱全球监控系统:亿级指标Linktracking、Logging(事件日志)、Metric(聚合指标)下从分钟级到秒级监控的进化。今天分享的话题主要围绕Metric部分展开。为什么叫聚合指标呢?因为我们收集和存储的指标很多,所以在大多数场景下我们关注的是指标的聚合值,比如1分钟或者5分钟内的最大值和平均值,或者一些Top10的数据,或者一些分位数的值,比如第95位或者第90个百分位数,代表每个人都或多或少接触过的产品。比如ELK是Logging的代表,Prometheus是近几年比较流行的。一、自研时序数据库EyesTSDB简介第一部分将从概述、架构设计、核心功能、应用场景、问题与挑战五个方面介绍我们自研时序数据库EyesTSDB。1.概览自研时序数据库,支持全局监控。覆盖全球10多个国家、20多个地区。还支持国内私有云、公有云、混合云监控,可同时满足公司游戏出海。监控需求。我们有多种监控方式,包括基础监控、网络监控、线程监控和业务定制。我们也有丰富的数据收集方法。目前Agent收集的插件有1000+。SDK通过HTTP等网络协议上报或上报监控数据。它还支持内部日志数据转换,以便在程序开发时可以快速连接到我们的监控平台。.另外我们的服务对象包括我们的基础设施,有超过30万台物理机,还有云监控和k8s容器监控。服务产品包括梦幻西游、大话西游、阴阳师等公司的头部产品,上图也列出了我们目前的量级。我们现在有1500万个监测实体,连续指标总数达到15亿个。2.架构设计接下来介绍一下我们的架构设计。这是简化版的架构图,分为上下两部分。上半部分是监控中心,下半部分是Region区域。1)监控中心监控中心包括前端系统UI和告警界面,以及后面的监控调度、数据总线、数据存储和插件仓库,后面会详细介绍。2)MonitoringRegionMonitoringRegion主要包括Region节点和被监控机器,被监控机器上会安装一个Agent插件。Arbiter:我们的监控调度中心也是一个核心模块。它结合CMDB生成监控机器的配置,同时负责Region的保活和调度。它采用Active-Standby主备模式来保证高可用性。数据总线:主要负责采集监控数据,然后通过Kafka中转。数据存储:我们设计了冷热存储来存储我们的时间序列数据。插件仓库:是我们的特色之一。它将与gitlab链接以保存用户的插件。用户可以通过自定义插件代码实现自己想要的任何监控方式。监控调度:结合cmdb生成配置,负责Region的保活和调度,采用Active-Standby模式保证高可用。Agent:负责采集监控指标并上报给Region,由Region统一上报给数据总线,包括核心模块、系统插件、网络插件、用户自定义插件.右图是服务器端监控基础设施。当CMDB发生变化时,Arbiter会订阅变化,然后生成最新的配置,发送到Region区域。比如Publisher收到变化后,会同步给agent去问,agent会问Arbiter:我该去哪个Publisher?报告数据?然后Arbiter会告诉它它所属的Region和Publisher列表。代理将尝试连接,如果成功,它将连接到网络。它会与Publisher保持长链接,并将自己产生的所有数据交给Publisher中转。我们会在Publisher去center的时候做网络优化,比agent直接去center快很多。3、核心功能1)监控对象设计下面给大家介绍一下我们监控对象的设计,这也是我们的核心功能之一。我们将监控对象抽象为Entity,用EntityType描述它属于什么类型,用Tag描述它的属性。同时,tag也会有一个类似于交叉表的作用,将实体链接在一起。比如机器是一类实体,进程是一类实体,具体的机器名比如hostname01就是机器的一个Entity,运行的代理进程就是进程的一个实体,最后我们可以通过Entity或Metric标签过滤到我们期望的TimeSeries(时间序列数据)。目前,我们拥有约500+个EntityType和1500万个Entity实体模型,覆盖约15亿个时序指标。2)自定义插件监控(python)刚刚提到有一个测试是我们自定义的插件,下面是它的工作流程。①首先用户在前端界面创建插件,我们会自动创建一个gitlab仓库;②然后用户在这个仓库中编写插件代码,提交代码后,会触发pip包的构建;③监控调度中心会生成agent需要的配置插件,然后发送给Agent;④Agent获取到插件信息后,从pip源中拉取pip包并安装运行。这里也看看我们插件的代码量。举个例子,我们这里其实定义了一个基类,用户只需要实现sample方法即可。3)数据总线插件安装后,监控数据如何流动?这是由我们的数据总线控制的。各个报表终端的数据聚合到Kafka后,我们会有一个模块对数据进行清洗和预处理,然后流到下一个Kafka进行存储,告警或者其他订阅系统。同时,我们还有一个预聚合模块,用于对用户关心的数据进行预聚合,可以减少数据量,加快数据查询速度。可以从我们的UI配置预聚合规则。4)数据存储下面介绍我们的数据存储,具有冷热分离、过期删除、HDFS永久存储等特点。冷热分离:数据总线会流向Kafka,数据写入模块负责写入我们的热库。我们使用Redis来存储热数据,每个实体的数据只存储6个小时,然后通过冷数据写入模块每隔半小时将Redis中的数据写入到MongoDB的冷存储中。逾期删除:我们的冷库分为4个粒度:1分钟、5分钟、30分钟、1天。当用户查询不同时间段时,我们会根据时间段选择不同粒度的数据库查询。每个粒度的存储周期不同。比如1分钟只保存7天,5分钟保存30天。数据过期后会自动删除。HDFS归档存储:每天通过归档写入模块将冷库中的时序数据存储在廉价的HDFS中,用于AI、异常检测等数据分析业务场景。当用户发起查询时,我们会根据时序数据库的UUID拉取时序数据,然后根据UUID查询对应的时序数据,合并后将冷热数据返回给用户。4.应用场景接下来,我将展示一些应用场景。主要有4个应用场景,分别是机器视图、进程视图、容器视图和自定义dashboard。1)machineview主要负责一些基础的监控机器。我们关注的基础指标包括CPU、内存、IO等,我们会和CMDB、分组、服务、机器三元组做一些联动。一台机器可以绑定不同的服务,然后绑定成一个组,我们可以在里面做不同的树展示。当点击具体的机器时,我们会展开这台机器的面板,可以看到详细的时间序列数据指标,也可以选择聚合方式。auto是时间粒度。粒度展示给用户,面板左侧也可以查看不同类型的数据。2)进程视图这里是我们的进程视图。我们可以将实体类型标签显示为目录级别。比如我有3个进程,都属于一个进程组。我可以在上面看到Redis的最大CPU使用率。速率、最大RSS内存使用量和其他信息。点击每个具体层级,可以显示每个进程的具体指标详情,然后点击刚才机器视图一样的面板,会出现更详细的指标。3)Dashboard下面介绍一下我们自定义的dashboard,用户可以在里面配置实体类型。仪表盘可以填写查询指标和过滤条件Tag。它支持灵活的括号逻辑表达式,例如(a|b)&c。同时可以根据标签进行分组聚合,还可以指定返回的时间间隔。默认情况下,它会根据查询范围计算一个合适的区间。配置好之后,我们就可以按照不同的类型来展示我们的数据了。比如这是一个大盘,会显示我们整个项目中运行了哪些服务,以及基本服务指标的使用情况。您还可以点击机器详细信息或其他一些业务。监控之类的。5、问题与挑战这套监控系统已经运行了好几年了,貌似没有什么问题,但是我们知道技术的发展日新月异,比如从以前的单体架构到分布式架构,而现在的servicemesh我们传统的监控也很难满足用户的需求。整个监控系统的设计都是基于分钟的粒度。至少只能存储1分钟的监控数据,不能满足一些敏感业务的监控场景。比如数据库的OP监控在1分钟内会发生很多次,导致漏峰漏谷。导致DBA处理不及时,影响业务。越来越多的云原生场景的监控粒度在秒级,业务期望也能支持秒级监控。这套TSDB基本都是基于python写的。在海量数据处理方面,python显得有些力不从心。虽然我们用golang重构了大部分模块,但是有些核心模块因为复杂没有重构。2、结合开源指标设计秒级监控我们如何支持秒级监控?其实我们也做了一些研究:Thanos目前内部使用OpenTSDB做存储,但是不支持定时查询,第三方存储和集群管理需要很大的人力物力成本。原来的Prometheus是单机存储,无法支持集群的肆意扩张,也无法满足需求。EyesTSDB改造支持二级采集。需要在Agent端支持秒级采集,然后在存储端进行粒度存储。基本上属于推翻重建,好处不明显。最终我们选择了一款支持集群部署的Prometheus远程存储,既能满足秒级,又能支持云原生场景——VictoriaMetrics。VictoriaMetrics是一款开源时序数据库,具有以下特点:开源时序数据库是快速、高效、可扩展、高性能的监控系统。多种协议写入,也支持OpenTSDB的HTTP写入协议。最重要的一点是它支持多租户,因为目前我们的EyesTSDB也是多租户的,不同的产品是通过租户来连接的。1.目录结构首先介绍一下VictoriaMetrics的目录结构,数据和索引分开。data是它的数据目录,indexdb是它的索引目录。数据目录分大目录和小目录,为什么要分大目录和小目录呢?这主要是从占用的磁盘空间上考虑的。时序数据往往读取最近写入的数据,很少读取历史数据。而且时序数据的数据量比较大,通常会采用压缩算法进行压缩,所以历史数据放在big目录下,会用比较高的压缩算法进行压缩,而small会用a压缩压缩级别相对较低的Data,small会定期合并到big中。索引使用存储期保存。有两个主要的。一是电流存储期。比如我配置了一个月的存储周期,一个月的数据就会存储在这里,然后就是下一个存储周期的数据。索引支持保存最小时间和最大时间,方便一些二分查找,可以快速定位到具体的数据位置。2.数据结构先说一下它大概的数据结构:AccountID和ProjectID是它的租户信息;MetricGroupID为其指标组ID;JobID和InstanceID是标签指示器。例如,JobID是第一个标签的哈希值。InstanceID是第二个标签的hash值;最后一个MetricID是它的指标ID,它是一个自动递增的时间戳ID。3.整体架构右边的图就是它的整体架构。我们可以从中间看到它。中间主要是存储,上下分别是查询和写入。它的查询是vmselect,它的辅助是vminsert。两者都是无状态的,我可以随时扩充节点。接下来是写协议,支持Prometheus写或者InfluxDB线路协议写。它里面的存储其实是有状态的,但是也支持我们横向扩展,比如存储块代码,我们可以增加节点支持数据工厂的写。目前它无缝支持Grafana和PrometheusAPI查询。以上是VictoriaMetrics的结构,我们如何将其转化为我们可以使用的结构呢?4.新架构设计这是我们目前的一套新架构。中间的红框就是我们刚才提到的VictoriaMetrics的基本架构。我们从上面的entry可以看到,agent,比如我有一个exporter,它会写入transfer,这个支持RemoteWrite协议,然后会流到一个kafka,下面有一个proxy模块,负责数据预处理和Clean,然后送到我们的告警系统做一些告警匹配和规则匹配。下面是它的存储,左边是数据存储,右边是索引存储。我们在这方面做了改进。以上主要是一些API和UI模块。在底部,我们可以看到右侧有一个冷数据存储节点。该块将写入冷数据。在数据集群中,我们添加了一个Shuffle模块,负责解析vm文件。将同一个指标的所有时序数据发送到冷数据存储,然后downsample下采样模块会降低粒度,存储到冷数据集群中。有多组数据集群,一组通用的索引集群,从而降低存储成本。5、如何与内部CMDB链接?然后我们既支持秒级又支持云原生,最后怎么继承我们的CMDB联动?刚刚提到我们的Entity和Metric都会有tags,这些tags包括我们内部的CMDB属性,比如右图。我们将这些标签单独存储,它们与Metric标签是分开的。它将索引指标和TSID,最后是标签和MetricID。它将为每个标签做一次索引。TSDB分为两个模块。第一个是元信息。我们可以看到最上面的例子,它是一个指标,后面是它的时间戳和值。元信息将包括指标名称和标签。下面是它的时间序列数据,时间戳和值都存储在这里,中间通过一个ID关联起来。大多数TSDB不支持单个标签键和多个标签值,例如gid=1,gid=2。如何给标签添加CMDB标签?我们将其存储在一个单独的副本中。标签是用不同的索引存储的,因为VictoriaMetrics本身就有一个索引命名空间,不同的命名空间是不一样的。然后我们添加了命名空间来传输数据。同时也增加了对这些标签进行增删改查的接口,以满足我们CMDB标签的编写和查询,进而提供给不同的数据库进行查询。6.新特性1)vmshufflevmshuffle是我们自己做的一个函数,因为一个指标可能存储在不同的节点上,我们把一个指标的数据聚合到一个存储节点上,然后在集群上定期存储在一个冷数据中。目前支持的场景:短时间高精度数据长时间之前查看历史数据统计分析使用历史数据进行模型训练我们如何在节点上存储一个指标?其实我们就是把它提供的一些原始数据,比如MetricGroupID、ProjectID、AccountID、MetricName,统一组织起来,hash到不同的vmstorage中。同一个metric下的数据会存储在同一个vmstorage中,然后在metric之后,Data会出现在文件中连续的位置。2)vmdownsample此外,我们还做了一个下采样函数。我们之前的一套EyesTSDB有不同强度的下采样,那我们怎么支持这套呢?我们有一个备份集群。刚才说的vmshuffle把数据存储在冷数据集群中,然后每个节点会运行一个数据聚合模块,然后引导它,因为一个指标只会存储在一个节点上,指标会被聚合。拉出块数据,比如一天一次,拉出前一天的数据进行聚合,然后按照不同的强度,比如5分钟,30分钟,一天,分别存储在不同的集群中,可以满足要求从之前的EyesTSDB到这套转换是完全兼容和支持的。7.问题与挑战1)如何在查询端通过tags和labels过滤时间序列数据?刚才我们提到我们开辟了一个标签命名空间来存储。其实它类似于原来存储的label命名空间,所以可以复用已有的支持的功能,比如label的promql查询语句,filter,aggregation等功能。2)如何满足现有的业务查询场景?它已经支持promql的查询语法,所以我们可以通过灵活的查询语句将它匹配到我们的dashboard。比如我们之前提供的avg、min、sum等聚合方式,可以通过avg(avg_over_time)支持不同曲线、不同时间间隔的聚合值。比如avg_over_time作为5分钟内的平均值,然后avg使用这5分钟内的平均曲线,然后取平均值,满足上面提到的dashboard上的查询。三、未来展望1、数据质量目前我们存储了大量的数据,但有些数据似乎质量不高。比如用户上报各种数据,但他们真正关注的可能只有20%到30%,我们以后会提高数据质量,提高我们存储的性能。2.业务多样化的需求我们内部有多套集群,不同的集群有不同的需求。比如一组集群需要做一些去重,有些集群不需要关联CMDB,甚至我们以后会做一些SaaSsometypeof。3.代理和调度中心性能这是EyesTSDB集的性能优化。老一套是用Python写的,中间用GoLand重构。目前还在重构中,还没有完全重构。4.反馈给开源最后,我们会开源。我们开发的一些附加功能稳定后,我们也会考虑反馈给开源社区,与大家共同发展进步。我们还有很多想法,比如自动化的集群构建,基于SaaS的集群管理,后面会跟大家分享。Q&AQ1:这个数据库采用了哪种冷热数据分离方案?有数据丢失的风险吗?A1:在这个新的集合中,我们有一个热数据库,冷数据从备份集群同步。在数据丢失风险方面,我们主库目前是有储备的,我们各种降采样粒度的冷库也有储备。Q2:如何提高CMDB数据的准确性?有什么计划吗?A2:在这方面,我们的EyesTSDB集合其实是有一些延迟的,比如这么大的CMDB数据是怎么流入数据然后存储的,或者alarm部分其实是有延迟的。然后我们配合CMDB系统,实现一些实时同步。我们新的一套CMDB有一些拓扑结构。它使用一个图数据库来存储CMDB数据,然后当中间的一个节点发生变化时,它会触发一个变化消息。,收到消息后,将更新与该节点相关的信息。这涉及到一些批量合并和时间策略。这一套也是我们目前在做的,也基本落地了。以后有机会再分享给大家。它是如何完成的。