超大规模跨域集群统一监控实践
本文作者为中国移动云能力中心大数据团队软件开发工程师景泓斐,本文针对超大规模跨域集群(超过 5k 节点)的监控平台出现较多的性能问题,进行逐步分析和性能压测,最后给出优化方案和实践效果,供大家参考。
背景
通常大数据平台需要上线统一监控平台以满足日常 Hadoop 集群运维的需求,若线上节点较多(5000+节点),当纳管所有节点后,监控平台会出现诸多性能问题,需要探究监控平台的瓶颈在哪里。
监控平台
架构监控平台的架构主要由 Prometheus,VictoriaMetrics,Grafana,exporter 采集,自研 coordinator 等组件构成。
Prometheus 作为一套完整的开源监控方案,因为其诸多强大的特性以及生态的开放性,俨然已经成为了云原生监控领域的事实标准并在全球范围内得到了广泛的部署应用。Prometheus 具有提供多维度数据模型和灵活的查询方式,但其也有一定的局限性:
1.扩展性较差。
2.自带存储方式受限于本地磁盘容量。
3.随着数据采集量的增加,单台 Prometheus 性能也会到达瓶颈(一般是内存先达到瓶颈)。
Prometheus 对于规模较大的集群来说,单点性能具有瓶颈,因此 Prometheus 提供了 Remotie Write 功能,将采集到的数据直接写入远端存储中,目前已支持 InflunxDB,VictoriaMetrics,Kafka 等多种存储。
VictoriaMetrics 是一个支持水平扩展的时序数据库,可以作为 Prometheus 的远端存储,并且实现了 PromSQL,可以直接通过 VictoriaMetrics 查询时序数据,避开 Prometheus 查询时的单点瓶颈。VictoriaMetrics 集群版包括三个组件 vminsert,vmselect,vmstorage。
1.vmstorage : 用于存储数据。
2.vmselect : 从 vmstorage 节点获取并聚合所需数据,返回给查询数据的客户端(如 Grafana)。3.vminsert : 通过 remote write API 接收来自 Prometheus 的数据并将其分布在可用的 vmstorage 节点上。
4.VictoriaMetrics 扩展非常灵活,在部署时可以按照需求部署不同的副本,以应对各类场景:
•若数据量比较大,部署较多的 vmstorage 副本;
•若查询请求比较多,部署较多的 vmselect 副本;
•若插入请求比较多,部署较多的 vminsert 副本;
以 Prometheus 和 VictoriaMetrics 为主体,构建了以下监控平台架构:
1.在 Hadoop 集群各节点安装 node_exporter,jmx_exporter 等监控采集工具,并添加相关配置;
2.部署自研工具 coordinator,获取 Hadoop 集群节点和监控信息,将其存入 Consul 中;
3.Prometheus 配置 consul_sd,从 Consul 中获取需要采集的 metrics 地址;
4.Prometheus Remote Write 中配置远端地址为 vminsert 地址,数据写入 vminsert;
5.Vminsert 根据 labels 计算一致性 hash,写入多个 vmstorage 中(可配置多副本),vmstorage 可水平扩展;
6.Grafana 数据源配置 vmselect 地址,vmselect 从 vmstorage 获取并聚合所需数据。
问题分析
在实际部署过程中,由于采集的数据量很大,我们部署了 4 组 prometheus,以及 6 组 vmstorage,但还是遇到了一些性能问题。部署采集一段时间后,Prometheus 数据开始产生延迟,并且内存开始逐渐升高,最后导致占用了物理机大量内存触发系统 oom kill。
原以为是数据量太大导致单个 prometheus 达到内存瓶颈,但减少 exporter 之后重启 prometheus,内存还是会溢出。查看 prometheus 日志,发现在写入 vminsert 时偶发写入超时。再定位到 vminsert 日志发现,写入 vmstorage 时发生超时。最后定位到超时的 vmstorage 节点,发现 vmstorage 日志中有大量的 merge 操作,并且其使用的磁盘使用率长期处于 100%。
从图中可以看到,sde 盘写入的 iops 比较高,但写入量却并不是很大,说明写入操作比较频繁,而且注意到 await(平均每次设备 I/O 操作的等待时间)和 svctm(平均每次设备 I/O 操作的服务时间 )相差非常大,如果 await 远大于 svctm,说明 I/O 队列太长,IO 响应太慢,这就需要排查 prometheus 的 remote write 是否出现问题。首先看下 RemoteWrite 的处理过程,prometheus 配置了 remote write 的目标地址后,它会从 WAL 读取数据,然后把采样数据写入各分片的内存队列,最后发起向远程目标地址的请求。
当开启 remote write 功能后,prometheus 官网说明内存的消耗是会上涨约 25%,主要是分区中缓存的数据和缓存 series ID 到标签值的映射,实际内存消耗情况也依赖具体参数设置,下面列出的是所有 remote write 参数配置。
其中比较关键的参数为:capcity,max_sample_per_send,max_shards。
•capcity: 用来指定每个分片队列可容纳的样本数上限。当队列达到上限后,将停止从 WAL 读数据。•max_shards: 用来指定最大的分片数。当队列落后远程写模块时,prometheus 将增加分片数直到最大值,来增加吞吐量。
•max_sample_per_send: 用来指定每次批量发送给远程写目标地址的最大 samples 数。
默认的设置适用于大部分场景,但由于线上采集量较大,默认 max_sample_per_send 只有 100,这就导致每次发送的数据量不大,增加了 RPC,以及落到 vmstorage 的磁盘 IOPS。
由于数据量大,且远端存储响应超时等原因,Prometheus 检测到在有数据 pending 的情况下,会根据 min_shards 和 max_shards 的区间范围自动调整分区数,当分区数增加,驻留在内存中的数据量也会上升,导致 prometheus 内存也会不断的升高。同时之前传输失败的数据也积压在内存中,消耗大量内存资源。
如下图,在开启 debug 日志的情况下,也能看到 prometheus 当前的输入输出流量,以及 pending 的数据量,在检测到 samplePending 比较高的情况下,prometheus 会增加分区数,来提高吞吐量,同时也会提高内存使用量。
性能测试
随着后续大数据平台的扩容,规模会达到上万节点,为了保证统一监控平台的稳定,有必要进行一次性能压测,为后续监控集群扩容提供参数依据。
单个样本大小和样本总量对于测试结果有较大的影响。为了模拟真实环境的情况,在压测前,进行了几组测试,发现了一些问题。在指标为纯随机值时,单个样本大小为 8.6bytes,在指标为固定值时,单个样本大小又变成 0.6bytes。单个样本大小在样本总量非常大的情况下,多出 1 字节几乎就要多消耗 10GB 的内存,因此在之前几组测试中都因为内存过大导致 prometheus 提前终止。
通过查阅资料发现原因在于 Prometheus 对样本的压缩算法。时序数据库的最大特点是,每个 series 都是由若干二元组组成的,类似(T1, V1) (T2, V2) (T3, V4) ... (Tn, Vn),T 表示时间戳(int64),V 表示数值(float64),各占 8 个字节,每个 sample 点(二元组)为 16 个字节。Prometheus 采用了 delta-of-delta 和 XOR 压缩算法,将 16 字节的样本点压缩到 1-3 字节,虽然压缩率很高,但算法是利用监控数据的特定特点实现的,在其他场合未必生效。
delta-of-delta 算法用于压缩时间戳,检查间隔往往是固定的(通常是 1min),因此 Delta2–Delta1 或者 Delta3–Delta2 将会是非常小的值,然后根据差值的范围,采用不等长的编码就可以达到压缩的目的。
XOR 算法针对值进行压缩,由于相邻时间点样本值的变化幅度相对较小,举个例子,下面是 117.0 和 118.0 两个数值对其异或后,不同的 bits 只有 2 位,头部和尾部都有大量连续的位是‘0’,对其进行压缩存储就能节约大量空间。
回过来看一下之前纯随机为 8.6 字节,说明在随机情况下样本值是几乎没有压缩的,而在固定值下每个样本 0.6 字节基本上全部被压缩了。所以在压测时我们不能使用纯随机或者固定值,都会影响到我们性能测试的真实性,在模拟时尽可能把随机范围控制在一定区间,最后稳定在 2 字节左右。
压测过程
压测环境:1 台 32 核,256GB 内存物理机
部署组件:prometheus1,vmstorage2,vmselect1,vminsert1
通过程序启动 3000 个线程,模拟 3000 个 exporter 进程,指标内容为一定范围内的随机数,指标数量支持可配置,采集间隔为 60 秒。通过增加指标数量来提高 Prometheus 采集的每秒样本数,在达到 40K/s,80K/s,160K/s,320K/s,640K/s 时分别测试对应节点的 CPU,内存,磁盘的使用情况,测试结果如下:
根据采集数据量进行压测后,目前一台物理机部署 1 个 prometheus 和 2 个 vmstorage 在样本数达到 640K/s 时出现了一定的性能问题,prometheus 内存升高,以及 vmstorage 数据出现部分延迟,机器的 CPU 也达到了 85%以上。真实环境的物理机配置相对高一些,但也不会相差太多,且需要留有一定的资源维持服务器稳定,所以基本上单个 prometheus 不建议采集超过 640K 的样本数了。
此次压测针对线上问题进行了优化,包括 prometheus 远端写的参数调整降低磁盘 IOPS,以及在单节点部署两个 Vmstorage 实例。因为 vmstorage 存储不支持配置多个路径,导致无法利用多个磁盘性能,所以通过指定不同端口,在单节点上启动多个 vmstorage 方式来缓解磁盘压力。
结论
压测环境下,640000/s 已经将资源基本耗尽,根据测试估性能作为后续部署参考:
•内存:Prometheus 需要 110-120GB,单个 Vmstorage 需要 40-50GB;
•IO:磁盘偶有延迟但基本可以维持此数据量;
•CPU:利用率在 85%以上。
优化方案
根据之前的问题分析及性能压测后,我们对 Prometheus 和 VictoriaMetrics 的性能瓶颈有了大概的预估,结合我们预估的样本总量,在已有的 6 台监控节点上进行了部署优化,方案如下:
Vmstorage 扩容
按照测试时的部署方案,单台节点部署 1 个 prometheus 和 2 个 vmstorage,指定不同的端口和存储磁盘。对比原来部署规划,vm 扩容了 6 个,prometheus 扩容了 2 个。
数据盘做 Raid10
12 块磁盘,做两组 raid10,分别给两个 vmstorage 使用,扩大了存储总容量,提高磁盘读写性能。
配置优化
调整 prometheus.yml 中的 remote write 参数。
•max_samples_per_send: 1000,默认值(100)适用于大多数系统,可适当调大;根据所使用的后端,适当调整每次发送的最大样本数。因为许多系统,通过每批发送更多样本而不会显著增加延迟。而有些后端,如果每个请求中发送大量样本(simples),就会出现问题。
•capacity: 2000,2-10 倍 max_samples_per_send;
•max_shards: 30,默认(1000);不建议太多,会导致 OOM;除非远程存储写入非常缓慢,否则不建议将 max_shards 的值调整为比默认值大。相反,调整为小于默认值会减少内存占用;
•min_shards: 10,默认(1),可适当调大;如果远端写入落后,Prometheus 会自动扩展分片的数量;增加最小分片将允许 Prometheus 在计算所需的分片数时避免在开始时落后。
经过测试,此配置能够满足指标传输,在远端存储无性能问题情况下,不会造成数据挤压。同时能最大限度减少内存的消耗,保证 prometheus 正常运行。
Prometheus 版本升级
目前线上使用的 V2.15 版本 2019 年发布的,较为滞后,VictoriaMetrics 官网指出在 V2.12 版本之前的 Remote Write 功能有缺陷,在 V2.15 以后的版本涉及多项 Remote Write 特性的优化和 BUGFIX,因此我们采用较新且稳定的版本 V2.35(经过测试,该版本对内存也有一定优化,内存过高时,会清理一部分内存,避免 oom)。
部署流程优化
在 6 台节点上部署 nodeexporter,将监控系统的节点加入到监控中便于观察性能;
再将集群的 exporter 分批次平均分配加入 prometheus 中,观察每秒样本数量稳定后,再添加下一个集群(每个 prometheus 以 600K 样本数为阈值)
优化之后,由于 vmstorage 规模翻倍,且使用的每块盘的性能和容量提升了 3 倍,整个 IO 性能提高了 6 倍,实际上线后也证明这个系统已经不存在磁盘上的瓶颈,而目前的瓶颈在于更多的数据采集导致的 prometheus 内存升高。根据测试结果,prometheus 在采集间隔 60s 时达到 640K 每秒的样本数时,使用的内存达到 120+50*2=220GB,已经处于一个较高的使用率。线上实际在达到 750K 左右时内存达到了瓶颈,所以为了维持稳定,不再提高采集率。
目前,5000 节点使用了大约一半的资源,整个监控平台预估能存储 10000 节点的监控信息。不过由于不同组件采集的指标数不同,比如 kafka 和 regionserver 取决于实际的分区数和 region 数而定,通常会比其他指标多很多。所以实际添加监控时,还需要具体问题具体分析,以实际的集群规划来估算。
最后看下实际优化后的效果:
上面图 1 展示的是 prometheus 样本的每秒样本数和样本平均大小,通过观察每秒样本数达到 600K 之后便停止加入更多 exporter,同时可以看到真实环境下,平均样本大小仅为 1-2 字节左右。图 2 展示的是达到 600K 采集率的 prometheus 节点占用资源情况,可以看到不管是内存还是 CPU 的消耗都和性能压测时的结果相差不大,而这也达到了一个比较稳定的状态,样本过多会占用太多资源导致性能问题,过少则不能充分利用物理机资源。
参考资料:
•Prometheus 远程写:https://prometheus.io/docs/practices/remote_write/
•Prometheus Github:https://github.com/prometheus/prometheus/releases
•VM 官网文档:https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html
•XOR 压缩算法:https://vearne.cc/archives/38939
评论