[转] open-falcon编写的整个脑洞历程

[From] https://mp.weixin.qq.com/s?__biz=MjM5OTcxMzE0MQ==&mid=400225178&idx=1&sn=c98609a9b66f84549e41cd421b4df74d前端

 

讲师:秦晓辉java

我的介绍:mysql

一个来自运维部的研发,长期从事自动化运维平台的构建,参与百度自动化部署系统Archer、小米的监控系统open-falcon,偶尔作作PaaS,国内首个开源PaaS平台(噱头,哈)DINP的做者。代码熟手,工程师,not程序员。nginx

分享的主题:《open-falcon编写的整个脑洞历程》git

1. zabbix时代的痛程序员

2. open-falcon的目标制定github

3. 架构设计的习惯性redis

4. 试用以后算法

5. 一些折中sql

6. 将来改进

 

你们好,我是秦晓辉,来自小米运维部,毕业这几年一直作运维平台开发,对部署系统、监控系统相对熟悉一些,此次主要是给你们介绍一下open-falcon开发过程当中的一些思考,力求以最直白的表述重走一下开发过程,若是大家公司也要写一套监控,或许会有一点帮助,群里大牛众多,献丑了。

 

原本想提纲挈领的讲一讲,顶多40分钟搞定,写稿件的时候越写越多,限于我的表达能力的问题,而又想尽可能讲清楚,老是啰啰嗦嗦的,最后发现时间关系仍是无法所有讲到,你们见谅。

 

咱们先来说讲zabbix时代的痛,小米初期是使用zabbix来作监控的。zabbix你们应该是知道的,大名鼎鼎,成熟稳健,不少公司都在用。小米也不例外,初期作运维开发的人比较少,机器量、业务量也少,zabbix能够很好的知足需求。

 

咱们要开发一个项目、产品,确定是要解决一些问题,zabbix是很好,可是机器量、业务量上来以后,zabbix就有些力不从心了。那咱们先来讲一下zabbix存在的问题。

 

小米在大规模使用zabbix的年代,我当时在研究CloudFoundry,直到众位sre受不了zabbix了,但愿开发一个新的监控系统,咱们开始组建监控团队,开始open-falcon的设计、编码。因此对zabbix的问题可能理解不深刻,抛砖引玉……

 

1. 性能瓶颈。zabbix是使用MySQL来存放监控历史数据的。一台机器假设有100个监控项,2000台机器,就是20w监控项,监控系统的数据采集没有高峰低谷,是持续性的,周期性的,通常是一分钟采集一次。

机器量愈来愈大,数据量就愈来愈大,MySQL的写入逐渐成为瓶颈,业界有一些proxy的方案,咱们有试用,也尝试把采集周期调长,好比3分钟采集一次,或者5分钟采集一次,可是都治标不治本。

 

zabbix有些数据采集是经过pull的方式,也就是server端主动探测的方式,当目标机器量大了以后,这些pull任务也常常出现积压。维护zabbix的同窗焦头烂额。

2. 管理成本高昂。为了让zabbix压力小一点,咱们整个公司搭建了多套zabbix,好比多看本身用一套、电商本身用一套、米聊本身用一套,若是要作一些公司级别的统计,须要去多个数据源拉取数据。每套zabbix都得有运维人员跟进,人力成本上升。

3. zabbix有些易用性问题。好比zabbix的模板是不支持继承的,机器分组也是扁平化的,监控策略不容易复用。zabbix要采集哪些数据,是须要在server端作手工配置的,咱们认为这是一个本该省去的操做。

4. 监控系统没有统一化。机器相关的数据采集、监控咱们使用zabbix来作,可是咱们还须要业务的监控,好比某个thrift rpc接口,每分钟调用的cpslatency,咱们但愿作监控,某些url5xx4xx咱们也但愿作监控,某个开源软件,好比redisopenstackmysql的一些状态统计数据,咱们也但愿作监控。

 

咱们称后面这些数据为performance数据,我同事来炜曾经专门写了一个系统叫perfcounter,用来存放这些performance数据。perfcounter使用rrdtool来绘图,rrd是一个环形数据库,不少监控系统的数据都是使用rrd来存储的,这个就不展开讲了,你们能够google一下rrd相关知识。

 

perfcounter的绘图作得不错,可是报警功能比较薄弱。zabbix自己有多套,再加上perfcounter,入口比较多,要看监控数据,可能要去不一样的地方分别查看,比较麻烦。迫切须要一个大一统的解决方案。

 

