Elasticsearch监控——磁盘利用率

Elasticsearch 监控指标

由于最近在做 ES 集群监控相关工作,所以首要的便是收集需要监控的指标。

Elasticsearch的监控可以分为 集群节点 两个维度。

集群维度监控指标获取

Elasticsearch 提供了原生的 cluster API 可以进行集群状态的获取,具体如下:

1
2
3
GET _cluster/health
# curl实现
curl -XGET 'host:9200/_cluster/health?pretty=true'

该命令获取结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
{
"cluster_name": "elasticsearch",
"status": "green",
"timed_out": false,
"number_of_nodes": 1,
"number_of_data_nodes": 1,
"active_primary_shards": 2,
"active_shards": 2,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0
}

由上面返回结果可以看到,该API主要返回 es 的整体健康信息,包括集群健康度、分片状态等。

_cluster/health API 外,ES 还提供了一个获取集群全量统计信息的 API:_cluster/stats。
该接口统计信息包含集群的分片数、文档数、段信息、插件信息以及JVM状态、系统级别的监控等等。

节点维度监控指标

Elasticsearch 提供了 _node/stats API 用来进行节点监控信息的获取,该API可以通过参数组合来获取不同的指标信息,使用如下:

1
2
3
GET _node/stats
# curl 实现
curl -XGET 'host:9200/_nodes/_all/stats/fs,jvm,os,indices?pretty=true'

通过该命令,可以获取 ES 集群节点的 cpu 利用率、jvm 情况等核心监控指标。

磁盘IO使用率监控

通过 ES 原生提供的API,其实已经可以满足对 cpu、jvm 等重要监控项的监控支持,但是在实际应用中,data 节点的一个瓶颈来源于磁盘的io。换而言之,磁盘io利用率也是一个重点的监控指标。

通过 ES 的 node API 获取的结果中,针对节点的 IO 信息的描述,具体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
"io_stats" : {
"devices" : [
{
"device_name" : "sda",
"operations" : 92636401,
"read_operations" : 573880,
"write_operations" : 92062521,
"read_kilobytes" : 29470340,
"write_kilobytes" : 4085359108
}
],
"total" : {
"operations" : 92636401,
"read_operations" : 573880,
"write_operations" : 92062521,
"read_kilobytes" : 29470340,
"write_kilobytes" : 4085359108
}
}

以上可以看出,针对于磁盘IO信息,仅给出了启动到现在的读/写操作数、读/写数据量的数据,通过这些数据并不能算出单位时间内IO所用的时间占比,故需要考虑其他思路进行该监控指标的获取。

考虑使用iostat

iostat 作为一个强大的 Linux 监控工具,其提供磁盘级的I/O状态。此处使用的命令如下:

1
iostat -xd 1

通过该命令,可以查看实时的磁盘io信息。输出结果中,有一个名为 %util 的字段,该字段表示该间隔时间内,有多少的时间被用于I/O操作,当该字段接近100%,说明设备产生饱和,也就是我们所说的IO瓶颈。

得出结论,iostat 中的 %util 指标即为我们想要的监控数据,但是我们的目的是远端获取该值,远程直接执行iostat命令肯定是个不太好的方式。在此基础上,调查到 iostat 命令是基于系统级别的 /proc/diskstats 文件来计算的,故我们可以直接从 /proc/diskstats 文件中读取所需要的磁盘指标元数据,然后自行进行计算。

实现 iostat %util 指标计算

通过 cat /proc/diskstats 命令可以获取文件信息,每一行代表一个设备的实时信息数据,举例如下:

1
202 0 xvda 88773 1108 2010114 551529 31249889 47896636 633188176 338606000 0 56198497 339137808

其中每列的简介如下:

  • 第一列:设备号
  • 第二列:次设备号
  • 第三列:设备名称
  • 第四列:成功完成读的总次数
  • 第五列:合并读次数
  • 第六列:读扇区的次数
  • 第七列:读花费时间(ms)
  • 第八列:成功完成写的总次数
  • 第九列:合并写次数
  • 第十列:写扇区的次数
  • 第十一列:写花费时间(ms)
  • 第十二列:正在处理的输入/输出请求数
  • 第十三列:输入/输出操作花费的时间(ms)
  • 第十四列:输入/输出操作花费的加权时间(ms)

由此我们可以看出,我们所需要的便是第十三列的值。针对一个时间间隔,取开始和结束两次的值,即可计算该单位时间内磁盘 IO 利用率。我所使用的命令如下:

由于机器可能挂载多个设备,为了使得命令通用,都取最大的一行默认为 elasticsearch data 挂载到的设备,具体用到命令如下:

1
cat /proc/diskstats | awk 'BEGIN {max = 0} {if ($4+0 > max+0) {max=$4 ;content=$0} } END {print content}'| awk '{print $13}'

在该命令中,以成功完成读的总次数为基础进行排序,+0 是为了保证以数字而不是字符串进行排序,以获取 data 所存储的设备,然后取出我们所需要的输入/输出操作花费的时间。

有了这个数据,便可以在程序中进行磁盘IO利用率指标的计算,并针对数据进行持久化记录。

另:如果设备较少或者监控的集群较少,也可以一次取出一定间隔的两次数据,命令如下:

1
cat /proc/diskstats | awk 'BEGIN {max = 0} {if ($4+0 > max+0) {max=$4 ;content=$0} } END {print content}'| awk '{print $13}'; sleep 10; cat /proc/diskstats | awk 'BEGIN {max = 0} {if ($4+0 > max+0) {max=$4 ;content=$0} } END {print content}'| awk '{print $13}'

取到两次数据作差再除以时间间隔(ms),即可完成计算。公式如下:

$$ioRate = \frac{end-start}{period} * 100\% $$

其中,end和start分别为时间间隔结束和开始时通过命令取到的 输入/输出操作花费的时间毫秒数,period为时间间隔,单位为毫秒

小结

Elasticsearch 官方提供的 API 已经能满足大多数监控指标的采集需求,此文作为补充,补充了一下针对于磁盘IO利用率的采集方式。