近期几年日志分析这方面的人才需求越来越多,主要伴随数据挖掘的高速发展而迅速增长的。
碰巧又在工作中又接触到一些日志记录方面的工作。就顺便了解一下日志系统的整个流程。
以下这篇文章转自百度同学的一篇文章,针对大规模日志分析。联系到hadoop,hive的解决方式,阐述的比較全面。
另外就是阿里已经开发出类似的系统odps—通过sql语言进行数据的分析处理,详情见:http://102.alibaba.com/competition/addDiscovery/faq.htm
————————————————————————————————————————
日志在计算机系统中是一个非常广泛的概念。不论什么程序都有可能输出日志:操作系统内核、各种应用server等等。日志的内容、规模和用途也各不同样,非常难一概而论。
本文讨论的日志处理方法中的日志。仅指Web日志。事实上并没有精确的定义。可能包含但不限于各种前端Webserver——apache、lighttpd、tomcat等产生的用户訪问日志,以及各种Web应用程序自己输出的日志。
在Web日志中。每条日志通常代表着用户的一次訪问行为。比如以下就是一条典型的apache日志:
211.87.152.44 – - [18/Mar/2005:12:21:42 +0800] “GET / HTTP/1.1″ 200 899 “http://www.baidu.com/” “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon)”
从上面这条日志中。我们能够得到非常多实用的信息,比如訪问者的IP、訪问的时间、訪问的目标网页、来源的地址以及訪问者所使用的client的UserAgent信息等。假设须要很多其他的信息,则要用其他手段去获取:比如想得到用户屏幕的分辨率。一般须要使用js代码单独发送请求。而假设想得到诸如用户訪问的详细新闻标题等信息,则可能须要Web应用程序在自己的代码里输出。
为什么要分析日志
毫无疑问,Web日志中包括了大量人们——主要是产品分析人员会感兴趣的信息。最简单的。我们能够从中获取站点每类页面的PV值(PageView。页面訪问量)、独立IP数(即去重之后的IP数量)等;略微复杂一些的,能够计算得出用户所检索的关键词排行榜、用户停留时间最高的页面等。更复杂的,构建广告点击模型、分析用户行为特征等等。
既然这些数据是如此的实用,那么当然已经有无数现成的工具能够帮助我们来分析它们,比如awstats、Webalizer。都是专门用于统计分析Webserver日志的免费程序。
另外另一类产品,它们不分析直接日志。而是通过让用户在页面中嵌入js代码的方式来直接进行数据统计,或者说我们能够觉得它是直接让日志输出到了它们的server。典型的代表产品——大名鼎鼎的Google Analytics。另外还有国内的cnzz、百度统计等。
非常多人可能会说,既然如此,我们为什么还须要自己来分析日志,有必要吗?当然有。我们的用户(产品分析人员)需求是无穷尽的,上面说的这几类工具尽管非常好非常强大。但显然没办法满足所有的需求。
不管是本地分析的工具。还是在线的分析服务。它们尽管提非常丰富的的统计分析功能,能够做一定程度的配置。可是依旧非常有限的。要进行稍复杂点的分析,或者要做基于日志的数据挖掘,依旧须要自己来完毕。
另外绝大多数日志分析工具都是仅仅能用于单机的。数据量稍大就没辙了。同一时候那些提供在线分析的服务对于单个网站通常也都有最大流量的限制——这是非常easy理解的,他们也须要考虑server的负载。
所以,非常多时候还是得靠自己。
怎么进行日志分析
这并非一个简单的问题。即使我们把“日志”限定为Web日志。依旧包括了成千上万种可能的格式和数据。而是“分析”更是难以定义。或许是简单的统计值的计算,或许是复杂的数据挖掘算法。
以下并不打算讨论这些复杂的问题,而仅仅是笼统的讨论怎样构建进行日志分析工作的基础。
有了这些基础会让基于日志的简单统计分析变得非常easy,并让复杂的分析挖掘等变得可行。
少量数据的情况
先考虑最简单的情况,在数据规模比較小的时候,或许是几十MB、几百MB或者几十GB。总之就是在单机处理尚能忍受的时候。一切都非常好办,现成的各种Unix/Linux工具——awk、grep、sort、join等都是日志分析的利器,假设不过想知道某个页面的PV。一个wc+grep就能搞定。假设有稍复杂的逻辑,那就使用各种脚本语言,尤其是perl,配合伟大的正則表達式。基本就能够解决全部的问题。
比如,我们想从上面提到的apache日志中得到訪问量最高前100个IP,实现非常easy:
cat logfile | awk ‘{a[$1]++} END {for(b in a) print b” ”a[b]}’|sort -k2 -r|head -n 100
只是当我们须要频繁去分析日志的时候,上面的做法在一段时间之后可能就会让我们头疼怎样进行各种日志文件、用于分析的脚本文件、crontab文件等等的维护,而且可能会存在大量反复的代码来做数据格式的解析和清洗,这个时候或许就须要更合适的东西。比方——数据库。
当然。要使用数据库来进行日志分析还是须要一些代价的,最基本的就是怎样将各种异构的日志文件导入的数据库中——这个过程通常称为ETL(Extraction-Transformation-Loading)。幸好依旧有各种现成的开源、免费的工具来帮助我们做这件事情。而且在日志种类不太多的时候,自己写几个简单的脚本来完毕这项工作也并不困难。
比如能够将上面的日志去掉不必要的字段。然后导入例如以下的数据库中:
如今须要考虑一下用什么数据库来存储这些数据。MySQL是一个非常经典的开源数据库,它的传统引擎(MyISAM或者InnoDB,行存储)或许并不非常的适合日志数据的存储,可是在小数据量的时候还是非常够用的。并且,在这方面如今已经有了更好的选择,比如开源且免费的Infobright、Infinidb。都是专门为数据仓库应用而进行了优化的数据引擎。採用列存储,有良好的数据压缩。处理几百GB的数据基本上不是问题。
使用数据库的优点之中的一个就是,伟大的SQL能够帮我们非常easy的完毕绝大部分的统计分析工作——PV仅仅须要SELECT+COUNT。计算搜索词排行仅仅须要SELECT+COUNT+GROUP+ORDER+LIMIT。此外,数据库本身的结构化存储模式也让日志数据的管理变的更简单。降低运维代价。
相同还是上面的那个样例。简单的一个SQL就能够搞定:
SELECT * FROM (SELECT ip, COUNT(*) AS ip_count FROM apache_log GROUP BY ip) a ORDER BY ip_count DESC LIMIT 100
至于性能问题,数据库的索引和各种优化机制一般会让我们的统计分析工作变得更快。而且上面提到的Infobright和Infinidb都专门为类似SUM、COUNt之类的聚集应用做了优化。当然也不是绝对的会快。比如在数据库中进行LIKE操作,一般会比grep一个文件还要慢非常多。
更进一步的。使用基于数据库的存储,能够非常easy的进行OLAP(联机分析处理)应用,从日志中挖掘价值会变的更加简单。
很多其它的数据怎么办
一个好的数据库似乎会让事情变的非常easy。可是别忘了前面提到的都是单机数据库。一台单机在存储容量、并发性上毫无疑问都是有非常大限制的。
而日志数据的特点之中的一个就是随时间持续增长,而且因为非常多分析过程往往须要历史数据。短时间内的增长或许能够通过分库、分表或者数据压缩等来解决。只是非常显然并非长久之计。
想要彻底解决数据规模增长带来的问题。非常自然的会想到使用分布式技术,结合上面的结论。或许使用某个分布式数据库是一个好选择,那么对终于用户就能够全然透明了。
这个的确是非常理想的情况,只是现实往往是残酷的。
首先。实现比較完美的分布式数据库(受限于CAP原则)是一个很复杂的问题。因此在这里并不像单机数据库那样。有那么多开源的好东西能够用,甚至于商用的也并非太多。
当然。也并非绝对。假设有钱。还是能够考虑一下Oracle RAC、Greenplum之类东西。
其次。绝大多数分布式数据库都是NoSQL的,所以想继续用上SQL的那些长处基本上是没指望,取而代之的都是一些简单、难以使用的接口。单从这点看来,使用这些数据库的价值已经减少非常多了。
所以,还是先现实一点,先退一步考虑怎样解决的超大规模的日志的分析问题,而不是想怎样让它变的像在小数据规模时那样简单。单单想做到这点,眼下看来并非太难,而且依旧有免费的午餐能够吃。
Hadoop是伟大的Apache基金会以下的一套分布式系统,包含分布式文件系统(HDFS)、MapReduce计算框架、HBase等非常多组件——这些基本都是Google的GFS/MapReduce/BigTable的克隆产品。
Hadoop经过数年的发展,眼下已经非常成熟了。尤其是当中的HDFS和MapReduce计算框架组件。数百台机器的集群已经被证明能够使用。能够承担PB级别的数据。
Hadoop项目中的HBase是一个按列存储的NoSQL分布式数据库,它提供的功能和接口都很easy。仅仅能进行简单的K-V查询。因此并不直接适用于大多数日志分析应用。
所以一般使用Hadoop来做日志分析,首先还是须要将日志存储在HDFS中,然后再使用它提供的MapReduce API编写日志分析程序。
MapReduce是一种分布式编程模型,并不难学习,可是非常显然使用它来处理日志的代价依旧远大于单机脚本或者SQL。一个简单的词频统计计算可能都须要上百代码——SQL仅仅须要一行。另外还有复杂的环境准备和启动脚本。
比如相同还是上面的样例。实现就要复杂的多。通常须要两轮MapReduce来完毕。首先要在第一轮的mapper中计算部分ip的訪问次数之和,并以ip为key输出:
//遍历输入,并聚合结果
foreach(record in input) {
ip = record.ip;
dict[ip]++;
}
//用emit输出。第一个參数为key。用于reduce的分发
foreach(<ip, count> in dict) {
emit(ip, count);
}
然后在第一轮的reduce中就能够得到每一个ip完整的计数,能够顺便排个序。而且仅仅保留前100个。
count = 0;
//对于每一个key(ip),遍历全部的values(count),并累加
while(input.values.hasNext()) {
count += input.values.next();
}
//插入到大小为100的堆中
heap_insert(input.key, count);
在reduce结束的时候输出:
//输出当前reduce中count最高的100个ip
foreach(<ip, count> in dict) {
emit(ip, count);
}
因为reduce通常会有非常多个。所以最后还须要将全部reduce的输出进行合并、再排序。并得到终于的前100个IP以及相应的訪问量。
所以,使用Hadoop来做日志分析非常显然不是一件简单事情。它带来了非常多的额外的学习和运维成本,可是至少,它让超大规模的日志分析变成了可能。
如何变得更简单
在超大规模的数据上做不论什么事情都不是一件easy的事情,包含日志分析。但也并非说分布式的日志分析就一定要去写MapReduce代码,总是能够去做进一步的抽象,在特定的应用下让事情变得更简单。
或许有人会非常自然的想到假设能用SQL来操作Hadoop上的数据该有多好。
其实。不只唯独你一个人会这么想。非常多人都这么想,而且他们实现了这个想法,于是就有了Hive。
Hive如今也是Hadoop项目以下的一个子项目,它能够让我们用SQL的接口来运行MapReduce,甚至提供了JDBC和ODBC的接口。有了这个之后,Hadoop基本上被包装成一个数据库。当然实际上Hive的SQL终于还是被翻译成了MapReduce代码来运行,因此即使最简单的SQL可能也要运行好几十秒。
幸好在通常的离线日志分析中,这个时间还是能够接受的。更重要的是。对于上面提到的样例,我们又能够用一样的SQL来完毕分析任务了。
当然Hive并非全然的兼容SQL语法,并且也不能做到全然的对用户屏蔽细节。非常多时候为了运行性能的优化。依旧须要用户去了解一些MapReduce的基本知识,依据自己的应用模式来设置一些參数,否则我们可能会发现一个查询运行非常慢,或者压根运行不出来。
另外,非常显然Hive也并不能覆盖全部的需求,所以它依旧保留插入原始MapReduce代码的接口,以便扩展。
很多其它的问题
即使有了Hive这样一个类似于数据库的东西,我们依旧还有非常多事情须要做。比如时间久了,可能会有越来越多的须要例行运行的SQL,而这些SQL中,或许有一些是做了反复的事情;或许有一些的运行效率非常低下,一个复杂的SQL就占满了全部的计算资源。这种系统会变得越来越难以维护的,直到有一天例行的SQL最终跑不完了。
而最终用户往往不会去关心这些事情。他们仅仅关心自己提交的查询是不是能即时得到响应,怎么样才干尽快的拿到结果。
举个简单的样例,假设发如今使用apache_log的全部查询中,差点儿没有人用当中的user_agent字段。那么我们全然能够把这个字段去除掉。或者拆分成两张表,以降低多数查询的IO时间。提高运行的效率。
为了系统化的解决这些问题。我们可能须要引入例行任务的调度机制,可能须要去分析全部的SQL来发现哪些是能够合并的、哪些的性能须要优化。使用的数据表是不是须要做水平或者垂直分表等等。依据实际情况的不同,这时事情可能是人工来完毕。也可能是敲代码来自己主动分析并调整。
再者随着日志类型、分析需求的不断增长。用户会越来越多的抱怨非常难找到想要的数据在哪份日志里,或者跑的好好的查询由于日志格式的变化而突然不能用了。另外上面提到的ETL过程也会变得复杂,简单的转换导入脚本非常可能已经解决不了问题。
这时候可能须要构建一个数据管理系统,或者干脆考虑建立一个所谓的数据仓库。
总之。随着日志数据量、日志类型、用户数量、分析需求等等的不断增长,越来越多的问题会逐渐浮现出来。日志分析这件事情可可以不再像我们最初想象的要简单,它会变得越来越有价值值。还有一个越来越大的挑战。
版权声明:本文博客原创文章,博客,未经同意,不得转载。