不能否认,zabbix是个很优秀的方案,初期zabbix帮咱们解决了很大的问题,不过如上所述,咱们在使用过程当中也遇到了一些问题,刚开始的时候提到过,zabbix时代我还在作PaaS,因此上面的说法主要是在作open-falcon设计的时候从各位sre了解到的。

 

下面咱们来讲说open-falcon的目标制定。咱们已经肯定要作一个新的监控解决方案了。因而开始讨论,这货应该作成什么样子。每一个人可能都会有一些思考,可是每一个point基本都比较散乱,我初入监控这个业务,主要是推进你们的讨论,而后整理方案,再讨论,再整理,最终出一个产品需求文档和概要设计。

 

有人说,咱们应该既能够处理机器监控,也能够处理业务监控,还能够处理各类开源软件的监控。

 

没错,就是要这种大一统,并且不一样的系统有不一样的采集方式,有不一样的监控指标,DBAMySQL熟悉,知道应该采集哪些指标,云存储团队对HBase熟悉,知道应该采集哪些指标,可是我做为监控系统的开发人员,我对MySQL不熟,对HBase不熟,因此咱们没法提供其对应的采集脚本。

 

下面重点!

因此咱们要制定规范,制定推送接口,你们本身去采集本身的系统,完事按照咱们的规范,把数据组织成监控系统须要的数据格式,发送给监控系统的接口。这样你们就能够共建监控数据,把各类须要监控的软件、平台都归入进来。

 

固然了,对于操做系统的一些指标,好比cpu、内存、IO、网卡、磁盘、负载等等,这个仍是须要咱们监控系统开发人员去提供采集机制的。

因而,咱们仿照zabbix_agentd,编写了falcon-agent

这一部分主要是讲监控系统的数据采集机制

 

这里有哪些思考的点呢?首先,咱们不但愿用户在server端配置哪一个机器应该采集哪一个指标,这样作麻烦且不必。咱们尽可能把agent作得能够自发现,好比某机器有12块盘,agent应该能够自动探测到,而后采集各块盘的指标pushserver;好比某个机器有2块网卡,agent也应该自动探测到,把各块网卡的流量、丢包率等信息采集pushserver

 

就是说,咱们但愿在装机的时候就把agent安装好,agent就能够自动去采集相关数据了,省去了服务端的配置。

 

顺着这个思路继续延伸一下哈,天不遂人愿,咱们但愿服务端不作任何配置,agent就能够自动去采集,这是咱们的设计哲学,可是有的时候仍是要打破一下,好比端口存活监控、进程数监控。

 

咱们拿端口存活监控来举例,按照咱们自动去采集数据的哲学,agent应该如何处理端口存活性呢?你们稍微思考一下。

 

刚开始咱们的想法是这样的:咱们能够把当前机器上监听的全部tcp端口收集到,汇报给server,好比某机器监听了2280两个端口,ss -tln,获取之。这样的确是能够收集到数据。可是我如今要作80端口的存活性监控,server端应该怎么作呢?

 

想一想cpu.idle,咱们一般会在server端作配置,说某个机器的cpu.idle,连续3<5%,就报警,最多报3次。这个策略要想正常工做,cpu.idle的数据就应该源源不断的上来。每一个周期都不能少。

 

可是端口监控,ss -tln,能够获取当前有哪些tcp端口在监听,假设如今nginx进程挂了,80端口再也不监听,ss -tln就只能获取到22端口,获取不到80端口了,因而汇报给server端的数据就少了80端口的数据。

 

相似cpu.idle的监控方式是须要数据源源不断上来的,因而,端口监控在这种模式下没法完成。怎么办?

 

