open-falcon监控系统简介

Introduction

监控系统是整个运维环节,乃至整个产品生命周期中最重要的一环,事前及时预警发现故障,事后提供翔实的数据用于追查定位问题。监控系统作为一个成熟的运维产品,业界有很多开源的实现可供选择。当公司刚刚起步,业务规模较小,运维团队也刚刚建立的初期,选择一款开源的监控系统,是一个省时省力,效率最高的方案。之后,随着业务规模的持续快速增长,监控的对象也越来越多,越来越复杂,监控系统的使用对象也从最初少数的几个SRE,扩大为更多的DEVS,SRE。这时候,监控系统的容量和用户的“使用效率”成了最为突出的问题。

监控系统业界有很多杰出的开源监控系统。我们在早期,一直在用zabbix,不过随着业务的快速发展,以及互联网公司特有的一些需求,现有的开源的监控系统在性能、扩展性、和用户的使用效率方面,已经无法支撑了。

因此,我们在过去的一年里,从互联网公司的一些需求出发,从各位SRE、SA、DEVS的使用经验和反馈出发,结合业界的一些大的互联网公司做监控,用监控的一些思考出发,设计开发了小米的监控系统:open-falcon。

open-falcon的目标是做最开放、最好用的互联网企业级监控产品。

Highlights and features

  • 强大灵活的数据采集:自动发现,支持falcon-agent、snmp、支持用户主动push、用户自定义插件支持、opentsdb data model like(timestamp、endpoint、metric、key-value tags)
  • 水平扩展能力:支持每个周期上亿次的数据采集、告警判定、历史数据存储和查询
  • 高效率的告警策略管理:高效的portal、支持策略模板、模板继承和覆盖、多种告警方式、支持callback调用
  • 人性化的告警设置:最大告警次数、告警级别、告警恢复通知、告警暂停、不同时段不同阈值、支持维护周期
  • 高效率的graph组件:单机支撑200万metric的上报、归档、存储(周期为1分钟)
  • 高效的历史数据query组件:采用rrdtool的数据归档策略,秒级返回上百个metric一年的历史数据
  • dashboard:多维度的数据展示,用户自定义Screen
  • 高可用:整个系统无核心单点,易运维,易部署,可水平扩展
  • 开发语言: 整个系统的后端,全部golang编写,portal和dashboard使用python编写。

Architecture

备注:虚线所在的aggregator组件还在设计开发阶段。

每台服务器,都有安装falcon-agent,falcon-agent是一个golang开发的daemon程序,用于自发现的采集单机的各种数据和指标,这些指标包括不限于以下几个方面,共计200多项指标。

  • CPU相关
  • 磁盘相关
  • IO
  • Load
  • 内存相关
  • 网络相关
  • 端口存活、进程存活
  • ntp offset(插件)
  • 某个进程资源消耗(插件)
  • netstat、ss 等相关统计项采集
  • 机器内核配置参数

只要安装了falcon-agent的机器,就会自动开始采集各项指标,主动上报,不需要用户在server做任何配置(这和zabbix有很大的不同),这样做的好处,就是用户维护方便,覆盖率高。当然这样做也会server端造成较大的压力,不过open-falcon的服务端组件单机性能足够高,同时都可以水平扩展,所以自动多采集足够多的数据,反而是一件好事情,对于SRE和DEV来讲,事后追查问题,不再是难题。

另外,falcon-agent提供了一个proxy-gateway,用户可以方便的通过http接口,push数据到本机的gateway,gateway会帮忙高效率的转发到server端。

falcon-agent,可以在我们的github上找到 : https://github.com/open-falcon/agent

Data model

Data Model是否强大,是否灵活,对于监控系统用户的“使用效率”至关重要。比如以zabbix为例,上报的数据为hostname(或者ip)、metric,那么用户添加告警策略、管理告警策略的时候,就只能以这两个维度进行。举一个最常见的场景:

hostA的磁盘空间,小于5%,就告警。一般的服务器上,都会有两个主要的分区,根分区和home分区,在zabbix里面,就得加两条规则;如果是hadoop的机器,一般还会有十几块的数据盘,还得再加10多条规则,这样就会痛苦,不幸福,不利于自动化(当然zabbix可以通过配置一些自动发现策略来搞定这个,不过比较麻烦)。

open-falcon,采用和opentsdb相同的数据格式:metric、endpoint加多组key value tags,举两个例子:

{
    metric: load.1min,
    endpoint: open-falcon-host,
    tags: srv=falcon,idc=aws-sgp,group=az1,
    value: 1.5,
    timestamp: `date +%s`,
    counterType: GAUGE,
    step: 60
}
{
    metric: net.port.listen,
    endpoint: open-falcon-host,
    tags: port=3306,
    value: 1,
    timestamp: `date +%s`,
    counterType: GAUGE,
    step: 60
}

通过这样的数据结构,我们就可以从多个维度来配置告警,配置dashboard等等。 备注:endpoint是一个特殊的tag。

Data collection

transfer,接收客户端发送的数据,做一些数据规整,检查之后,转发到多个后端系统去处理。在转发到每个后端业务系统的时候,transfer会根据一致性hash算法,进行数据分片,来达到后端业务系统的水平扩展。

transfer 提供jsonRpc接口和telnet接口两种方式,transfer自身是无状态的,挂掉一台或者多台不会有任何影响,同时transfer性能很高,每分钟可以转发超过500万条数据。

transfer目前支持的业务后端,有三种,judge、graph、opentsdb。judge是我们开发的高性能告警判定组件,graph是我们开发的高性能数据存储、归档、查询组件,opentsdb是开源的时间序列数据存储服务。可以通过transfer的配置文件来开启。

transfer的数据来源,一般有三种:

  1. falcon-agent采集的基础监控数据
  2. falcon-agent执行用户自定义的插件返回的数据
  3. client library:线上的业务系统,都嵌入使用了统一的perfcounter.jar,对于业务系统中每个RPC接口的qps、latency都会主动采集并上报

说明:上面这三种数据,都会先发送给本机的proxy-gateway,再由gateway转发给transfer。

基础监控是指只要是个机器就能加的监控,比如cpu mem net io disk等,这些监控采集的方式固定,不需要配置,也不需要用户提供额外参数指定,只要agent跑起来就可以直接采集上报上去; 非基础监控则相反,比如端口监控,你不给我端口号就不行,不然我上报所有65535个端口的监听状态你也用不了,这类监控需要用户配置后才会开始采集上报的监控(包括类似于端口监控的配置触发类监控,以及类似于mysql的插件脚本泪监控),一般就不算基础监控的范畴了。

Alerting

报警判定,是由judge组件来完成。用户在web portal来配置相关的报警策略,存储在MySQL中。heartbeat server 会定期加载MySQL中的内容。judge也会定期和heartbeat server保持沟通,来获取相关的报警策略。

heartbeat sever不仅仅是单纯的加载MySQL中的内容,根据模板继承、模板项覆盖、报警动作覆盖、模板和hostGroup绑定,计算出最终关联到每个endpoint的告警策略,提供给judge组件来使用。

transfer转发到judge的每条数据,都会触发相关策略的判定,来决定是否满足报警条件,如果满足条件,则会发送给alarm,alarm再以邮件、短信、米聊等形式通知相关用户,也可以执行用户预先配置好的callback地址。

用户可以很灵活的来配置告警判定策略,比如连续n次都满足条件、连续n次的最大值满足条件、不同的时间段不同的阈值、如果处于维护周期内则忽略 等等。

另外也支持突升突降类的判定和告警。

Query

到这里,数据已经成功的存储在了graph里。如何快速的读出来呢,读过去1小时的,过去1天的,过去一月的,过去一年的,都需要在1秒之内返回。

