示例场景

日志说明

有两台Web服务器,日志文件存放在/usr/local/nginx/logs/目录,日志默认为nginx定义格式。如:

123.13.17.13 - - [25/Aug/2016:00:00:01 +0800] "GET /AppFiles/apk/studynet/icon_v120/apk_80111_1.jpg HTTP/1.1" 206 51934 "http://img.xxx.com:8080/AppFiles/apk/studynet/icon_v120/apk_80111_1.jpg" "Dalvik/1.6.0 (Linux; U; Android 4.4.2; S100 Build/KOT49H)"
120.210.166.150 - - [25/Aug/2016:00:00:01 +0800] "GET /AppFiles/apk/studynet/products/product_lc01.zip HTTP/1.1" 206 16631 "http://img.xxx.com:8080/AppFiles/apk/studynet/products/product_lc01.zip" "Dalvik/1.6.0 (Linux; U; Android 4.4.2; S908 Build/KVT49L)"
123.13.17.13 - - [25/Aug/2016:00:00:01 +0800] "GET /AppFiles/apk/studynet/icon_v120/apk_80111_0.jpg HTTP/1.1" 206 53119 "http://img.xxx.com:8080/AppFiles/apk/studynet/icon_v120/apk_80111_0.jpg" "Dalvik/1.6.0 (Linux; U; Android 4.4.2; S100 Build/KOT49H)"
219.137.119.16 - - [25/Aug/2016:00:00:01 +0800] "GET /AppFiles/apk/gamenet/icon/icon_0_506_0.jpg HTTP/1.1" 404 1035 "-" "Dalvik/v3.3.110_update3 (Linux; U; Android 2.2.1-R-20151127.1131; ET_35 Build/KTU84Q)"
120.210.166.150 - - [25/Aug/2016:00:00:01 +0800] "GET /AppFiles/apk/studynet/products/product_lc01.zip HTTP/1.1" 206 40719 "http://img.xxx.com:8080/AppFiles/apk/studynet/products/product_lc01.zip" "Dalvik/1.6.0 (Linux; U; Android 4.4.2; S908 Build/KVT49L)"

以空格分隔,共有12列数据:

1、客户端IP
2、空白(远程登录名称)
3、空白(认证的远程用户)
4、请求时间
5、时区(UTC)
6、请求方法
7、请求资源
8、http协议
9、状态码
10、发送字节数
11、访问来源
12、客户浏览信息(不具体拆分)

场景部署

在两台Web服务器上部署HDFS客户端,以便定期上传Web日志到HDFS存储平台,最终实现分布式计算。

上传日志到HDFS存储的脚本

【/root/hadooptest/hdfsput.py】

#!/usr/bin/env python
# -*- encoding: utf-8 -*- import subprocess
import sys
import datetime webid = 'test1' #HDFS存储日志标志,另一台Web服务器为:test2
currdate = datetime.datetime.now().strftime('%Y%m%d') logspath = '/usr/local/nginx/logs/access.log' #日志路径
logname = 'access.log.'+webid try:
#创建HDFS目录,目录格式:nginx/20160825,加wait()是为了让父进程等待子进程完成后再继续往下执行(subporcess默认启动子进程后不等待其执行结果就继续往下执行)
subprocess.Popen(['/usr/local/hadoop-2.6.4/bin/hadoop','fs','-mkdir','-p','hdfs:///user/root/nginx'+currdate],stdout=subprocess.PIPE).wait()
except Exception as e:
pass putinfo = subprocess.Popen(['/usr/local/hadoop-2.6.4/bin/hadoop','fs','-put',logspath,'hdfs:///user/root/nginx/' +currdate +'/'+logname],stdout=subprocess.PIPE) #上传本地日志到HDFS for line in putinfo.stdout:
print line

添加定时功能到crontab

0 0 * * * /usr/bin/python /root/hadooptest/hdfsput.py >> /dev/null 2>&1

两台Web服务器都上传日志后,HDFS上信息如下:

[root@wx ~]# hadoop fs -ls /user/root/nginx/20160825
Found 2 items
-rw-r--r-- 1 root supergroup 15 2016-08-25 15:58 /user/root/nginx/20160825/access.log.test1
-rw-r--r-- 1 root supergroup 28 2016-08-25 15:58 /user/root/nginx/20160825/access.log.test2

网站访问流量统计

网站访问流量作为衡量一个站点的价值、热度的重要指标,另外CDN服务中流量会涉及计费,如何快速准确分析当前站点的流量数据至关重要。下面实现精确到分钟统计网站访问流量,原理是在mapper操作时将Web日志中小时的每分钟作为key,将对应的行发送字节数作为value,在reducer操作时对相同key做累加(sum统计)。

【/root/hadooptest/httpflow.py】

#/usr/bin/env python
# -*- coding:utf-8 -*- from mrjob.job import MRJob
import re class MRCounter(MRJob):
def mapper(self, key, line):
i = 0
for flow in line.split(): #获取时间段,为域日志的第4列,内容如:“[24/Aug/2016:00:00:02”
if i==3:
timerow = flow.split(':')
hm = timerow[1] + ':' + timerow[2] #获取'小时:分钟',作为key
if i==9 and re.match(r'\d{1,}',flow): #获取日志第10列:发送的字节数,作为value
yield hm,int(flow) #初始化key:value
i+=1 def reducer(self, key, occurences):
yield key,sum(occurences) #相同key“小时:分钟”的value做累加操作 if __name__ == '__main__':
MRCounter.run()

生成Hadoop任务,运行:

python /root/hadoop/httpflow.py -r hadoop -o hdfs://output/httpflow hdfs:///user/root/nginx

建议将分析的数据定期入库MySQL,利用MySQL灵活丰富的SQL支持,可以很方便的对数据进行加工,轻松输出比较美观的数据报表。

网站HTTP状态码统计

统计一个网站的HTTP状态码比例数据,可以帮助我们了解网站的可用度及健康状态,比如我们关注的200、404/5xx状态等。在此示例中我们利用Mrjob的多步调用的形式来实现,除了基本的mapper、reducer方法外,还可以自定义处理方法,在steps中添加调用即可。

【/root/hadooptest/httpstatus.py】

#!/usr/bin/env python
# -*- encoding: utf-8 -*- from mrjob.job import MRJob
import re class MRCounter(MRJob):
def mapper(self, key, line):
i = 0
for httpcode in line.split():
if i == 8 and re.match(r'\d{1,3}',httpcode): #获取日志中HTTP状态码段,作为key
yield httpcode,1 #初始化key:value,value计数为1,方便reducer做累加
i+=1 def reducer(self, httpcode,occurrences):
yield httpcode,sum(occurrences) #对排序后的key对应的value作sum累加 def steps(self):
return [self.mr(mapper=self.mapper),self.mr(reducer=self.reducer)] #在steps方法中添加调用队列 if __name__ == '__main__':
MRCounter.run()

生成Hadoop任务,运行:

python httpstatus.py -r hadoop -o hdfs:///output/httpstatus hdfs:///user/nginx

分析结果:

[root@wx hadooptest]# hadoop fs -cat /output/httpstatus/part-00000
"" 608997
"" 2802574
"" 1
"" 34600
"" 30
"" 1
"" 1653791
"" 180358
"" 2689

网站分钟级请求数统计

一个网站请求量大小,直接关系到网站的访问质量,非常有必要对改数据进行分析且关注。本示例以分钟为单位对网站的访问数进行统计。

【/root/hadooptest/http_minute_conn.py】