咱们能够写一个nodata的组件,来判断数据多长时间没上来就报警。可是nodata组件实现起来还有点小麻烦,并且还存在另外两个问题,一个是策略配置方式与cpu.idle等数据的策略配置方式不同,好比cpu.idleall(#3)<5报警,端口存活须要配置成相似:nodata(300),方式不一样用户的使用成本会上升;再一点是有些机器可能监听了N多个端口,可是真正须要监控的端口,只有少许几个,自发现端口形成资源浪费。

all(#3) 表示连续3次都

nodata(300) 表示300s没数据上来

 

换个方式……

端口再也不作成自发现的。用户要想对端口作监控,最后确定是要配置策略的。咱们从用户配置的策略中找出全部须要监控的端口,经过hbs模块下发给agent,这样agent就能够只对特定端口作监控了。好比刚才的例子,某主机须要监控2280两个端口,用户必然在服务端配置策略,咱们从策略中分析出2280,而后下发给对应的agentagent就能够只监控这俩端口了,端口活着,汇报个1给服务端,端口死了,汇报个0给服务端,好比:net.port.listen/port=22 value=1net.port.li1net.port.li1net.port.listen/port=80 value=0

 

下发这个动做是经过hbs这个模块来完成的,即heartbeat serveragent每分钟去调用hbs,询问本身应该监听哪些端口、哪些进程、要执行哪些插件。经过这种机制来下发一些状态信息。

 

OK,数据采集这部分,就是这么多内容:

1. server端制定接口规范,以此接入各类监控数据

2. agent自发现采集各类Linux性能指标,无需server端作配置

3. 进程、端口监控等没法作到自发现的,又不想引入nodata组件,想让策略配置统一化,就须要hbs来下发信息。

继续下个点以前,这里再补充两点不过重要的。

1. agent要采用什么语言来开发?

开发open-falcon这个系统以前,其实我最熟悉的语言是java。可是agentrun在全部目标机器上的,用本身最熟悉的java来开发么?要run agent,每一个机器上都要先启动一个java虚拟机,这有点扯……

 

咱们但愿找一个资源占用尽可能少的语言,CC++或许是个不错的选择,可是CC++我并不熟悉,听说写很差还容易内存泄露,呵呵。C/C++相对更底层,对于不一样的操做系统可能要写不少分支,简单看过zabbix_agentd的源码,各类操做系统的分支处理,很麻烦。固然了,zabbix但愿兼容各类操做系统,因此写的分支比较多,咱们公司的操做系统清一色centos,不会有这么多分支判断。

 

咱们但愿找一个更工程化的语言,不容易出错的语言,毕竟要在全部的机器上部署,今天这个core了明天那个core了也让人受不了。

 

go语言看着还不错哦。首先,go是静态编译的,编译完了一个二进制,扔到相同平台的机器上能够直接跑,不须要安装乱七八糟的lib库,这点特别吸引我,特别是我在上家公司作过至关长一段时间的自动化部署,这种部署友好的静态编译发布,我喜欢。

 

go的进程不须要java那种虚拟机,资源占用比较少;go的并发支持是语言层面的,server端须要并发的组件用着合适;go的资源回收是defer关键字,也不是传统的try...catch...finally,干净且不容易出错;gofunction能够有多个返回值,错误处理一般是一个额外的error类型的返回值,无需抛异常,由于是返回值,不刻意忽略的话就确定会记得处理,不然编译都过不了;gogithub结合,生态创建的比较快;go的模板看起来怪怪的,还好我不须要用……

 

2. agent怎么扩展?

咱们能够在agent中预置一些采集项,可是咱们不是神,没法覆盖全部的需求。有些用户须要扩展agent的功能,采集更多的指标。咱们须要提供这种机制。这就是插件机制的设计初衷。

 

zabbix是有一个目录,你们只要把采集脚本放到这个目录,zabbix就去执行。这样作天然是能够解决问题,可是有些问题实际上是扔给了使用者,好比脚本的分发管理问题。

 

那咱们来思考,要采集数据发送给server端,应该要作哪些事情呢?

 

a) 写一个采集数据的脚本

b) 把脚本分发到须要采集数据的机器上

c) 写一个cron每隔一段时间去跑这个脚本

d) 收集脚本的输出,调用server的接口去push数据

e) 根据需求相应的对脚本作上线、下线、升级

 

插件机制是如何解决这几个过程的呢?首先,脚本确定仍是要用户本身写,可是咱们提供一个脚本的管理,采集脚本是代码,代码就须要版本管理,咱们内部有个gitlab,要求用户把插件提交到咱们指定的git repo。而后agent每隔一段时间去git pull这个git repo,采集脚本就完成了分发。

 

而后咱们在server端提供一个配置,哪些机器应该执行哪些插件,经过hbs把这个信息分发给agentagent就能够去执行了,脚本按照一个什么周期去跑呢?这个信息写在脚本的名称里,好比60_ntpoffset.sh60表示60s执行一次,agent经过对脚本文件名的分析,能够得知执行周期。

 

执行周期也能够在server端配置,均可以,咱们是放到文件名里了

 