这些都是靠graph和query组件来实现的,transfer会将数据往graph组件转发一份,graph收到数据以后,会以rrdtool的数据归档方式来存储,同时提供查询RPC接口。

query面向终端用户,收到查询请求后,会去多个graph里面,查询不同metric的数据,汇总后统一返回给用户。

Dashboard

dashboard首页,用户可以以多个维度来搜索endpoint列表,即可以根据上报的tags来搜索关联的endpoint。

用户可以自定义多个metric,添加到某个screen中,这样每天早上只需要打开screen看一眼,服务的运行情况便尽在掌握了。 

当然,也可以查看清晰大图,横坐标上zoom in/out,快速筛选反选。总之用户的“使用效率”是第一要务。 

Web portal

一个高效的portal,对于提升用户的“使用效率”,加成很大,平时大家都这么忙,能给各位SRE、Devs减轻一些负担,那是再好不过了。

这是host group的管理页面,可以和服务树结合,机器进出服务树节点,相关的模板会自动关联或者解除。这样服务上下线,都不需要手动来变更监控,大大提高效率,降低遗漏和误报警。 

一个最简单的模板的例子,模板支持继承和策略覆盖,模板和host group绑定后,host group下的机器会自动应用该模板的所有策略。 

当然,也可以写一个简单的表达式,就能达到监控的目的,这对于那些endpoint不是机器名的场景非常方便。 

添加一个表达式也是很简单的。 

Storage

对于监控系统来讲,历史数据的存储和高效率查询,永远是个很难的问题!

  1. 数据量大:目前我们的监控系统,每个周期,大概有2000万次数据上报(上报周期为1分钟和5分钟两种,各占50%),一天24小时里,从来不会有业务低峰,不管是白天和黑夜,每个周期,总会有那么多的数据要更新。
  2. 写操作多:一般的业务系统,通常都是读多写少,可以方便的使用各种缓存技术,再者各类数据库,对于查询操作的处理效率远远高于写操作。而监控系统恰恰相反,写操作远远高于读。每个周期几千万次的更新操作,对于常用数据库(MySQL、postgresql、mongodb)都是无法完成的。
  3. 高效率的查:我们说监控系统读操作少,是说相对写入来讲。监控系统本身对于读的要求很高,用户经常会有查询上百个meitric,在过去一天、一周、一月、一年的数据。如何在1秒内返回给用户并绘图,这是一个不小的挑战。

open-falcon在这块,投入了较大的精力。我们把数据按照用途分成两类,一类是用来绘图的,一类是用户做数据挖掘的。

对于绘图的数据来讲,查询要快是关键,同时不能丢失信息量。对于用户要查询100个metric,在过去一年里的数据时,数据量本身就在那里了,很难1秒之类能返回,另外就算返回了,前端也无法渲染这么多的数据,还得采样,造成很多无谓的消耗和浪费。我们参考rrdtool的理念,在数据每次存入的时候,会自动进行采样、归档。我们的归档策略如下,历史数据保存5年。同时为了不丢失信息量,数据归档的时候,会按照平均值采样、最大值采样、最小值采样存三份。

// 1分钟一个点存 12小时
c.RRA("AVERAGE", 0.5, 1, 720)

// 5m一个点存2d
c.RRA("AVERAGE", 0.5, 5, 576)
c.RRA("MAX", 0.5, 5, 576)
c.RRA("MIN", 0.5, 5, 576)

// 20m一个点存7d
c.RRA("AVERAGE", 0.5, 20, 504)
c.RRA("MAX", 0.5, 20, 504)
c.RRA("MIN", 0.5, 20, 504)

// 3小时一个点存3个月
c.RRA("AVERAGE", 0.5, 180, 766)
c.RRA("MAX", 0.5, 180, 766)
c.RRA("MIN", 0.5, 180, 766)