#!/usr/bin/env python
# -*- encoding: utf-8 -*- from mrjob.job import MRJob
import re class MRCounter(MRJob):
def mapper(self, key, line):
i = 0
for dt in line.split():
if i == 3: #获取时间段,位于日志的第4列,内容如“[24/Aug/2016:00:00:02”
timerow = dt.split(':')
hm = timerow[1] + ':' + timerow[2] #获取'小时:分钟',作为key
yield hm,1 #初始化key:value
i+=1 def reducer(self, key,occurrences):
yield key,sum(occurrences) #对排序后的key对应的value作sum累加 if __name__ == '__main__':
MRCounter.run()

生成Hadoop任务,运行:

python http_minute_conn.py -r hadoop -o hdfs:///output/http_minute_conn hdfs:///user/nginx

网站访问来源IP统计

统计用户的访问来源IP可以更好地了解网站的用户分布,同时也可以帮助安全人员捕捉攻击来源。实现原理是定义匹配IP正则字符串作为key,将value初始化为1,执行reducer操作时做累加(sum)统计

【/root/hadooptest/ipstat.py】

#!/usr/bin/env python
# -*- encoding: utf-8 -*- from mrjob.job import MRJob
import re IP_RE = re.compile(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') #定义IP正则匹配 class MRCounter(MRJob):
def mapper(self, key, line):
for ip in IP_RE.findall(line): #匹配IP正则后生成key:value,其中key为IP地址,value初始值为1
yield ip,1 def reducer(self, ip,occurrences):
yield ip,sum(occurrences) #对排序后的key对应的value作sum累加 if __name__ == '__main__':
MRCounter.run()

生成Hadoop任务,运行:

python ipstat.py -r hadoop -o hdfs:///output/ipstat hdfs:///user/nginx

网站文件访问统计

通过统计网站文件的访问次数可以帮助运维人员了解访问最集中的文件,以便进行有针对性的优化,比如调整静态文件过期策略、优化动态cgi的执行速度、拆分业务逻辑等。实现原理是讲访问文件作为key,初始化value为1,执行reducer是做累加(sum)统计。

【/root/hadooptest/httpfile.py】

#!/usr/bin/env python
# -*- encoding: utf-8 -*- from mrjob.job import MRJob
import re IP_RE = re.compile(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') #定义IP正则匹配 class MRCounter(MRJob):
def mapper(self, key, line):
i = 0
for url in line.split():
if i==6: #获取日志中URL文件资源字段,作为key
yield url,1
i+=1 def reducer(self, url,occurrences):
yield url,sum(occurrences) #对排序后的key对应的value作sum累加 if __name__ == '__main__':
MRCounter.run()

生成Hadoop任务,运行:

python httpfile.py -r hadoop -o hdfs:///output/httpfile hdfs:///user/nginx

同理,我们可以使用以上方法对User-Agent域进行分析,包括浏览器类型及版本、操作系统及版本、浏览器内核等信息,为更好地提升用户体验提供数据支持。


参考资料:

根据刘天斯《Python自动化运维技术与最佳实践》整理

Hadoop:实战Web日志分析的更多相关文章

  1. Hadoop应用开发实战案例 第2周 Web日志分析项目 张丹

    课程内容 本文链接: 张丹博客 http://www.fens.me 用Maven构建Hadoop项目 http://blog.fens.me/hadoop-maven-eclipse/程序源代码下载 ...

  2. hadoop入门之海量Web日志分析 用Hadoop提取KPI统计指标

    转载自:http://blog.fens.me/hadoop-mapreduce-log-kpi/ 今天学习了这一篇博客,写得十分好,照着这篇博客敲了一遍. 发现几个问题, 一是这篇博客中采用的had ...

  3. 海量WEB日志分析

    Hadoop家族系列文章,主要介绍Hadoop家族产品,常用的项目包括Hadoop, Hive, Pig, HBase, Sqoop, Mahout, Zookeeper, Avro, Ambari, ...

  4. linux系统web日志分析脚本

    linux系统web日志分析这方面工具比较多,比如logwatch或awstats等使用perl语言开发,功能都非常强大.但这些软件都需要进行一些配置,很多朋友往往在技术方面没有投入太多力量,即便参照 ...

  5. hadoop实战 -- 网站日志KPI指标分析

    本项目分析apache服务器产生的日志,分析pv.独立ip数和跳出率等指标.其实这些指标在第三方系统中都可以检测到,在生产环境中通常用来分析用户交易等核心数据,此处只是用于演示说明日志数据的分析流程. ...

  6. [spark案例学习] WEB日志分析

    数据准备 数据下载:美国宇航局肯尼迪航天中心WEB日志 我们先来看看数据:首先将日志加载到RDD,并显示出前20行(默认). import sys import os log_file_path =' ...

  7. 可视化实时Web日志分析工具-goaccess

    说到web服务器就不得不说Nginx,目前已成为企业建站的首选.但由于种种历史原因,Nginx日志分析工具相较于传统的apache.lighthttp等还是少很多. 今天就和大家分享一个非常强大的实时 ...

  8. 《ElasticSearch6.x实战教程》之实战ELK日志分析系统、多数据源同步

    第十章-实战:ELK日志分析系统 ElasticSearch.Logstash.Kibana简称ELK系统,主要用于日志的收集与分析. 一个完整的大型分布式系统,会有很多与业务不相关的系统,其中日志系 ...

  9. 我的日志分析之道:简单的Web日志分析脚本

    前言 长话短说,事情的起因是这样的,由于工作原因需要分析网站日志,服务器是windows,iis日志,在网上找了找,github找了找,居然没找到,看来只有自己动手丰衣足食. 那么分析方法我大致可分为 ...

随机推荐

  1. 初始化IoC容器(Spring源码阅读)-我们到底能走多远系列(31)

    我们到底能走多远系列(31) 扯淡: 有个问题一直想问:各位你们的工资剩下来会怎么处理?已婚的,我知道工资永远都是不够的.未婚的你们,你们是怎么分配工资的? 毕竟,对自己的收入的分配差不多体现了自己的 ...

  2. 使用github + Octopress 搭建免费博客 + 碰到问题的解决方法

    使用github + Octopress 搭建免费博客,先说碰到的问题,具体创建方法见下面. 问题1, 添加ruby淘宝链接问题,显示无法获取, 解决: source “http://ruby.tao ...

  3. iOS7中如何去除UINavigationbar下边的那条黑线

    做项目过程中遇到要去掉导航栏下面的一条黑线,从网上找到的一个方法 默认UINavigationbar样式 准备用于替换的背景 替换后的效果 if ([self.navigationController ...

  4. iOS中的多线程及GCD

    多线程中的一些概念 //任务:代码段  方法  线程就是执行这些任务 //NSThread类 创建线程 执行线程 [NSThread isMainThread]//判断是否是主线程 #import & ...

  5. spring学习笔记---Jackson的使用和定制

      前言: JAVA总是把实体对象(数据库/Nosql等)转换为POJO对象再处理, 虽然有各类框架予以强力支持. 但实体对象和POJO, 由于"饮食习惯", "民族特色 ...

  6. 关于时间的util类,以后方便查阅

    public static int lastDayOfMonth(int year, int month)  {    if (month == 2)    {      if (isLeapYear ...

  7. 记录几种有关libsvm格式数据的list和dict用法

    # list元素求和 sum = reduce(lambda x,y: x+y, mylist) # 比较两个 lists 的元素是否完全一致 if all(x==y for x, y in zip( ...

  8. JS初学之-for套for遍历二维数组

    <!doctype html><html><head><meta charset="utf-8"><title>无标题文 ...

  9. Java—面向对象—权限修饰符及思维导图

    课上老师所讲实例整理: package org.hanqi.pn0120; //汽车 public class Car { //颜色 private String yanse; //品牌 privat ...

  10. java多线程之:SynchronousQueue队列

    SynchronousQueue是这样一种阻塞队列,其中每个 put 必须等待一个 take,反之亦然.同步队列没有任何内部容量,甚至连一个队列的容量都没有.      不能在同步队列上进行 peek ...