脚本执行完了,把输出打印到stdoutagent截获以后pushserver。插件的升级、回滚,就是经过git reposerver端的配置来完成。

OK,数据采集就说这么多,真的是又臭又长,哈。咱们回到系统设计阶段,看还有哪些点值得分享一下。

 

1. tag的设计。这个要好好跟大伙说说。这个设计灵感来自opentsdb,咱们说监控数据有不少,若是对每条监控项都配置报警,是一个很繁重的工做量。那咱们可否经过某个手段来对采集项作个聚合,一条配置能够搞定多个监控项?

举个例子,好比某台机器有多个分区:

/

/home

/home/work/data1

/home/work/data2

/home/work/data…

/home/work/data12

 

咱们想配置任何一个分区的磁盘剩余量小于5%就报警,怎么办?上例中,假设咱们有12块盘,加上/home分区和/分区,就有14个采集项,写14条策略规则?OMG……

这个时候tag机制就派上用场了,采集到的数据在汇报的时候,每条数据组织成这个样子:

{

"endpoint": "qd-sadev-falcon-graph01.hd",

"metric": "df.bytes.free.percent",

"tags": "fstype=ext4,mount=/home",

"value": 10.2,

"timestamp": 1427204756,

"step": 60,

"counterType": "GAUGE"

}

