运维监控系统实战笔记(10)--day 11

内容来自极客时间《运维监控系统实战笔记》--   监控概论(下):监控数据的采集方式及原理

监控数据采集方法的多样,比如读取 /proc 目录、执行系统调用、执行命令行工具、远程黑盒探测、远程拉取特定协议的数据、连到目标上去执行指令获取输出、代码埋点、日志分析提取等各种各样的方法。按照使用频率从高到低依次看一下,先来看读取 /proc 目录的方式。

读取 /proc 目录

/proc 是一个位于内存中的伪文件系统,该目录下保存的不是真正的文件和目录,而是一些“运行时”信息,Linux 操作系统层面的很多监控数据,比如内存数据、网卡流量、机器负载等,都是从 /proc 中获取的信息。

内存指标:

    
[root@dev01.nj ~]# cat /proc/meminfo
MemTotal:        7954676 kB
MemFree:          211136 kB
MemAvailable:    2486688 kB
Buffers:          115068 kB
Cached:          2309836 kB
...可以拿到内存总量、剩余量、可用量、Buffer、Cached 等数据,使用率必须经过计算

内存相关的指标都是 Gauge 类型的,网卡相关的数据都是 Counter 类型的数据。


[root@dev01.nj ~]# head -n3 /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
  eth0: 697407964307 2580235035    0    0    0     0          0         0 1969289573661 3137865547    0    0    0     0       0          0

所谓的总量,是指操作系统启动以来的累计值。从监控角度,通常我们不关注这个总量,而是关注最近一分钟或者最近一秒钟的流量是多少,所以在服务端看图的时候,通常要使用 irate 函数做二次计算。

你可能会觉得,OS 层面的监控很简单,不就是读取 /proc 目录下的内容吗?这倒也不尽然,有些数据从 /proc 下面是拿不到的,比如硬盘使用率。我们可以从 /proc/mounts 拿到机器的挂载点列表,但具体每个挂载点的使用率,就需要系统调用了。OS 内的数据采集,除了读取 /proc 目录之外也经常会通过执行命令行工具的方式采集指标,

执行命令行工具

调用一下系统命令,解析输出就可以了。比如我们想获取 9090 端口的监听状态,可以使用 ss 命令 ss -tln|grep 9090,想要拿到各个分区的使用率可以通过 df 命令 df -k。但是这个方式不太通用,性能也不好。

不同的发行版或不同 ss 版本,命令输出内容格式可能不同。性能问题也容易理解,调用命令行工具是需要 fork 一个进程的,相比于进程内的逻辑,效率大打折扣,

读取本地 /proc 目录或执行命令行工具,都是在目标监控机器上进行的操作。有的时候,我们无法在目标机器上部署客户端程序,这时候就需要黑盒探测手段了。

远程黑盒探测

典型的探测手段有三类,ICMP、TCP 和 HTTP。有一个软件叫 Blackbox Exporter,就是专门用来探测的,Categraf、Datadog-Agent 等采集器也都可以做这种探测。

ICMP 协议,我们可以通过 Ping 工具做测试,

 ping -c 3 www.baidu.com

不过有些机器是禁 Ping 的,这时候我们就可以通过 TCP 或 HTTP 来探测。对于 Linux 机器,一般是会开放 sshd 的 22 端口,那我们就可以用类似 telnet 的方式探测机器的 22 端口,如果成功就认为机器存活。

对于 HTTP 协议的探测,除了基本的连通性测试,还可以检查协议内容,比如要求返回的 status code 必须是 200,返回的 response body 必须包含 success 字符串,如果任何一个条件没有满足,从监控的角度就认为是异常的。

有黑盒监控,自然就有白盒监控。黑盒监控是把监控对象当成一个黑盒子,不去了解其内部运行机理,只是通过几种协议做简单探测。白盒监控与之相反,它要收集能够反映监控对象内部运行健康度的指标。但是监控对象的内部指标,从外部其实是无法拿到的,所以白盒监控的指标,需要监控对象自身想办法暴露出来。最典型的暴露方式,就是提供一个 HTTP 接口,在 response body 中返回监控指标的数据

拉取特定协议的数据

有很多组件都通过 HTTP 接口的方式,暴露了自身的监控指标。这里我给你举几个例子,让你有个感性的认识,比如 Elasticsearch 的 /_cluster/health 接口。


[root@dev01.nj ~]# curl  -uelastic:Pass1223 http://10.206.0.7:9200/_cluster/health -s | jq .
{
  "cluster_name": "elasticsearch-cluster",
  "status": "yellow",
  "timed_out": false,
  "number_of_nodes": 3,
  "number_of_data_nodes": 3,
  "active_primary_shards": 430,
  "active_shards": 430,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 430,
  "delayed_unassigned_shards": 0,
  "number_of_pending_tasks": 0,
  "number_of_in_flight_fetch": 0,
  "task_max_waiting_in_queue_millis": 0,
  "active_shards_percent_as_number": 50
}

返回的内容大多是指标数值,转换成监控服务端要求的数据格式,传上去即可。除了 /_cluster/health ,还可以测试一下 /_cluster/stats,也能帮你了解这种获取指标的方式。

还有很多其他组件也是用这种方式来暴露指标的,比如 RabbitMQ,访问 /api/overview 可以拿到 Message 数量、Connection 数量等概要信息。再比如 Kubelet,访问 /stats/summary 可以拿到 Node 和 Pod 等很多概要信息。

