对一个日访问量达数亿次的网站,做web访问日志的实时分析(注意:是实时分析,即每个请求参数均需在秒级时间内被统计、分析和显示),听起来简直就是“Impossible mission”。但是运营部门需要,无奈硬着头皮接下来,本以为一定要用C来写才能达到要求(至少是其中最关键的环节),但是没想到仔细分析之后,竟然完全用php和mysql解决了,再次印证了它们的强大——要是你发现你写的程序效率不高,那只是你的思路和做法问题,和php无关。
我仅仅举一个某个运营节点上的例子描述一下这个系统。
该节点是由10台cache服务器构成,在这10台服务器上的squid+lighttpd承受了来自网上每天5亿多次的请求,一台服务器1秒钟产生上千条的combined格式日志数据,要详细分析ip、路径、来源、浏览器等等,注意,还要实时。
我的做法是——
先把这些cache服务器租车个内网(还好一台服务器至少有两个网口),然后加入一台日志分析服务器到这个内网中,再将每个cache服务器的日志改为网络管道方式发布在该内网上,以供分析服务器建立tcp连接实时取得日志数据;
在分析服务器上,对于每个cache服务器的日志管道单独建立一个进程接收日志(进程调试的时候,打出来看一眼接收数据,好家伙~山呼海啸一样的数据扑面而来!),每条进行简单的拆分直接插入数据库(每个管道单独的一个数据接收表),实践证明,php+mysql没有让cache的日志管道堵塞,运行如飞,还绰绰有余!
接下来,为每个接收进程再建立一个分发汇总进程,负责将同类数据分析汇集到一个表中,比如把所有数据接收表中的独立ip汇总到同一个表中等等,不用说,这个进程的效率更没问题。
然后就是实时运行的统计进程了,每种数据一个进程,比如独立ip统计的ip_stat,点击量统计的click_stat和来源统计的referer_stat等,这些进程都很轻载、出色地完成了任务,延时很短。
这里要注意的问题有——
1、不要在接受数据量大的表上随意建立索引,否则会引起插入进程的低效。
2、分发完和统计完的数据要及时删除,只留下统计结果入库,保证数据库很小(统计了10亿多次,数据库只有50M的样子,还可以吧?要知道每分钟一个cache服务器产生的日志就是50多M)。
3、要建立维护进程的进程,我是用管道建立进程的,然后周期性巡检这些进程是否存活。为了不让这些进程因为管道缓冲区的读写而阻塞,我使用了磁盘文件转向代替了管道缓冲:子进程周期性向磁盘文件追加一个时间戳,维护进程读出之后判断该进程的状态,发现问题就杀死该进程并重启一个。
4、由于数据库经常大规模删除(运行的时候我经常看到接收表中几万条数据瞬间消失),会产生很大的数据冗余,所以要建立一个周期性optimize进程来清理之。
5、一条一条插入数据的效率远远低于一次性插入很多数据的效率。
6、日志每日归档也是确保数据库不增大的必要条件:我是当天保留每分钟的详细数据,次日到一个月之内我就只保留每小时的统计数据了,超过一个月我就记录每天一个数据,这样,数据库始终就那么大。
实际效果:在这个节点上,分析服务器(双cpu/2G内存/SATA硬盘)的效率用上了一半,数据库大小稳定,不会因为分析的数据多而快速增长。
接下来的就是写一个查询日志分析结果的页面了,由于前面的数据分类清晰,所以页面简单而高效,在当日数据分析的页面上,甚至还做了ajax的实时效果,你能看着数据和曲线的实时跳动,真是好玩。
[ 本帖最后由 phpxxx 于 2007-11-2 11:53 PM 编辑 ]
补充一句,之所以不用现成的那几个日志分析器,是因为那些都是事后分析的~
一般来说特殊问题只能自己解决,只有那些通用问题才可以借助现成的系统。
原帖由 uuq 于 2007-11-2 11:59 PM 发表
不归档么.
日志本身不归档,结果归档
原帖由 phpxxx 于 2007-11-2 11:42 PM 发表
在这10台服务器上的squid+lighttpd承受了来自网上每天5亿多次的请求,一台服务器1秒钟产生上千条的combined格式日志数据
原帖由 phpxxx 于 2007-11-2 11:42 PM 发表
对于每个cache服务器的日志管道单独建立一个进程接收日志(进程调试的时候,打出来看一眼接收数据,好家伙~山呼海啸一样的数据扑面而来!),每条进行简单的拆分直接插入数据库
这不相当于每1秒钟有10*1000 同时写Mysql 很不敢相信这样的做法能有多高效原帖由 phpxxx 于 2007-11-2 11:42 PM 发表
在分析服务器上,对于每个cache服务器的日志管道单独建立一个进程接收日志
这也用PHP来解决的吗?原帖由 phpxxx 于 2007-11-2 11:42 PM 发表
6、日志每日归档也是确保数据库不增大的必要条件:我是当天保留每分钟的详细数据,次日到一个月之内我就只保留每小时的统计数据了,超过一个月我就记录每天一个数据,这样,数据库始终就那么大。
这个做得妙..
[ 本帖最后由 风在芯中 于 2007-11-3 10:51 AM 编辑 ]