上面表示qd-sadev-falcon-graph01.hd这个机器的/home分区的磁盘剩余百分比(df.bytes.free.percent

再举个例子

{

"endpoint": "qd-sadev-falcon-graph01.hd",

"metric": "df.bytes.free.percent",

"tags": "fstype=ext4,mount=/home/work/data1",

"value": 10.2,

"timestamp": 1427204756,

"step": 60,

"counterType": "GAUGE"

}

metric(监控项名称)是相同的,只是tag不一样,不一样的tag表示不一样的挂载点。这样一来,咱们就能够这么配置策略:说,对于某一批机器而言,df.bytes.free.percent这个采集项,只要value<5就报警。咱们没有配置tag,那么这14个挂载点的数据都与这个策略关联,一个策略配置,搞定了14条数据。还有好比网卡也能够用相似的处理方式。

上面的例子还没法彻底体现出tag的威力。咱们再举个例子,说一个业务监控的例子。小米的好多服务都是java写的,有个团队依据open-falcon提供的接口规范,写了一个通用jar包,全部thrift中间层服务,只要引入这个jar包,就能够自动采集全部rpc接口的调用延迟,因而,产生了N多这样的数据:

{

"endpoint": "qd-sadev-falcon-judge01.hd",

"metric": "latency",

"tags": "department=sadev,project=falcon,module=judge,method=com.mi.falcon.judge.rpc.send",

"value": 10.2,

"timestamp": 1427204756,

"step": 60,

"counterType": "GAUGE"

}

 

插一句:业务代码中嵌入监控采集逻辑,目前咱们的实践来看,真的很好用,嘿

若是咱们这么配置:latency/department=sadev all(#2) > 20就报警。就意味着对sadev这个部门的全部rpc接口的latency都作了策略配置。覆盖了N条监控数据。怎么样?有那么点意思吧?

说白了,tag就是一种聚合手段,能够用更少的配置覆盖更多的监控项。

OKtag的设计就讲这么多。下面咱们说说模板继承。zabbixhost有一个扁平的group来管理,模板是没法继承的,这个让咱们的管理很是不方便。举个例子。

 

sadev这个部门的全部机器能够放到一个group,配置load.1min大于20报警,sadev这个部门下有不少项目,好比falcon这个项目,falcon这个项目总体使用机器资源比较狠,因而配置的load.1min大于30报警,falcon这个项目下有不少模块,好比graph模块,graph的机器负载更重,正常的load.1min都是35,咱们但愿load.1min大于40报警。因而问题来了

 

qd-sadev-falcon-graph01.hd这个机器是graph的一台机器,它应该处于graph这个组,天然也应该处于falcon这个组和sadev这个组,因而,这个机器与三个模板都有绑定关系,load.1min>20的时候报一次警,>30 >40的时候都会报警,这显然不是咱们须要的。

 

模板继承能够解决这个问题,graph.template继承自falcon.templatefalcon.template又继承自sadev.templatesadev.template中配置各类经常使用监控项,好比cpu.idle < 5报警,df.bytes.free.percent < 5报警,load.1min < 20报警,falcon.templategraph.template中只是load.1min比较特殊,那就只须要对load.1min配置特定的阈值便可。如此一来,graph的机器只有在load.1min>40的时候报警,>20的时候>30的时候都不会报警,你们理解一下。

 

模板的思考就讲解到这里。下面说说这个机器分组的问题,open-falconzabbix同样,都是使用扁平的分组结构。这种状况有个问题,就是机器的维护不方便,好比上面的例子,咱们graph机器要扩容,须要把新扩容的机器加入graph这个组,同时也要加入falcon这个组,加入sadev这个组,比较麻烦。

 

因此小米内部的实践方式是与内部的机器管理系统相结合,那是一个树状的结构,机器加入graph中,也就自动加入了falcon中,自动加入了sadev中。你们若是要在公司内部引入open-falcon,最好也要作个二次开发,与本身公司的CMDB、服务树、机器管理之类的系统结合一下。

 

那这里有一个点,好多公司把机器管理、服务树、CMDB这种管理机器的系统作成树状结构,缘由何在?部署系统有这个需求么?部署系统的最小部署单位一般是模块,一个模块所在的机器彻底能够放到一个扁平的group中。树状结构不是部署系统的需求,而是监控系统的需求,监控系统一般在一个大节点上绑定一些经常使用的策略配置,而后在小节点上绑定一些特殊的策略配置,相互之间有个继承覆盖关系。好多人不理解这个树状结构的设计初衷,个人理解就是这个样子的,不必定对哈,我的观点而已。

 

咱们继续往下讲:架构设计的习惯性

 

这个阶段有哪些脑洞历程呢?首先,监控系统的数据量估计是不小,你看一个zabbix都扛不住对吧,哈哈……并且没有高峰低谷,周期性的,每时每刻都有大量数据上来。那第一反应是什么?

 

没错,上集群!一台机器不管如何都是搞不定的,那就必需要搞多个机器协同工做。

 

监控系统的本质,在我看来就是采集数据并作处理的一个过程。处理方式最重要的有两种,一个是报警,一个是存储历史数据。这两个处理逻辑差别比较大,报警要求速度很快,尽可能在内存里完成;存储历史数据主要是写磁盘,读少写多。

 

那最直观的思路就是把报警作成一个组件,把数据存储作成另外一个组件。先说存储,以前说过,咱们内部有个perfcounter系统来存放performance数据,这个系统是用rrd来存放的数据。架构设计的习惯性,让咱们再次选择使用rrd来作存储,毕竟rrd是不少监控系统的存储介质,随大流,问题不大。

 

rrd是本地文件,一台机器的磁盘容量或许能够搞定监控系统的全部数据,可是IO确定不够,perfcounter当时用了5台机器,所有都是ssdraid10IO仍是比较高。因此,要搞多台机器来存放rrd文件,每台机器只处理一部分,压力就小了。

 

因而,咱们习惯性的使用perfcounter采用的一致性哈希算法,来对数据作分片。数据分片一般有两种方式,一个是使用算法来计算,一个是在中心端记录一个对应关系。监控系统的量会比较大,若是要使用对应关系,还得维护一个存储,当时我我的实际上是主张使用一个存储来存放对应关系的,可是团队其余成员都以为略麻烦,就放弃了,直接使用一致性哈希来计算对应关系,架构上显得简单很多。

 

你们应该知道,使用算法来计算对应规则,会有一个比较麻烦的问题,就是扩容,一旦扩容,一些原本打到老机器的数据就会打到新机器上,虽然一致性哈希的算法会使迁移的量比较少,可是仍然不可避免会有数据迁移。这个问题怎么办呢?

 

分享一个观点:遇到一个比较棘手的技术问题,若是能在业务层面作规避,将是最省事的。因而咱们就想业务上可否接受数据迁移时候的丢失呢?说实话,不太容易接受,能不丢,尽可能仍是不要丢。

 

因而咱们退一步,扩容的时候,咱们不是立马迁移到新机器列表,而是先作一段时间的migrating,好比作一个月。这样一来,扩容以后,对于每一个监控项仍是会有至少一个月的数据,这样用户是能够接受的。

 

说完了存储,咱们再来讲说报警。报警数据要求的历史点数比较少,好比咱们一般会配置说某个机器的cpu.idle连续三次达到阈值就报警,这里的“连续三次”就意味着,只要有最近三个点就能够搞定用户这个策略。数据量少,可是访问频繁,由于每一个数据上来,都有可能找到其关联的策略,都须要拉取其历史点作判断,这样的场景,没啥说的,用内存吧。

 

咱们把用来处理报警的这个模块称为judgejudge会有不少实例,当时想,某个实例挂了或者重启都不该该影响正常的报警,为了可以水平扩展,尽可能作得无状态,那历史数据就不能存在judge的内存里了。redis吧,有名的内存nosql。因而咱们就一次性上线了一堆judge实例,前面架设lvs作负载均衡,数据使用redis存储,走起。

 

稍总结一下,对于server的数据处理,这个属于产品实现细节了,咱们由于团队人少,刚开始只有俩人,后来三个,因此力求简单,粗暴的解决问题。数据经过一致性哈希对rrd作一个分片,确实能够大幅缩减开发时间,不过也存在一些问题,你们发现问题在哪里了么?

下面咱们先说试用以后立马发现的问题。

 

当时初版上线,用了7台机器56redis实例,给judge存放少许历史数据,发现每一个redisqps都是4K5K的样子,初版只是部署了少许agent(具体的量记不清了),结果qps就这么大,当时agent比较少,redis的压力让咱们不能接受。

怎么办?你们有思路么?

 

外部内存的速度若是跟不上,那最直观的想法就是使用进程自身的内存,这里也就是judge组件的内存。那若是用了judge的内存,judge就有状态了,就没法水平扩展了呢。

 

仔细想一想其实问题不大,judge使用内存的话,仍然须要使用算法作分片,既然绘图组件用了一致性哈希,那能够复用一下。同一个监控指标的数据,当前这分钟上来的数据打到某个judge,下一分钟上来的数据,一样应该打到这个judge,一致性哈希能够作到,没问题。

 

每一个judge实例只处理一部分数据,好比50w,放到内存里量也不大,只是GoGC不知道好很差用,若是GoGC很差用,咱们就在单机多搞一些judge实例,作进程级隔离,先想好退路,呵呵。

 

judge是数据驱动型的。就是说,数据来到我这个实例,我就去处理,数据没来,我就不处理,judge前面有个组件叫transfer来作转发,作一致性哈希计算,能够保证数据分发规则,看起来都没啥问题。最惹人烦的是什么呢?是judge重启,你们能够想一想judge重启会带来哪些问题

 

judge一旦重启,就丢掉了历史数据,好比用户配置说某个机器的cpu.idle连续3次达到阈值就报警。前两次都达到阈值了,而后,而后judge重启,这俩点就丢了。judge重启完成,又上来一个达到阈值的新点,已经知足连续3次达到阈值了,可是,却没法报警。若是后面继续有两个点达到阈值那还好,仍是会报警,若是后面的点都正常了,那此次本该有的报警就永远都不会报了。

 

这个问题业务上能够接受么?好吧,咱们又来问业务了。首先,judge重启的概率比较小,只有升级的时候才会重启,代码写得注意一些,理论上是不会挂的;再一点,机器一旦出了问题,若是sre不介入处理,一般采集到的点都是持续性达到阈值,因此老是会报出来的,不然基本就能够不用关心。

 

这么看来,这个改造是能够进行的。因而,代码开始重构,上线以后效果大大好转,处理能力是原来的8倍左右。

原本想单开一节来讲说一些折中考虑,发现折中都穿插在前面讲完了,那咱们就再也不单独讲系统的折中处理了。

 

时间已经比较久了,其余一些小的点咱们就先不讲了,最后咱们说说系统的问题以及将来的改造。

 

最大的问题是什么?相信你们已经想到了,就是每一个graph(绘图组件)实例都是单点。若是某一台绘图机器磁盘坏,那这部分数据就丢了。怎么解决呢?

 

最简单的,硬件解决,咱们每一个机器都是ssdraid10,稳定性比较高。而后,咱们作了一个双写机制,可是如今的绘图机器IO已经比较高了,再搞个双写,势必要加机器,老板最近又在搞什么控制成本云云,就算了吧。监控数据虽然不是丢了会死人那么严重,可是若是不解决仍然让咱们如鲠在喉。

因而,咱们开始求助于一些分布式存储,咱们作数据分片,作双写备份,很大程度上其实就是在解决分布式存储领域的问题,那咱们为何不直接使用分布式存储呢?

 

opentsdb,嗯,看着还不错,就是用来存放时间序列的数据。咱们组一个同事聂安对opentsdb作了一些调研,以为不能知足需求,两点:1. opentsdb不提供归档,要查看一年的历史数据,opentsdb就真的去把一年的全部点load出来,速度慢不说,浏览器非卡死不可; 2. opentsdbtag数目限制,tag数不能多于8个,但咱们在用的过程发现,好多业务数据的tag都是910个,无法减小。

 

你们看rrd的时候顺便看一下它提供的归档机制,很强大

 

经过改代码,或许能够调整tag数不能多于8个的限制,但性能可能会急剧降低。另外在很早的时候,同事来炜曾简单尝试过opentsdb,当时只用了10来台opentsdb前端,一打就挂一打就挂,多是咱们机器用的太少,也多是某些参数没有作调优,时间关系,当时没有深刻去研究,可是先入为主的以为opentsdb不够强。再加上聂安此次调研,咱们最终就放弃了opentsdb

 

小米有好几个hbasecommitter,团队强大,咱们如今准备直接使用hbase作存储,云存储团队给咱们技术支持,本身作归档,用hbase作后端,实现一个分布式rrd。目前基本开发完成,测试中……若是OK的话,之后就不用担忧graph单点数据丢失的问题了。

 

第二个问题:agent挂了无从知晓

 

这个问题的本质实际上是一个nodata的需求,也就是数据多久没上来应该有个报警机制。开源版本的open-falcon目前没有提供解决方案。应该如何设计这个nodata组件呢?

 

nodata组件的开源工做应该正在进行中

 

咱们仍是不但愿改变用户的使用习惯,好比如今每一个agent每一个周期都会push一个agent.alive=1的数据,用户只要在portal上配置说all(#3) agent.alive != 1就报警。若是没有nodata组件,这个策略是无法工做的,由于agent挂了,不会有agent.alive=0的数据上来。那咱们只要写一个组件,在发现没有agent.alive数据的时候就自动push一个agent.alive=0的数据不就能够了么。

 

O了,这就是nodat组件的工做逻辑,咱们能够配置一些关键的指标的default值(当server端发现没有对应数据上来的时候,就自动push一个default值),注意,这里只是配置了一些关键指标,不是全部指标都配置,若是全部指标都配置,工做量不可接受,并且也不必,好比agent会采集cpu、内存、磁盘、io等不少数据,咱们不必为这些数据都配置default值,只要配置agent.alivedefault值是0,就能够了,就能够监测到agent是否挂掉。

 

最后一个问题:如何处理集群监控

 

好比咱们有一个集群,挂一两台机器没啥问题,可是挂的机器超过10%就有问题了。另外一个例子:咱们有个集群,失败请求率小于5%没有问题,大于5%了就要尽快接入处理了。

这种从集群视角去判断阈值的情形,应该如何支持呢?

 

这个问题若是从简单着手,能够直接作成:对一批机器的某个指标作一个相加。好比某集群有30台机器,要对集群的总体错误率作一个统计,只要每台机器都计算一个本机的错误率:query_fail_rate=query_fail/query_total,而后把全部机器的这个query_fail_rate相加求平均便可。

 

可是,这样作显然是不太准确,更准确的作法应该是把全部的query_fail相加,把全部的query_total相加,而后作除法。

 

因此最后能够抽象为一批机器+一个除法表达式。一批机器就是指某个集群的全部机器,一个除法表达式,在上例中,其分子是query_fail,分母是query_total。集群指标聚合的这个组件姑且称之为aggregator,这个aggregator组件获得机器列表和分子、分母以后,就能够去计算了。把每一个机器的query_fail查询到并所有相加,把每一个机器的全部query_total查询到并所有相加,最后作个除法便可

 

这种作法是否能够解决集群机器挂的数量达到某个值就报警的需求?没问题的,分子是agent.alive,分母是机器总量,好比30(这个能够动态计算),agent.alive正常来讲都是1,若是挂了就是0(咱们的nodata组件的成果),好比有3台挂了,分子之和计算出来应该是27,分母是3027/30<90%? 符合阈值就报警。

 

这种抽象看起来问题不大,最后一点要说明的是,aggregator模块去计算的集群聚合结果应该是每一个周期都要计算,计算结果要从新pushfalcon,这样这个集群的聚合结果就能够像一个普通的监控项同样,能够用来绘图,能够用来报警。

 

OK,已经挺长时间了,整个open-falcon的脑洞历程就讲解这么多,但愿对你们有帮助,谢谢你们。

 

Q1 elk或者stasdgraphite比是否使用方便

A1. 这个方便程度很难讲了,falcon侧重的是作一个监控框架,归入各类数据,而后作好报警,还有历史数据归档,和elk之类的可能目标不是彻底一致,不是一类产品

 

Q2. 最后说的 求 集群监控 query_fail_rate 的部分应该也会有 单点问题的吧、怎么规避的呢

A2. aggregator模块的确是会有单点问题的,目前尚未去解决,能够作个选主之类的逻辑,多个实例一块儿上,可是每次只有一个主在工做

 

Q3.我想请教一下,open-falcon将大多数监控处理放到了agent,部署升级得关注版本一致性,若是使用snmp协议监控资源,服务端每次采集资源时经过gogoroutine并发采集入库,资源报警和其余程序经过trap反馈给服务端,感受是否会更方便一些,问的比较弱,见笑了。

A3. snmp没有agent强大,agent做为一个常驻进程运行在机器上,能够干的事情更多一些,并且snmppullserver端的压力会大一些,处理起来略麻烦

 

Q4.监控在告警时存在误报么、怎么保证每条发送出去的告警都是有用的?

A4. hbs只是用来分发agent要执行的插件、要监控的进程、端口,不作报警相关的处理,这样逻辑结构上更清晰一些:)

 

Q5. 目前业务层也接入了监控系统,会出现监控系统单点故障致使全局的应用所有不可用吗?

A5. 业务系统中嵌入监控的逻辑,就要很当心了,这个监控逻辑不能阻塞主要业务处理,只是一个旁路,一个单独的线程,监控系统整个挂了,不会影响到各个业务:)

 

Q6.监控在告警时存在误报么、怎么保证每条发送出去的告警都是有用的?

A6误报这个是不存在的,都是按照用户的策略去报警,固然,有的时候用户不知道本身的阈值设置多少合适,随便设置了一个,这种状况报的警可能确实没啥用处

 

Q7agent端数据采集点有多少,性能压力是怎样的?

A7. agent在全部目标机器上部署,好比有1w台机器,就要部署1wagent,每一个agent大约采集200各监控项,如今小米的falcon应用状况是每一个周期5000w左右的数据上来,有几十台监控server端协同工做

 

Q8jduge中的transfer作转发,这个是单点处理么?若是挂了怎么办?

A8. transfer只是一个转发组件,是无状态的,transfer挂个一两台没有问题

 

Q9、看到agent运行脚本的时候,采集的是stdout的数据,stderr的数据采集么?若是不当心采集了二进制数据,是怎么处理?不当心调试的时候采集数据量比较大,阻塞了网络的状况有么?

A9. 只采集stdout是一种约定,须要汇报的数据写入stdout,脚本运行出错了写入stderr,若是采集的脚本不能decode成要求的数据格式,直接扔掉。目前没有出现调试的时候数据量大阻塞网络的状况:)

 

