所以要紧的应该是有一个针对业务的,能反应业务状况的监控。但是这些,都意味着需要有比较好的技术掌控力。上tracing需要改代码,改代码,改代码……有些APM可以说hook了底层函数,减少上层业务的代码改动,不过这个掌控力的要求更高了。
如果找第三方呢,又会有额外的一些担心,毕竟自己不可见也挺为难的,偏偏这方面的开源项目又出奇的少。
所以折中一下,还有一种方式:技术难度没那么高,安全性上又放心的就是老老实实打日志。全面一点的话,可以说从前到后都可以打日志。页面埋点可以出日志,服务器访问肯定有日志,业务逻辑可以出日志,跑业务的PHP-fpm、tomcat、rails,再往后的数据库啊,缓存啊,各种后端集群啊……默认也都是有日志的。
因为日志本身有append的特性,所以打日志对业务应用的IOPS影响也小。应该说开发们应该或多或少都是有这个习惯的,从这里入手,对于业务运维也是最方便。
不过通过日志来获取整个系统的状态,也是有难度的。传统方式下,运维是怎么用日志的?SSH上服务器,然后cat | grep | awk | sort | uniq | less.
因为日志在服务器上存储的时候,一般是按照天去rotate的,如果要排查一个三五分钟的问题,比如早上看下报表,发现『昨晚 23:12 到 23:29 那会儿有个小坑,找找问题吧』,如果预定思路都没有,从几个方向试一下,这个文件就被一遍又一遍的cat全文再grep那几分钟……当然对于比较小的文件有OS的VFS cache可以帮忙——但是如果这个事情放到服务化场景下,要横跨十几台服务器上几十个文件呢?运维一天可能也就够干这一件事情了。
上面这个举例,其中难点,文件大、跨服务器,这都不是最难的。最难的是因为你不知道问题在哪,所以你要尝试各个方向都先找找。这就是定点采样的监控系统、离线分析的Hadoop系统都比较难搞的地方了。
这两种方式都要求你有规划好的逻辑、规则了,然后去编码,固化下来。但是很多业务运维的工作是“我知道有问题,我知道问题原因一定在这堆数据里,但是我现在也不知道在哪。”
所以需要一种可以随时让我们修改规则、实时反馈数据结果的方式,才能真正的简化在服务化场景下的业务运维工作。
02/日志搜索引擎的实践分析
前两年我在微博做架构师,最终就选择了通过日志搜索引擎的方式来简化我们团队、乃至我们对口的研发团队的苦逼工作。开源社区对应这个方式,有一系列开源项目,合称叫ELK Stack。
比如监控系统,大家都知道时间序列趋势是最重要的。这是防火墙之父说的一条法则。
但是通过日志搜索引擎出来的时间序列效果会更特殊一点。上个图:
这些趋势图是从哪来的呢,从微博PHP记录的日志里:诈一看好像我们上个storm实时计算这些数也行啊,为啥用了个没那么有名的东西呢?奥秘在上面截图的顶部那堆小白框里。
我再放大了单独截取一下这些小白框:这里每个框,都是一个搜索框。搜索框跟下面的图表,是多对多的关系。
那么只需要在某个搜索框里,填一个关键字,或者复杂一点点的语法,比如request_time:>100 AND backend_time:<10,也不是太复杂的语法,一共也就几种。敲下回车,下面对应的图表,立刻就会同步更新结果。
这个结果,是实时的。也就是说,你设置时间是now-1h TO now,那就每次搜索都是反馈到最近的结果。
比如你一个网站,有 2000 个接口,常见的状态码有 6、7 个,客户端平台版本也有 6、7 个,机器上千台(嗯,这既是微博的状态)。如果通过传统预先定义的方式做监控,这就是好几千万个metric了,怎么可能搞得完。而在这个系统里,就是一份日志,随时可以换逻辑看结果。
上面这个例子,还是在时序趋势图的范畴呢。其实做数据分析还会有很多别的可视化方案。下面还是拿PHP说,另一个做运维的时候其实应该很关心的日志,PHP的slowlog是这个样子的。可能很多人其实平常就没把这东西放到监控系统要考虑的范畴里,就是等到业务已经出问题了才上去看,其实slowlog能预知到不少情况的。
当然如果只是说时序趋势统计,那么slowlog你就只关心一下堆栈最底下那个函数就是了。
但是我们有另外一个方式: 这个仪表盘上三张图,不多~但是顶上这张就很有趣了~~其实是把整个slowlog的堆栈完全都处理出来,而不单是最底部的:那么我们对每一层的函数,做一个堆叠式的统计,然后做一个千层饼式的可视化,就不单单知道那个函数最慢,还能知道哪个请求链受这个影响最大了。比如这个示例里,就可以看到微博最慢的处理是往推荐平台后端做curl请求。
按说机房这个维度,对于微博这个服务化的场景,影响应该不大。哪个机房这个效果应该都类似才对。但是截图里可以看到有一张饼图,明显杂色比别人多蛮多的。那么我们看看下面的图表,时间趋势图上,也是按机房划分,似乎又看不出来什么异常。再看看主机统计表格。top10里,9个是yhg机房,唯独一个是xd机房的主机,那问题就比较集中了。
现在做一步:点击这个xd机房的主机名。页面变成这样了: 整个页面都变成只针对这一台主机的情况了。时序趋势说明这会儿这台机器确实slowlog涨幅很大。(虽然在整个机房里显不出来)
不过这没什么。要点在上面的饼图。这个分布跟之前差别就太大了。鼠标挪上去看看堆栈情况:占比最大的堆栈请求链,变成了链接memcached时,需要的gethostbyname()函数太慢。
这下问题就清楚了。
最后我们另一位同事上去大概花了几分钟,strace跟了一下,定位到dnsmasq的cache容量不够,所以会不定期的域名解析缓存失效,导致服务抖动。
这个问题,其实会影响到整个服务的SLA的。(可能平均时间上反应不出来,但是我们SLA是按百分位时间来定,这种解析超时反应到SLA上就是蛮头疼的总有一些人响应快不了了)
如果按部就班的查问题,时间花费太久,但是通过日志搜索统计,前后加起来不到半个小时。整个一套下来,一点代码没写,当然也有配合devops进程写代码的时候,是另一个场景:app发版,需要特别关注crash。
crash的日志也是汇报上来的。这种大crash在页面上看当然可以。不过我们不仅仅满足于此了。因为这个模式是比较固定的。那么就花了几十行代码,固化一下,把新出现的appversion和新上量的crashlog函数堆栈,直接同步到jira上,由QA去分发到人。
因为ES引擎是RESTful接口,所以这固化逻辑的代码基本就是拼JSON。
说到固化DevOps的逻辑成代码。DevOps文化其实强调一点,其他部门也要参与~我们这个系统出了业务运维和研发,其实包括客服也是在使用了:
对业务的最终用户反馈,投诉报错,先由客服人员在系统上过一遍,根据 uid 搜索,一下子就知道这个投诉过了哪些关,触发了哪些报错。客服当然不知道这意味着啥,但是她联系开发或者运维,告诉对方啥问题的时候,就明确多了,这也是一种提高DevOps效率的途径。