写代码的人都知道日志很重要,机器不多的时候,查看日志很简单,ssh 上去 grep + awk + perl 啥的 ad hoc 的搞几把就行,但面对上百台甚至上千台机器时,如何有效的收集和分析日志就成了个很头疼的事情。日志处理必然有如下过程:
- 从各个服务器读取日志
- 把日志存放到集中的地方
- 挖掘日志数据,用友好的 UI 展示出来,最好能做到实时的输入表达式做过滤、聚合
下面分三个方面聊聊,整个过程是需要多方配合的,包括写日志、读日志、转储日志、分析日志,注意聊这些的背景是互联网行业,机器多,日志多,服务质量对机器负载和带宽消耗很敏感。最后再简单介绍下 Splunk 这个牛逼的商业软件。
一、读取日志
这个事情猛一想是很简单的事情,scp、rsync 一下不是很简单么,但是要想做细致了还是很有嚼头的:
- 写日志一般会先写到一个固定文件,到了一定大小或者某个时间会关闭文件并改名,然后有某个定时任务在后台以很低的进程调度优先级以及很低的 IO 优先级对其压缩(不在写日志或者更名时直接压缩是为了避免影响提供服务的那个进程的性能,尤其是在 log 写速率很快时),这种情况下显然首选读取压缩过的日志文件以节省带宽以及压缩的开销
- 上面这个方式是批量的,有延时,比如每小时压缩一次,那么有一小时的延迟,如果线上突然出问题了,运维人员打电话催着调查,咱不大好说“等会,日志还没出来呢”,批量方式适合研究后台算法的人员分析日志,对于开发人员来说往往需要实时日志收集,实时收集有两种,a) 应用直接支持通过网络发送日志的方式,b) 应用通过某个代理服务发送日志,比如 rsyslog 和 syslog-ng,通过管道发给 netcat 什么的,或者写到磁盘上,再用 tail -f 或者类似原理的工具不断读取并转发出去。实时日志收集看起来很美好,但实现是相当麻烦而且有风险的,如果应用自身不是直接写磁盘,那么网络和管道可能导致应用写日志阻塞,这时的解决办法往往会想到异步记录日志,但异步记录日志实现变复杂而且还要担心异步那个线程能否及时刷出日志,还有转发的那个进程是否性能够好而且够稳定。
- 读取日志的那个进程如果崩溃了,怎么恢复呢?对于批量收集,需要记录一个状态表明某个日志文件是收集过了,这个是很好实现的,断点续传也可靠,因为那个日志文件不会被修改或者重命名,而对于实时收集,syslog 那种那就只能是丢了就丢了,对于 tail -f 的做法,需要记录读取的偏移量,以及小心处理日志文件写满后被改名的状况(这个问题可以用一个粗暴的办法绕过去,就是收集完日志后去掉重复的,在读取日志和存储日志时多了点开销)。这个地方是需要读写日志双方合作的,单个日志文件多大(太大了失败重传开销大),什么时候滚动日志,日志名字规则,放在什么目录下面,等等。
- 除了批量和实时的区分,读取日志还分 push 和 pull 两种模式,模式的区分是看哪方发起的日志读取。push 模式的主要问题是带宽消耗不大容易控制,pull 就很简单了,收集日志的服务器一个个机器的轮流收集就好了,对于批量收集,最好用 pull 模式,因为批量收集是突然消耗大量带宽传输一个打包的大文件,很有必要控制带宽,而对于实时收集,很自然是 push 模式了,但其实有时也是可以用 pull 方式的,比如 "ssh HOST tail -f /some/log",收集一端衡量带宽分配。pull 模式需要注意一点,如何让多台 log collector 机器不要同时去收集同一台机器,这个地方主要是为了控制带宽和对目标机的性能影响。
- 收集日志脚本在读取一个文件出错时会跳过剩下的文件还是会继续收集下去?后一种方式是推荐的,否则磁盘一旦坏了一个文件,除非人为干预,就永远收集不了其它文件了。
- 写本地文件还是直接通过网络发送出去?我个人是推荐直接写磁盘的,一是磁盘比网络可靠,二是磁盘上缓存一份方便 ad hoc 的 ssh 上去查看一把,用 tail -f 还可以实现近乎实时的日志收集,三是实现简单,有哪个程序员不懂往磁盘上写日志么?
- 真的需要实时收集吗?其实,我个人觉得只有在开发的时候需要实时收集,能很方便的实时看到各个子系统的错误日志,上线之后运维人员有实时的 monitoring 系统,这个针对性更强,传输数据量很小,日志还是数据量太大,拿来做 monitoring 用途简直就是偷懒。而到了发现问题、联系上人员、开始调查,往往一小时过去了,批量收集的日志已经到位(对于实时分析用户行为来说,实时日志收集很有意义,这时日志的作用不是为了调试问题了)。
说的很复杂的样子,总结一句,我个人是觉得记日志到本地文件,然后 log collector 机器定期的主动 pull 日志文件是综合来说最优的日志收集方式。
二、转储日志
日志读取出来了,发到网络上了,被某个收集程序拿到了,然后就需要考虑存储了,在互联网行业呆过的人一开始可能会很意外的发现硬盘居然是如此不靠谱的东西,两三百台机器,三天两头的坏磁盘,搞的都让人怀疑是不是采购硬盘的家伙搞猫腻。存储可靠性是一个问题,安全性也是一个问题,有时候日志里包含敏感信息,或者日志存储只允许接收某几台机器的写入,这时候就需要有日志转发了,对于写日志方不写磁盘直接往外丢的实时收集,还需要日志转发方缓存一下,以应对远程日志存储暂时失败的情况,这时候其实就又出来了上面读取日志的许多挠头问题——日志收集真不是个看起来那么简单的事情啊!
虽然日志往往是个丢一点也无所谓的事情,但能不丢自然最好,而且分析日志往往会用到 Hadoop 的一套工具,所以用 HDFS/HBase 做日志存储是相当直接的做法,这一套可以参考 Facebook 的复杂日志收集、存储、分析流程:http://www-conf.slac.stanford.edu/xldb2011/talks/xldb2011_tue_0940_facebookrealtimeanalytics.pdf,从这里可以看到实时事件流处理的整个过程真是叫处处头大如斗!所以上“实时”系统之前,扪心自问一下,真的有必要吗?十分钟级别延迟够么?一分钟级别延迟够么?盲目的把所有日志收集做到秒级别延时是超级浪费的事情。
写的太长了点,总结一下,可靠的实时收集是很困难的,可靠的批量收集容易的多的多的多。。。。从被收集机器批量读取日志,通过网络发送到日志收集服务器,不经过磁盘,直接再次通过网络传到 HDFS 或者 HBase,这个流程容易实现而且很可靠,可靠性是通过重复运行修复失败达到的,前几天我就整了个两百行的 Shell 脚本做这个事情。
三、日志分析
数据就位了,浩如烟海,想查点东西就得有好用的日志分析辅助工具,不能有需求了就临时凑一段 hadoop M/R job 等半天才能得到结果,做日志分析需要做这些事情:
- 解析原始日志格式,分解成有意义的字段,有的 log 收集方案在第一阶段就解析日志只发送关心的字段,以节省带宽。
- 根据时间戳,request ID,session ID,user ID 等关联日志条目,以尽量清晰当时各个子系统的状态;
- 根据分析的目的做过滤、聚合、统计等等,最后整一份漂亮的报表出来。
这三个步骤往往是需要不断反复以得到理想结果,所以有一个实时交互系统是很方便的,这也是为什么大多 log 收集方案最后总会牵扯进 MySQL、ElasticSearch 之类的东西,尤其是 ElasticSearch,简直是搞搜索的狗皮膏药,其 percolate 特性相当有创意。另外,交互系统自然有个实时的图形显示就更直观了,比如显示某个时间段某个用户的访问模式,某个错误的出现模式,等等。
一不小心,又啰嗦了很长的一篇,最后聊一下牛逼的商业日志解决方案 Splunk,它牛逼的地方在于上面第三点,对于第一点和第二点我觉得没啥惊奇的,甚至不是很强悍,比如貌似并不直接支持带宽控制。在日志分析方面,其 Web UI 做的相当出色,第一,它的 web 应用是插件模式的,可以往里头加入很多第三方的插件,技术上没啥惊奇,跟 Tomcat 里跑多个 servlet 似的,但产品思路很好的,把日志分析这种通常觉得是很零碎的活拔升到一个平台高度了;第二,我也不知道是不是它首创,其搜索界面有一个时间轴的图,可以实时的显示搜索结果的分布,比如最近几天的 HTTP 503 错误出现频率,比如最近几天某个 user ID 的访问频率,注意搜索条件是可以非常复杂的,不只是关键词搜索,所以用下来颇有 data insight 的感觉,这个图是会根据数据量和时间范围自动缩放的,技术上不惊奇,但从产品设计上讲是很赞的;第三,并不要求用户一开始就定义日志格式,伊会自己猜测,比如 url 里的 name=param,日志里的 key=val,等等,猜测的还是八九不离十的,猜测不准的地方伊的 UI 上可以支持定制,不用写配置文件,这个地方的 UI 设计也很赞,大家有兴趣可以去下载下来试用下;第四,伊的搜索语法很强大,内置了很多函数,不知道是不是借了 Lucene 的东风,更牛逼的是伊的管道符可以把搜索结果送给报表系统,报表系统很美观很强大,不愧是商业软件,第四,伊支持流式搜索(类似 ElasticSearch 里 percolate 特性),所以伊顺势就支持了 alert,一旦日志符合某个条件,就发个警报出来。
说了 Splunk 不少好话,现在说说坏话。
首先,这玩意真不便宜,它有两部分费用,一次性收费,按每天的数据量计算,比如一天 1GB log,那么要一次性给一万美刀,一天 1000GB,一次性要给 120 万美刀(数据量大有优惠),然后是每年的费用,按一次性费用的 20% 收取,虽然我觉得其 Web UI 做的很棒,但我还是觉得这钱花的真心疼,自己整个 UI,糙点就糙点,能有百分之七八十的功能就行了,而且 UI 上一些很友好方便的东西,对于 coder 来说也不过是浮云,自己定义配置文件,写点统计脚本,不是啥吓人的事情,分析日志本来就不是指望 manager 上去点点鼠标就能搞定的,splunk 的那套搜索语言还是需要花点力气学习的。
其次,这东西的日志收集并不是特别有创意,甚至可以说不是很强大,如果主要需求就是收集日志供 Hadoop 上的任务分析,不需要实时的日志搜索和报表,那么也没必要花这么一大笔钱,简单需求可以用 Graylog2 以及 logstash 凑合凑合。