我们要始终假设自己的系统处在高危状态.
监控的概念
为什么要做监控? 我们的系统上线后, 可能随时都会遇到各种各样的问题, 因此我们需要监控各种指标, 从而能够及时发现问题. 那么这些指标有哪些呢? 例如CPU, 他的负荷量是否长期居高(90+)不下, 中断次数是否过多? 磁盘IO?内存使用量? 是否一直在swap? 软件层面上, 例如Nginx是否正常运行? 最重要的, 业务层面上, 并发量, 响应时间, 每秒钟的事务量等等, 这些都是我们需要进行考量.
所以监控的第一步, 我们需要得到这些数据, 也就是采样. 但是这些数据, 获取单一时间点的值的意义不大, 我们需要将获取的数据进行存储, 持续采样, 得到历史数据和趋势数据. 得到了这些数据之后, 我们需要进行展示. 当数据出现异常, 我们首要做的是就是报警. 由此, 我们就得到了一个完整的监控系统所必须的几个功能: 采样, 存储, 展示, 报警.
监控管理是贯穿在整个运维过程中的, 对于不同类型的系统, 主机, 我们对应的监控系统也是不一样的.
采样
对于上面的几个过程, 采样就是周期性的获取某个关注指标相关的数据. 现在回忆一下我们之前看过的Ansible和Puppet, 我们可以使用ssh通道, 也可以在目标主机上安装一个agent. 这里甚至也可以是一个传感器. 当然啦, 这里也不一定非要是主机, 我们的被监控对象也可以使交换机路由器这些网络设备, 还有UPS也可以被监控.
因此一般, 我们会在网络中存放一个NMS, 也就是监控机. 通过agent或者是通道来发送命令. 再使用通道的情况下, 很多数据的获取, 我们需要管理员权限才可以获取, 这种时候我们如果目标主机的sudo权限设定的不当的话, 监控可能会失败, 如果使用管理员账号, 可能又会有信息泄露的风险, 不安全. 而如果使用agent来与NMS进行交互的话, agent可以在本地发起子进程来进行调用. 因此使用agent的方式更加安全.
除了使用ssh/telnet通道, master/agent这两种, 我们还有哪些采样的通道嘞? 硬件接口, 例如IPMI, 智慧平台管理接口, 很多厂商都有实现, 例如DELL的DRAC, HP的Integrated Lights-Out等等. 另外还有一个大家都很熟悉的东西, 那就是SNMP, 简单网络管理协议, 这个古老的协议使得很多设备都自带一个它的agent. 例如在windows上, 我们可以找到可选功能安装页面, 启用之就行了. 在Linux上, 我们需要安装一个软件包就行了:
1 | [root@node1 ~]# yum info net-snmp |
有一个封装了SNMP协议功能的开源监控项目, 叫做cacti. 他将数据存储到了一个叫做RRDTool的数据日志和可视化系统中.
另外还有一个叫做JMX的玩意, 全称是Java management extension. 这个数据管理接口可以采集Java虚拟机的各项指标.
存储
至此我们就差不多说完了采样, 接下来我们来说说存储系统. 对于历史数据而言, 我们可能需要每次采样的结果, 保存时长三个月半年不能. 但对于趋势数据而言, 我们需要的就不会是每次的完整结果了, 我们可能需要的只是每个小时的最大最小和平均, 因此它的数据量远远小于历史数据, 也就是聚合数据, 我们可以保存时长较长周期.
最为常见的存储系统就是FS了, 显然这是十分麻烦的. 首先我们的指标非常多, 这仅仅对于一个主机而言. 如果我们想要获得某一个时间的数据, 就需要将整个巨大的文件载入到内存中, 这显然是不合理的. 因此我们就想到了使用关系型数据库, 但是对于监控系统而言, 数据的插入是非常多的, 也就是写操作, 这就会造成每秒钟事务的非常多. 另外一种就是轮询数据库, 也就是我们刚才提到的RRD: RoundRobin DataBase. 我们可以在一开始直接获得一个环状的数据区域, 当整个环填满了之后, 新数据就会将旧数据覆盖掉. 还有一种就是我们刚刚学习的NoSQL, 例如redis/mongo.
展示
展示就很简单了, 我们可以直接使用WebGUI, 或者是APP之类的.
报警
报警就很好理解了, 我们可以使用邮件, 短信, 或者是微信等等等等, 任何能够到达用户的通知方法都可以. 一般情况下, 我们需要写脚本, 这样只要触发该脚本即可.
Zabbix
Zabbix可以使用我们刚才提到的各种数据采集方式, 同时可以进行阈值定义, 支持递进式的报警机制. 使用mysql/pgsql来存储数据, 支持网络自动发现, 并且可以提供丰富的可视化选项. 我们可以使用布置监控代理来实现分布式监控. 同时, Zabbix提供了API, 我们还可以二次开发.

