注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

网易杭研后台技术中心的博客

 
 
 
 
 

日志

 
 

LogStat日志处理流程优化简析  

来自bioinfo   2013-01-04 17:21:29|  分类: BI |举报 |字号 订阅

  下载LOFTER 我的照片书  |
Apache格式的Web访问日志在我们的日常数据处理中占据了很大的份额,这种日志本身具备良好的结构和规范,可以方便地进行各种解析和转 化。访问日志所携带的信息很多,视具体的日志配置不同而不同,但一般都会有IP,访问时间戳,请求类型,请求URL,状态码,字节数,Referer,域 名和浏览器信息等。统计流程所做的就是从这些信息中计算出需要分析的指标和数据。

一般来说,一条日志可能会对应于到多个统计指标中。如某 一次请求页面,既是当前页面的一次PV,也是总站的一个PV,同时也可以是外站一个新的来源。同样一个统计指标可能需要对日志中多个字段进行匹配后才能确 定。假设对于N条日志,需要统计M个指标,每个指标需要对日志进行K次匹配,那么其时间复杂度为O(N*M*K)。日志的规模显然是一直在增长的,我们也 无法限制;需要统计的指标也是会随时间或者业务需求来增加,只有匹配次数K可以进行优化来降低整体的运行时间。

为了方便统计,我们的统计指标以XML配置文件的形式存放,以下对格式进行一下简要说明:
<?xml version="1.0" encoding="UTF8"?>
<statUnit>
<pvItem>1</pvItem>
<uvItem>2</uvItem>
<match>
<entry fieldName="request" matchType="contain"><![CDATA[GET /tag]]></entry>
<entry fieldName="hostName" matchType="equal"><![CDATA[lofter.163.com]]></entry>
</match>
</statUnit>
<statUnit>
<pvItem>3</pvItem>
<uvItem>4</uvItem>
<match>
<entry fieldName="request" matchType="contain"><![CDATA[GET /tag/lomo]]></entry>
<entry fieldName="hostName" matchType="equal"><![CDATA[lofter.163.com]]></entry>
</match>
</statUnit>
从 配置文件看出这是计算4个统计指标,我们称之为2个统计配置(因为每个统计配置对应2个指标,由同样的统计方法得到,区别在于一个需要对用户去重,一个不 需要)。每条日志在处理时会顺序地完成所有统计配置的比较,很明显,统计项配置越少,每个统计项配置中的match项目越少则程序运行得越快;match 项目的匹配方式越高效也能带来性能的提升,比如equal方式就比regexp(执行正则匹配)效率快,而是用正则匹配则不同表达式可以带来不同的匹配效 率。

为了共享配置信息,减少统计项配置,或者说是减少日志重复的匹配次数,我们引入了配置组的概念。即对于一类相似的URL我们使用同一组配置项,下面是一个组配置
<?xml version="1.0" encoding="UTF8"?>
<statUnit>
<unitType>group</unitType>
<match groupMatchIndex="1">
<entry fieldName="request" matchType="regexp"><![CDATA[GET /tag(/lomo)?]]></entry>
<entry fieldName="hostName" matchType="equal"><![CDATA[lofter.163.com]]></entry>
</match>
<group>
<entry fieldName="1" matchType="equal"><![CDATA[]]></entry>
<pvItem>1</pvItem>
<uvItem>2</uvItem>
</group>
<group>
<entry fieldName="1" matchType="equal"><![CDATA[/lomo]]></entry>
<pvItem>3</pvItem>
<uvItem>4</uvItem>
</group>
</statUnit>
这 样我们把2次的配置项比较转换成了一次比较,同时通过正则表达式捕获可变的部分,将其放入一个K/V内存结构中,后续只需要将group配置做一次单独的 取Key操作即可。在上例中,"/lomo和"NULL对象"被放入一个List,然后遍历整个group中的entry配置,看是否存在为空或者是" /lomo",存在则计数器加1,不存在则Pass。

从此思路出发,很快可以对组配置中的匹配类型增加其他类型,如使用 regexp/contain/startsWiith等等,当然equal是最高效的,仅仅做一次Key的命中而已,其他方式则需要对组内其他配置进行 遍历。同时稍加修改也支持多个正则表达式组来进行匹配,如

<?xml version="1.0" encoding="UTF8"?>
<statUnit>
<unitType>group</unitType>
<match>
<entry fieldName="request" matchType="regexp"><![CDATA[GET /([^/]+)/([^/]+)/?from=(baidu|google)]]></entry>
<entry fieldName="hostName" matchType="equal"><![CDATA[www.lofter.com]]></entry>
</match>
<group>
<entry fieldName="1,2" matchType="combine"><![CDATA[hot lomo]]></entry>
<pvItem>1</pvItem>
<uvItem>2</uvItem>
</group>
<group>
<entry fieldName="1,3" matchType="combine"><![CDATA[hot baidu]]></entry>
<pvItem>3</pvItem>
<uvItem>4</uvItem>
</group>
<group>
<entry fieldName="1" matchType="contain"><![CDATA[hot]]></entry>
<pvItem>5</pvItem>
<uvItem>6</uvItem>
</group>
</statUnit>

当 然也可以支持更复杂的匹配逻辑,但这与我们的初衷相违背,我们的目标就是要近可能减少匹配次数降低复杂度。如此一来我们可以将一类URL放入一个统计配置 组中,然后组内的配置可以通过线性的时间处理完成。当然这带来了对于统计配置的额外处理的复杂度,但是这和需要处理的庞大日志量以及统计指标来说,是值得 的。

P.S. 我们使用Hadoop的MapReduce来完成上述处理过程,当然除了对于流程本身的调优,还有Hadoop自身的一些设置,如禁用shuffle过程 中的排序操作,也可以带来程序整体的运行效率(前提是结果不关心排序)。为什么不使用Hive来处理?因为反复起Hive任务本身开销很大,同时数据冗余 太多,每次计算某一指标都会爬整个数据集。
  评论这张
 
阅读(599)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017