// 1天一个点存1year
c.RRA("AVERAGE", 0.5, 720, 730)
c.RRA("MAX", 0.5, 720, 730)
c.RRA("MIN", 0.5, 720, 730)

对于原始数据,transfer会打一份到hbase,也可以直接使用opentsdb,transfer支持往opentsdb写入数据。


管理升级机器上各种agent的一个小工具

背景

我们的监控系统open-falcon开源在即,需要在所有机器上部署falcon-agent采集机器硬件信息。我们内部使用一个自研工具frigga来管理各种agent,包括监控的agent、部署的agent、naming的agent等等,这个工具是ruby的,部署起来不是很方便,笔者最近花了一点时间用Go写了一个简化版的frigga,静态编译部署起来方便,专门用于管理升级监控agent,随着open-falcon的发布一并发布,大家可以尝试一下,超简单。

组件

工具由两部分组成

  • ops-updater: 部署在所有机器上,一般在装机的时候安装,功能简单,从不用升级,Go写的,静态编译,无任何lib依赖
  • ops-meta: 服务端,ops-updater定期与ops-meta通信,询问本机应该部署哪几个agent,版本分别是多少,然后做相应动作,完成ops-meta的指示

理念

  • 对于一个公司而言,agent并不多,也就有个监控agent、部署agent、naming agent,所以ops-meta直接采用配置文件而不是数据库之类的大型存储来存放agent信息
  • 公司级别agent升级慢一点没关系,比如一晚上升级完问题都不大,所以ops-updater与ops-meta的通信周期默认是5min,比较长。如果做成长连接,周期调小,是否就可以不光用来部署agent,也可以部署一些业务程序?不要这么做!部署其他业务组件是部署agent的责任,ops-updater做的事情少才不容易出错。ops-updater推荐在装机的时候直接安装好,功能少基本不升级。
  • 配置文件中针对各个agent有个default配置,有个others配置,这个others配置是为了解决小流量问题,对于某些前缀的机器可以采用与default不同的配置,也就间接解决了小流量测试问题
  • ops-updater会汇报自己管理的各个agent的状态、版本号,这个信息直接存放在ops-meta模块的内存中,因为数据量真没多少,即使有100w机器,3个agent也没多少数据
  • ops-updater启动之后应该随机sleep一段时间再与ops-meta周期性通信,避免大量ops-updater同时与ops-meta通信造成压力

代码

这个小组件没有放到github上,而是在国内的gitcafe,感觉用着还不错,赞一个

  • ops-common: https://gitcafe.com/ops/common
  • ops-updater: https://gitcafe.com/ops/updater
  • ops-meta: https://gitcafe.com/ops/meta

编译

这是个Go语言写的项目,故而我们要先搭建Go的编译环境

cd ~ wget http://dinp.qiniudn.com/go1.4.1.linux-amd64.tar.gz tar zxvf go1.4.1.linux-amd64.tar.gz mkdir -p workspace/src echo "" >> .bashrc echo 'export GOROOT=$HOME/go' >> .bashrc echo 'export GOPATH=$HOME/workspace' >> .bashrc echo 'export PATH=$GOROOT/bin:$GOPATH/bin:$PATH' >> .bashrc echo "" >> .bashrc source .bashrc

接下来clone代码编译:

cd $GOPATH mkdir -p src/gitcafe.com/ops cd src/gitcafe.com/ops git clone git://gitcafe.com/ops/common.git git clone git://gitcafe.com/ops/updater.git git clone git://gitcafe.com/ops/meta.git cd updater go get ./... ./control pack cd ../meta go get ./... ./control pack

上面做完之后,updater目录和meta目录分别产出一个tarball,拿着这货去部署即可。注意:上面用到的Go语言环境是linux-amd64,我也只在64位Linux下测试使用过,其他平台需要您自己搞定哈

部署ops-meta

我们姑且就拿编译机来部署ops-meta,作为咱们的server