Zabbix的架构如上图所示:
其中最重要的组件就是Zabbix Server, 负责接受agent发送过来的各种数据. 同时各种配置信息也都保存在这里. 接着是Database, 听名字就知道这是个用于存储收集到的数据的组件.
Zabbix可以使用两种方式进行数据监控, 也就是被动和主动, 被动也就是Zabbix server去拉取数据, 然后agent返回数据, 而主动也就是Zabbix的agent主动将数据推到server端.
在Zabbix中, 我们可以把多个指标放在一个组中, 而这么一个组, 就叫做application, 而一个指标项就叫做item.

从逻辑层面上, 我们可以得到这样的一张关系图. 主要的过程在右下角.
安装Zabbix已经不能再简单了, 官方的网站上有着保姆级的教程, 并且配置文件的注释也十分的详细. 之后的配置都在WebGUI中进行.

配置完成之后就可以进行登录了, 默认的用户名是Admin, 密码是zabbix.
剩下的使用GUI就没有什么难的了.
另外, 我们可以安装一个zabbix的辅助程序叫做zabbix-get, 它相当于一个Zabbix接口的访问客户端. 例如:
1 | [root@node1 ~]# zabbix_get -s 192.168.10.102 -k "net.if.in[ens33, packets]" |
这个时候可以去agent端验证一下, 由于我这边两个节点一直在发包, 所以就没办法获得相同的结果啦.
Zabbix的核心功能
我们在添加item的页面, 可以看到zabbix agent提供了很多标准的item, 有些是不需要参数的, 而有些是需要我们加上参数的. 例如上面的流量监控, 就是需要我们提供网卡名称的. 例如CPU上下文切换: system.cpu.switches 就是一个不携带参数的item.
这里我们贴个例子:

可以看到, 我们在node2上设置了5个监控项, 并且zabbix为我们列出了上次检查的时间, 最新的数据以及变化量.
具体的一个配置页面如下:

首先是改监控项的名字, 接着选择使用何种方式进行数据采集, 这里我们一律使用的都是Zabbix agent. 接下来的key就是指明具体的监控项啦, 选择了监控项会决定下面的信息类型, 也就是数据类型啦, 有些可能返回的是个无符号整数, 有些可能是浮点型, 有些也可能是字符串. 接着我们还可以自定义数据的单位, 例如我们可以把网络流量每秒钟的出口报文这个一个key的单位自定义成为:packets/sec. 接着我们还可以设定间隔时间以及更加灵活的采集时间, 还可以进行schedule.
接下来的两个配置用来指明我们存储数据的方式. 还记得之前说过的application吗. 也就是item的组, 如果是新建组就直接在文本框中写名字就好了, 如果是要分配到已有的组, 就在下面的Applications选择即可. 另外, 向上看, 我们有一个叫做preprocessing的tab, 在这里我们可以对数据在展示之前进行预处理, 包括文本替换, 数据结构修改, 数学运算(倍乘), 验证等等.
经过一段时间之后, 我们可以前往数据页查看图表:

但是这个时候你会发现, 我们只是获取了数据, 并且有了一个可视化的界面, 但是还有一个很重要的动作没有. 那就是设置触发器.
目前我们只收集到了数据, 还没有做到当某个指标对应的数据超出合理范围的时候给相关人员发送警报. 简单的说, 触发器其实就是表达式, 用来定义阈值.
触发器支持多个函数, 例如平均, 计算数量, 最大最小值, 数据存在性, 求和, 正则等等. 一个基本的触发器表达式就像这样:
{<server>:<key>.<function>(<parameter>)}<operator><constant>
高度灵活, 所以我们创建出非常复杂的测试条件. 但是需要注意的是, 当条件满足的时候, TRUE表示的是PROBLEM状态, 反之, 就是OK状态.
在设置triggers的页面, 我们可以不手写表达式, 让zabbix为我们生成, 例如我们添加一个这样的触发器:
1 | {node2.zabbix.com:net.if.in[ens33, packets].last(#1)}>10000 |
这就是说, 当我们最后一个入站报文的值大于10000的时候, 就会被触发. 设置好了之后我们可以去图表页面看一下:

这里会看到一条红线, 这就是警戒线了. 平常我们的节点没啥流量, 所以只有十位数个位数的流量, 我们让他yum update一样, 瞬间这个值就会上去了. 然后我们可以去check一下problems页面就会看到红色闪烁的PROBLEM了, 当问题没有了之后, 状态就会变成RESOLVED. 而触发器的状态也会变成OK了.
另外, 想象这样的一种情景. 我们的一天服务器上运行的Nginx出现问题不能提供服务了, 但是这是因为我们的服务器本身宕机了, 如果我们对Nginx和服务器本身都加了触发器, 那么Nginx的触发器在这种情况下是不是压根就没意义了呀? 所以这就叫做, 触发器之间的依赖关系.
那么接下来, 我们就要定义Actions了.
首先我们需要定义条件, 也就是何时才使用这个action, 接下来下一步就是定义要做的操作. 我们之前说过, Zabbix可以进行步进式的操作设定, 也就是通过设定步骤来指明操作的层级.
例如我们在这里适用Linux的本地邮件来做个例子, 注意要先到Administration里面添加本地邮件这种Media Type和发送的消息内容(Zabbix有各种模板供你选用)才行, 另外还需要给你要发送的用户也配置上Media.
这样, 当我们的触发器触发到了这一个Action的时候, 我们就可以看到:
1 | [root@node1 ~]# mail |
接下来我们来说说Zabbix的主机配置模板, 我们可以设置一个链接至主机的模板, 从而实现主机的快速监控配置. 我们前往Configuration的Template里面,可以看到很多内置的模板. 模板可以导出, 也可以通过链接的方式进行模板之间的继承.
模板支持使用宏, 也就是预设的文本替换. 宏也有等级, 一共有三种:
- 优先级最高的, 全局宏, 在Administration中定义
- 模板宏, 在模板配置中定义, 也可以进行链接继承.
- 主机宏, 优先级最低, 在主机页面定义.
我们一开始就介绍过Zabbix支持网络发现, Zabbix提供了多个网络发现方式, 例如使用HTTP, SSH, SMTP, Zabbix agent等等. 在扫描到之后就会添加到监控主机当中来.
一旦发现主机, 就会产生发现事件, 也就是说我们的发现操作一共分为两步:
- discover
- actions: conditions, operations
Zabbix定义了多种发现事件:
| Event | Check of service result |
|---|---|
| Service Discovered | The service is ‘up’ after it was ‘down’ or when discovered for the first time. |
| Service Up | The service is ‘up’, consecutively. |
| Service Lost | The service is ‘down’ after it was ‘up’. |
| Service Down | The service is ‘down’, consecutively. |
| Host Discovered | At least one service of a host is ‘up’ after all services of that host were ‘down’ or a service is discovered which belongs to a not registered host. |
| Host Up | At least one service of a host is ‘up’, consecutively. |
| Host Lost | All services of a host are ‘down’ after at least one was ‘up’. |
| Host Down | All services of a host are ‘down’, consecutively. |
其实也就是Host, Service和Up/Down, Discovered/Lost的组合.
可以采取的行动有这些:
- Sending notifications
- Adding/removing hosts
- Enabling/disabling hosts
- Adding hosts to a group
- Removing hosts from a group
- Linking hosts to/unlinking from a template
- Executing remote scripts
因为我们先定义发现规则, 接着在设置发现事件触发之后采取的行动就可以了. 这里提个醒, 增加action的切换在左上角, 想吐槽一下这个UI, 真的好不明显啊.