Q10agent是打包到大家的镜像文件中,系统安装完后自动启动,而后上报么?若是是这样,那么何时填写的服务器地址?

A10. 咱们的系统由系统组统一装机,而后统一初始化,初始化的时候安装一些基础组件,agent就是在这个时机安装,以后各个业务线再作针对本身业务的初始化工做:)

 

Q11. 有没有相应的监控报表之类的?是否能够对接kibana

A11. 如今基本没有报表性质的东西,只有趋势图,针对各个监控项的历史趋势图。哦,还有一个未恢复的报警列表,各个产品线工程师能够在下班的时候看一眼这个未恢复的报警列表,看是否有忘记处理的。其余就没了,不懂kibana:)

 

Q12 如此多的监控项和图表如何展现,如何快速找到须要的东西

A12. 通常咱们要看什么数据是有很强目的性的,好比某个服务挂了,你可能要看这个服务所在机器的状况,因而就能够拿着机器名之类的去搜索,也能够根据metric(监控项)去搜索,等等。也能够提早作screen,把常常要看的图表放在一个页面

 

Q13是否有监控到异常,而后自动对服务器进行后续操做的?

 

A13 有的,异常了以后一般的处理是报警,也能够回调一个业务的接口,把相关的参数都传递个这个接口,用户就能够在这个接口中写本身的业务逻辑,好比去重启某个机器

相关文章
相关标签/搜索