Sensu 是由 Sonian 公司开发的一种监控框架,主要用于拥有大规模节点的云计算平台的检查与监控。目前发行的版本有企业版和开源版两种,收费的企业版本较之免费的开源版本拥有更多的功能。出于介绍的目的,本文的内容都是基于开源版本的 Sensu。
开源版本的 Sensu 遵循 MIT 许可,旨在为分布式的平台提供灵活易用、快速简单、便于拓展的监控和维护服务。主要包含以下功能与特性:
检查系统、服务和程序的运行状态。
基于分布式的设计,能够轻松的动态伸缩规模。
支持通过插件的形式自定义检查的内容,拥有丰富的插件库。
收集信息,获取被监控节点上的各项数据指标等。
可视化的操作界面,提供实时的 GUI 用于显示和操作相关信息。
内置的集成工具,可用于和其它系统集成,如 PagerDuty、Graphite、Email 等。
提供丰富的 API 接口,支持通过 API 调用访问事件和客户端信息,触发检测等。
加密的安全通信,支持各种复杂的网络拓扑。
Sensu 由服务器、客户端、RabbitMQ、Redis 和 API 这五个部分构成。图 1 展示了这些组件之间的关系以及通信的数据流。如图所示,RabbitMQ 用于组件之间的通信,Redis 用于持久化 Sensu 服务器和 Sensu API 的数据。因为客户端都是通过文件进行配置,并且不需要在服务器端配置客户端的信息,所以可以很轻易的增加和减少客户端的数量。由于 Sensu 的服务器和 API 原生支持多节点部署,所以不存在效率的瓶颈问题。从图中可以看到,为了解耦服务器和客户端,通信都是通过 RabbitMQ 进行的,如果只有单节点的 RabbitMQ,这可能会带来通信上的瓶颈问题。可以通过 RabbitMQ 官方提供的集群部署解决方案来解决这个问题。
Sensu 的设计中涵盖了一些自定义的概念,比如 Check、Event、Handler、Filter 等,为了更加清晰的介绍 Sensu,下面将对这些概念分别进行解释。
Check 是一段在客户端运行的可执行程序,用于检测和监控客户端上的各种服务、资源和应用程序的运行状态。Check 在执行后通过返回一个值来表示所检测内容的状态,通常使用 0 表示 OK,1 表示 WARNING,2 表示 CRITICAL,3 以及更大的值表示 UNKNOWN 或用户自定义状态。
Check 有两种类型:standard 和 metric。对于 standard 类型的 check 来说,Sensu 不会在每次执行后都生成 event,而只是在 check 所返回的结果为非 0 或者是从非 0 变为 0 的时候才会生成 event。这样带来的好处是降低了负载,适用于那些只关注于非正常状态,而在正常的状态无需采取措施的监控场景。相对应的,metric 类型的 check 则会在每次执行后,无论其返回的结果是什么都生成 event。此类型的 check 一般用于获取监控的信息,除了 check 所返回的状态值,还有一些其它的输出信息可以通过 event 进行收集,然后返回给 Sensu 服务器。
Check 还有 standalone 和 subscription 两种运行模式。Standalone 模式下的 check 直接在客户端进行配置,不需要服务器端发出执行的请求,可以根据配置的时间间隔在客户端自主执行,每次执行后会将结果通过消息队列返回给服务器。Subscription 模式下的 check 则是在服务器端配置,在配置的时候需要为 check 设置订阅主题。当要执行该 check 时,服务器会根据订阅主题分发执行请求,所有订阅了相应主题的客户端会收到执行的请求,从而运行 check 程序。同样的,执行的返回结果也会通过消息队列返回给服务器。
Sensu 使用 event 来通知所监控内容的状态变化。比如当 check 执行后返回 2,这表示所监控的内容出现了较为严重的问题,那么 Sensu 会生成 event 来报告这个问题,Event 会绑定一个或多个 handler 来对所报告的问题进行处理。Event 包含有一些上下文信息,主要包括执行 check 的客户端信息和 check 运行后的结果信息。Handler 通常会使用这些信息来执行相应的处理行为。通常 event 数据是以 JSON 格式传递的,以下是一个 event 的示例:
{ "action": "create", "occurrences": 1, "client": { "name": "i-424242", "address": "8.8.8.8", "subscriptions": [ "production", "webserver", "mysql" ], "timestamp": 1326390159 }, "check":{ "name": "frontend_http_check", "issued": 1326390169, "subscribers":[ "frontend" ], "interval": 60, "command": "check_http -I 127.0.0.1 -u http://web.example.com/healthcheck.html -R 'pageok'", "output": "HTTP CRITICAL: HTTP/1.1 503 Service Temporarily Unavailable", "status": 2, "handler": "slack", "history": [ "0", "2" ] } }
可以看到,event 数据包含了 Sensu 客户端的基本信息,包括名称、IP 等,同时也包含了所执行的 check 信息,客户端执行了该 check 并返回了状态值为 2,同时给出了一条输出内容“HTTP CRITICAL: HTTP/1.1 503 Service Temporarily Unavailable”,这条输出信息可以用来帮助 handler 对问题进行处理。
Sensu handler 用于处理 Sensu event。Handler 在 check 的配置文件中指定,可以同时指定多个 handler 对 event 进行处理。Sensu 包括以下几种类型的 handler:
Pipe handler: 执行命令,把 event 数据通过 STDIN 传递给处理程序。
TCP and UDP handler: 把 event 数据发送给一个远程的 socket。
Transport handler:向 Sensu transport(默认为 RabbitMQ) 发送 event 数据。
Set handler: 用于组成一个 event handler 集合,使得能够同时管理多个 handler。
Sensu Filter 用来过滤一些 Sensu event。Filter 会检查 event 中的数据和 filter 定义中的过滤规则是否匹配。符合匹配规则的 event 会根据选择的过滤方式,发送或者不发送给 event handler。
。Filter 通常用于过滤一些噪音信息,以防止错报和误报事件。Sensu filter 包含两种过滤方式:包含和排除。包含方式指定的是含有相应信息的 event 才会被发送至 handler。而排除方式则相反,含有指定信息的 event 会被过滤掉,不会被发送到 handler 进行处理。值得注意的是,可以同时指定多个 filter,此时 event 需要同时匹配所有指定的 filter 规则。
Sensu Mutators 用来转换 event 数据,然后将转换后的数据传递给 event handler。通过使用 Mutators 对 event 数据进行处理,就避免了在 handler 中对 event 数据进行数据处理和格式化,并且多个 handler 可以共享一个 mutator,从而减少了重复代码,简化了 handler 的实现工作。
Mutators 在 Sensu 服务器端执行,从 STDIN 接收 JSON 格式的 event 数据,并将转换后的数据写入 STDOUT。Mutators 会返回一个退出码用于标识转换是否成功。如果 Mutators 执行失败,事件将不会被 handler 处理,并且这个错误会被日志记录。
Sensu 的每个部分都可以单独安装在不同节点。另外 Sensu 也支持多服务器节点、多数据库节点的安装,但是这超出了本文的范围,以下安装与配置的介绍仅仅是针对单节点的情况。本文所使用的演示环境为 X86 平台上的 64 位 RHEL6.5 操作系统,所使用的 Sensu 版本为 0.20.0。
RabbitMQ 和 Redis 的安装与配置
1) 安装 epel 源 # wget http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm # rpm -Uvh epel-release-6-8.noarch.rpm 安装 erlang # yum install erlang 安装 RabbitMQ # rpm --import http://www.rabbitmq.com/rabbitmq-signing-key-public.asc # rpm -Uvh http://www.rabbitmq.com/releases/rabbitmq-server/v3.5.3/rabbitmq-server-3.5.3-1.noarch.rpm 配置 RabbitMQ # chkconfig rabbitmq-server on # /etc/init.d/rabbitmq-server start # rabbitmqctl add_vhost /sensu # rabbitmqctl add_user sensu secret # rabbitmqctl set_permissions -p /sensu sensu ".*" ".*" ".*"
# yum install redis # /sbin/chkconfig redis on # /etc/init.d/redis start
Sensu 服务器和客户端的安装过程是一致的,都是使用 sensu 的 yum 源进行安装。
配置 sensu 的 yum 源 # echo '[sensu] name=sensu baseurl=http://repos.sensuapp.org/yum/el/$basearch/ gpgcheck=0 enabled=1' | tee /etc/yum.repos.d/sensu.repo # yum install sensu
配置 sensu 服务器端,在/etc/sensu/目录下添加 config.json 文件:
{ "rabbitmq": { "host": "localhost", # 此处为 RabbitMQ 的 IP 地址。 "vhost": "/sensu", "user": "sensu", "password": "secret" }, "redis": { "host": "localhost" # 此处为 Redis 的 IP 地址。 }, "api": { "host": "localhost", # 此处为 API 的 IP 地址。 "port": 4567 } }
配置 sensu 客户端,在/etc/sensu/目录下添加 config.json 文件:
{ "rabbitmq": { "host": "9.114.194.31", "user": "sensu", "password": "secret", "vhost": "/sensu" }, "api": { "port": 4567 } }
此外,还需添加描述客户端信息的配置文件,在客户端节点/etc/sensu/conf.d/目录下添加 client.json 文件:
{ "client": { "name": "client234", "address": "9.114.192.234", "subscriptions": [ "test" ] } }
Uchiwa 是 sensu 的用户管理界面,主要包含查看客户端和 check 相关信息的功能。下面简要介绍 uchiwa 的安装与配置。
# wget http://dl.bintray.com/palourde/uchiwa/uchiwa-0.10.2-1.x86_64.rpm # rpm -Uvh uchiwa-0.10.2-1.x86_64.rpm
配置/etc/sensu/uchiwa.json 文件:
{ "sensu": [ { "name": "sensu31", "host": "9.114.194.36", #API 服务 IP 地址。 "port": 4567, #API 服务的端口。 "timeout": 5 } ], "uchiwa": { "host": "9.114.193.221", "port": 3000, "interval": 5 } }
下面将通过一个具体的实例来演示 sensu 的使用。出于演示的目的,例子中只使用了一个客户端节点。主要的逻辑是使用 sensu 对节点的剩余内存情况进行监控,每隔一段时间调用 check 去检查被监控机器上剩余的内存,并设置两个报警阈值,一个用于指示 WARNING 状态,另一个用于指示 CRITICAL 状态。此外,我们还添加了将 event 信息写入文件的 handler,传递给 handler 的 event 数据会被输出到文件中。最后,我们演示 filter 的使用,通过添加 filter 设置只有连续发生 5 次以上的状态才会递交给 hanlder 进行处理。
首先对 check 进行配置,我们使用 subscription 模式配置 check。本例中使用的 Check 插件源于 Sensu 社区,社区中提供了很多开源的插件程序。本例使用的 Check 插件逻辑非常简单,插件中通过调用 free 命令查询机器的内存使用情况,然后判断当前剩余内存是否小于警戒值。用户可通过参数设置 WARNING 和 CRITICAL 对应的内存警戒值,当所剩内存大于 WARNING 警戒值时,check 返回 0,小于 WARNING 警戒值但大于 CRITICAL 警戒值时返回 1,小于 CRITICAL 警戒线时返回 2。在服务器端/etc/sensu/config.d/目录下添加 check 的配置文件:
{ "checks": { "mem_check": { #check 的名称。 "type": "metric", #check 的类型。 "command": "/etc/sensu/plugins/check-mem.sh -w 102400 -c 10240 -p", #check 执行的命令。 "subscribers": [ # 订阅主题,订阅了以下主题的客户端会收到执行该 check 的请求。 "production", "test" ], "interval": 10, "handler": "file" # 配置处理 event 的 handler。 } } }
在 Sensu 客户端/etc/sensu/plugins/目录下添加 check 执行程序 check-mem.sh,并给其添加可执行权限。
# wget -O /etc/sensu/plugins/check-mem.sh https://github.com/sensu-plugins/sensu-plugins-memory-checks/blob/master/bin/check-memory.sh # chmod +x /etc/sensu/plugins/check-mem.sh
添加一个可以将 event 信息写入文件的 handler,在上面的 mem-check.json 中,已经通过名称指定了该 handler。当 handler 被调用时,会在/tmp 目录下生成以客户端信息命名的文件,文件内容为 event 的所有信息。在 sensu server 端/etc/sensu/conf.d/目录下添加 my_handler.json:
{ "handlers": { "file": { #handler 的名称,在 check 的配置文件中使用该名称引用 handler。 "type": "pipe", #handler 的类型。 "command": "/etc/sensu/plugins/event-file.rb", "timeout": 10, "filter": "recurrence" # 指定 filter。 } } }
在 Sensu 服务器端/etc/sensu/plugin/目录下安装 handler 的插件:event-file.rb。
# wget -O /etc/sensu/plugins/event-file.rb http://sensuapp.org/docs/0.20/files/event-file.rb # chmod +x /etc/sensu/plugins/event-file.rb
添加一个 filter,用于过滤掉重复出现次数小于 3 的事件。这样可以避免被监控节点上某些程序内存使用临时达到峰值引起的误报。Filter 在 handler 的配置文件中指定,可以看到,我们通过名称”recurrence”在 my_handler.json 中指定了使用该 filter。同样的,在服务器端/etc/sensu/config.d/目录下添加 filter 配置文件 my_filter.json:
{ "filters": { "recurrence": { #filter 的名称,在 handler 的配置文件中通过该名称引用 filter。 "attributes": { # 以下规则所使用属性与 event 中定义相同,具体可见 event 文档。此外, 由于 event 数据包含 client 和 check 的定义信息,所以用户可以通过在 client 和 check 的配置文件中添加自定义属性, 此处也可使用自定义的属性指定规则。 "occurrences": "eval: value > 5" #occurrences 属性表示事件发生的次数。 } } } }
启动 sensu 的服务器和客户端服务,并通过 uchiwa 查看运行结果。
从图 2 可以看到,history 中连续出现了 11 个返回值为 1,这表示连续 11 次 check 返回 WARNING 状态,从而通过了 filter 筛选条件,由 hanlder 进行处理。查看服务器/tmp 目录下是否成功生成输出文件:
图 3 的结果显示了 handler 成功的处理了 event,生成了对应的输出文件。
由于开源版本的 Sensu 不支持监控数据的可视化,不利于直观的表达监控结果,也没有原生的支持对历史数据的查询与搜索。通常我们利用将 Sensu 与其它工具集成,构建出一套能够通过图表展示监控信息并支持数据查询的监控系统。比较常见的集成有:将 Sensu 与 Graphite、Grafana 的集成。Graphite 本身也是一种监控工具,但是它并不提供收集数据的功能,只提供数据的存储、查询与显示功能。我们通常只使用 Graphite 提供的时序数据库和数据查询接口,由于 Graphite 提供的可视化图表不够美观,操作也不够方便,所以我们使用 Grafana 来实现数据的可视化。完整的流程为:Sensu 从监控节点获取数据,将数据格式化成 Graphite 要求的格式,然后通过调用 Graphite 的接口将数据发给 Graphite。Graphite 将数据存储在时序数据中供 Grafana 绘图使用。最终用户通过在 Grafana 中定制需要显示的数据及显示的方式,获得最终的可视化图表,如图 4 所示。
除此之外,Sensu 通常也会与运维人员经常使用的一些工具集成,比如 Slack 和 Pagerduty。Slack 是目前非常流行的一种及时通信工具,通过将 Sensu 和 Slack 集成,可以把监控的结果通过 Slack 实时的发送给运维人员。Pagerduty 是运维人员经常使用的用于管理事件、警报等内容的系统。当系统发生警报时,Pagerduty 记录该事件,标记当前状态并及时发送通知给运维人员。通过将 Sensu 与 Pagerduty 集成,可以统一对 Sensu 所监控的服务进行管理,方便运维人员及时的处理各种事件。
Sensu 给出了一种监控云计算平台的解决方案,本文对 Sensu 的概念、组成、安装配置和相关功能进行了介绍,并通过简单的示例演示了如何使用 Sensu 来对远程节点进行监控。在实际的工作场景中,Sensu 通常会和其它工具一起配合使用,从而达到自动发现问题、报告问题、解决问题的目的,降低运维成本,提高工作效率。目前主流的云计算平台 OpenStack 也在使用 Sensu 作为其监控解决方案,详情可参见社区文档和其监控工具子项目。