cd ~ mkdir -p ops tar zxvf workspace/src/gitcafe.com/ops/meta/ops-meta-0.0.2.tar.gz -C ops cd ops mv cfg.example.json cfg.json # modify cfg.json ./control start

这样ops-meta就启动了,启动之后这个组件监听在2000端口,./control status可以看到进程状态,或者通过ss -tln|grep 2000查看端口是否在监听

配置ops-meta

写这个工具的本意是为了批量部署管理我们的falcon-agent,我提前准备好了一个http://7xiumq.com1.z0.glb.clouddn.com/open-falcon-agent-demo-3.1.3.tar.gz ,咱们配置一下ops-meta,来把这个demo版本的falcon-agent管理起来

修改后的cfg.json如下:

{ "debug": true, "tarballDir": "./tarball", "http": { "enabled": true, "listen": "0.0.0.0:2000" }, "agents": [ { "default": { "name": "falcon-agent", "version": "3.1.3", "tarball": "http://127.0.0.1:2000/falcon", "md5": "", "cmd": "start" } } ] }

这里我们没有使用others配置,无需小流量,ops-meta同时充当了http download server的角色,把falcon-agent放到指定位置

cd ~/ops mkdir -p tarball/falcon cd tarball/falcon wget http://7xiumq.com1.z0.glb.clouddn.com/open-falcon-agent-demo-3.1.3.tar.gz -O falcon-agent-3.1.3.tar.gz md5sum falcon-agent-3.1.3.tar.gz > falcon-agent-3.1.3.tar.gz.md5

OK,做完以上工作之后ops-meta就准备好了,她托管了一个falcon-agent,静待ops-updater来下载

部署ops-updater

ops-updater理应部署在公司所有机器上,这里做测试,也在当前这个机器部署,咱们把它部署在~/agents目录,拉取下来的falcon-agent也会出现在这个目录,具体目录组织结构可以看一下我们的README

cd ~ mkdir -p agents tar zxvf workspace/src/gitcafe.com/ops/updater/ops-updater-0.0.1.tar.gz -C agents cd agents mv cfg.example.json cfg.json # modify cfg.json ./control start

这两个组件的部署都比较简单,再次赞一下Go的静态编译,检查方式与ops-meta一样,./control status或者ss -tln|grep 2001,ops-updater监听在2001端口,updater为啥要监听一个http端口呢?纯粹为了调试,为了健康检查,如果担心安全问题可以在配置文件中配置为enabled: false

配置ops-updater

配置基本可以维持默认,不过测试阶段,可以把interval调得小一点,比如:3,这个是ops-updater每隔多久请求一次ops-meta,单位是秒,先上如果机器量特别大,这个间隔就要调大一点了。

稍等一会,你就可以在~/agents目录中看到falcon-agent目录了,访问一下http://127.0.0.1:1988/ 看到本机Dashboard了么?看到了就说明falcon-agent已经被ops-updater部署成功了:)

不传之秘

如何查看各个机器上的agent部署情况呢?

ops-updater会把管理的agent的版本上报给ops-meta,ops-meta提供了一个http接口查看,比如我们要查看falcon-agent的部署情况

# 使用文本方式返回 curl http://127.0.0.1:2000/status/text/falcon-agent # 使用json返回 curl http://127.0.0.1:2000/status/json/falcon-agent

就这么多了,有问题可以加入我们的QQ群:373249123讨论,我会给解答滴:)

补充

这个项目只有两个模块,均是用Go语言编写的,我录制了一个视频放在极客学院讲解这个项目是如何一步一步做出来的,推荐Go语言学习者看一下

  • http://www.jikexueyuan.com/course/1336.html
  • http://www.jikexueyuan.com/course/1357.html
  • http://www.jikexueyuan.com/course/1462.html
  • http://www.jikexueyuan.com/course/1490.html

如果从中学到了知识,小小打赏一下吧:)

你可能感兴趣的:(open-falcon监控系统简介)