不同的接口返回的内容虽然都是指标数据,但是要推给监控服务端,还是要做一次格式转换,比如统一转换为 Prometheus 的文本格式。要是这些组件都直接暴露 Prometheus 的协议数据就好了,使用统一的解析器,就能大大简化监控采集逻辑。

这种拉取监控数据的方式虽然需要做一些数据格式的转换,但并不复杂。因为目标对象会把需要监控的数据直接通过接口暴露出来,监控采集器把数据拉到本地做格式转换即可。更复杂的方式是需要我们连接到目标对象上执行指令,MySQL、Redis、MongoDB 等都是这种方式,下面我们就来一起看一下这种采集方式的工作原理。

连接到目标对象执行命令

目前最常用的数据库就是 MySQL 和 Redis 了,我们就拿这两个组件来举例。先说 MySQL,我们经常需要获取一些连接相关的指标数据,比如当前有多少连接,总共拒绝了多少连接,总共接收过多少连接,登录 MySQL 命令行,使用下面的命令可以获取。

 show global status like '%onn%';

Threads_connected 表示当前有多少连接,Max_used_connections 表示曾经最多有多少连接,Connections 表示总计接收过多少连接。当然,除了连接数相关的指标,通过 show global status 还可以获取很多其他的指标,这些指标用于表示 MySQL 的运行状态,随着实例运行,这些数据会动态变化。

还有另一个命令 show global variables 可以获取一些全局变量信息,比如使用下面的命令可以获取 MySQL 最大连接数。

show global variables like '%onn%';

其中 max_connections 就是最大连接数,这个数值默认是 151。在很多生产环境下,都应该调大,所以我们要把这个指标作为一个告警规则监控起来,如果发现这个数值太小要及时告警。

当然,除了刚才介绍的两个命令,我们还可以执行其他命令获取其他数据库指标,比如 show slave status 可以获取 Slave 节点的信息。总的来看,MySQL 监控的原理就是,连上 MySQL 后执行各种 SQL 语句,解析结果,转换为监控时序数据。

Redis 也是类似的,比如我们通过 redis-cli 登录到命令行,执行 info memory 命令,就可以看到很多内存相关的指标。


127.0.0.1:6379> info memory
# Memory
used_memory:1345568
used_memory_human:1.28M
used_memory_rss:3653632
used_memory_rss_human:3.48M
used_memory_peak:1504640
used_memory_peak_human:1.43M
used_memory_peak_perc:89.43%
used_memory_overhead:1103288
used_memory_startup:1095648
used_memory_dataset:242280
used_memory_dataset_perc:96.94%
...

有些业务数据可能是存在 Redis 里的,所以监控 Redis 不只是获取 Redis 自身的指标,还应该支持自定义命令,获取一些业务数据,比如下面的命令,用于获取订单总量。


get /orders/total

这个例子是假设业务程序会自动更新 Redis Key:/orders/total,用这个 Key 来存放订单总量。

我们就把常见的 OS 和中间件的监控讲完了,按照上一讲的监控分层架构图,接下来就是应用监控和业务监控,应用监控和业务监控有两种典型的采集手段,一个是埋点,一个是日志解析。

代码埋点

所谓的代码埋点方式,是指应用程序内嵌一些监控相关的 SDK,在请求的关键链路上调用 SDK 的方法,告诉 SDK 当前是个什么请求、耗时多少、是否成功之类的,SDK 汇总这些数据并二次计算,最终推给监控服务端。

比如一个用 Go 写的 Web 程序,提供了 10 个 HTTP 接口,我们想获取这 10 个接口的成功率和延迟数据,那就要写程序实现这些逻辑,包括数据采集、统计、转发给服务端等。这些监控相关的逻辑是典型的横向需求,这个 Web 程序有需求,其他的程序也有这个需求,所以就把这部分代码抽象成一个统一的 Lib,即上面提到的这个 SDK,每个需要监控逻辑的程序都可以复用这个 SDK,提升效率。

但是每个项目都要调用这个 SDK 的方法仍然显得很冗余,是否有更简单的办法呢?有!每个公司可以建立统一的框架开发团队,开发统一的 HTTP 框架,在框架里使用 AOP 的编程方式,内置采集这些监控数据。这样一来,只要某个团队用了这个统一的 HTTP 框架,就自动具备了监控埋点能力。同理,我们也可以构建统一的 RPC 调用框架,统一的 MySQL 调用框架,这样就逐步构建了统一且完备的应用监控数据收集体系。

这种方式需要内嵌 SDK,对代码有侵入性,是否有更简单的办法呢?有!对于 Java 这种字节码语言,我们可以使用 JavaAgent 技术,动态修改字节码,自动获取监控数据,到 Google 上通过关键词“javaagent monitoring”可以找到很多资料。

当然,现在也开始流行 eBPF 技术,有些厂商在尝试,

对于自研的程序,代码埋点是没问题的,但是很多程序可能是外采的,我们没法修改它的源代码,这时候就要使用日志解析的方式了。一般程序都会打印日志,我们可以写日志解析程序,从日志中提取一些关键信息,比如从业务日志中很容易拿到 Exception 关键字出现的次数,从接入层日志中很容易就能拿到某个接口的访问次数。这部分内容我们会在第 20 讲详细演示,这里就不过多介绍了。

小结

总的来看,OS 层面的监控需要把 Agent 部署到机器里,读取一些本地的特殊文件,执行一些命令来获取监控数据;数据库、中间件的监控,大都是远程采集,只是协议各异,需要做一定的适配;应用监控的话,典型的采集方式有两种,一个是代码埋点,一个是日志解析。最后我把这一讲的内容总结成了一张脑图

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值