前段时间部门要我统计各个web应用的请求耗时情况,以便各个组能找出耗时多的功能进行优化。其实这个分析看似比较简单,只要拿到各个web应用的access日志就很容易获得所有请求的耗时。但调查了实际环境以后发现要填的坑还真不少啊。

1.日志位置问题

    每个web应用都部署在不同的机器下,共60多个应用,每个都来一套分析程序?算了吧。。。还是需要运维的配置一个同步,每天把access日志统一放到一个单独的服务器上。

2.日志归档规则

    有的是1天就一个access日志,有的则是一个小时一个access日志,这个也要考虑~~

3.日志格式

    每台应用部署在不同种类的web服务器里(resin,apache,nginx),access日志格式不统一,有的耗时字段在status后面,有的则在最后;耗时项的单位也各部相同,有的是秒,有的是微秒;带引号的不带引号的。。。每种格式写一段分析代码?太累。。。需要建立一个可配置的分析规则。

4.效率问题

    分析的日志量大概每天会有10G左右,用C做?-我不太熟,而且可维护性差点。用Java吧?-我对Java的IO的效率不是很有信心。。。可以用perl啊,脚本语言,内置正则,功能强大,而且有庞大的第三方代码库支持-CPAN,唯一的问题就是我不会perl。。。

把上面问题都搞定的话,做个每天的定时分析程序就OK了。

第一步,先学perl吧。也没找什么书,直接去perl网站下一个perl的解释器,里面就会有完整的tutorial,我完全看的这个,大概1天就会了,之后碰到什么问题直接去tutorial里查一下。perl的解释器流行的有两个,ActivePerl和strawberry-perl,他们的区别就是后面那个除了有perl解释器外,还赠送了很多linux下的基础工具,如make,gcc,如果在windows下开发最好还是用strawberry。学习perl的过程中,发现perl是一个很漂亮的语言,符号多,潜规则多,强大的正则api,使程序写出来很干净,开发速度很快。

第二步,关于日志格式的问题,我找到了一个专门做access日志分析的开源项目-AWStat(version7.0),支持access格式的自定义,仔细研究了一下源代码,找到解析格式的那部分代码-DefinePerlParsingFormat函数,随后我对这个函数做了一下改进,增加了解析耗时项的代码逻辑。其实这个解析的原理就是构造一个大的正则表达式,里面有很多的match group来表示不同的日志项。

第三步,日志位置和归档规则问题,需要设计一个配置文件,将系统名称,日志位置,文件名和归档规则一一对应起来,以便后续可以方便执行日志分析和生成分析报告。这部分偏逻辑性的工作我决定由Java来完成。

至此,整个分析程序的大致轮廓已经出来了,以AWStat项目的DefinePerlParsingFormat函数为基础,编写一个分析单个access日志文件的perl脚本,并由一个Java应用程序来调用,而后者主要负责控制日志分析的过程,采用多线程并发调用perl解释器执行perl脚本来分析多个日志文件,最终汇总分析结果。由于每个perl脚本的执行会在单独的linux进程中,所以对Java虚拟机不会构成压力,Java应用程序可以专注于分析任务的调度以及整理分析报告,这样的架构应该能得到不错的性能。

后续的开发中,我在perl脚本中又增加了mongoDB的支持,为每一个系统的每天日志建立能快速索引查询的日志数据库,但为了性能考虑,只提取access日志中时间,url,耗时几个字段。又顺便加了个内嵌jetty服务器,可以随时查看mongoDB中的日志数据。

这个日志分析程序部署在8核的RedHat上,每天10GB的日志量能在2分钟内完成所有分析并建立数据库,性能上还说的过去。其实更好的解决方案是建立分布式的存储架构,用hadoop来做,但需要的物理机器比较多,目前毕竟给我的资源有限,所以无法实施。

参考实现代码:git://github.com/frozen007/LogAnalysis.git