sparklinux服务器日志信息,一、Spark应用-(Web log)流式实时日志分析系统实现

使用Python脚本随机生成日志(获取日志)

使用脚本方式将日志自动上传至HDFS

Spark Streaming 自动监控HDFS目录,自动处理新文件

业务背景:

Web log 一般在 HTTP 服务器收集,比如 Nginx access 日志文件。

一个典型的方案是 Nginx 日志文件 + Flume + Kafka + Spark Streaming,如下所述:

接收服务器用 Nginx ,根据负载可以部署多台,数据落地至本地日志文件;

每个 Nginx 节点上部署 Flume ,使用 tail -f 实时读取 Nginx 日志,发送至 KafKa 集群;

专用的 Kafka 集群用户连接实时日志与 Spark 集群;

Spark Streaming 程序实时消费 Kafka 集群上的数据,实时分析,输出;

结果写入 MySQL 数据库。

简单来说就是如下工作流程:

Nginx -> Flume -> Kafka -> Spark -> Spark Streaming -> MySQL

一、系统实现

sample_web_log.py

genLog.sh

streaming.scala

随机生成PV日志的代码:sample_web_log.py

#!/usr/bin/env python

# -*- coding: utf-8 -*-

import random

import time

class WebLogGeneration(object):

# 类属性,由所有类的对象共享

site_url_base = "http://www.xxx.com/"

# 基本构造函数

def __init__(self):

# 前面7条是IE,所以大概浏览器类型70%为IE ,接入类型上,20%为移动设备,分别是7和8条,5% 为空

# https://github.com/mssola/user_agent/blob/master/all_test.go

self.user_agent_dist = {0.0:"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)",

0.1:"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)",

0.2:"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)",

0.3:"Mozilla/4.0 (compatible; MSIE6.0; Windows NT 5.0; .NET CLR 1.1.4322)",

0.4:"Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko",

0.5:"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0",

0.6:"Mozilla/4.0 (compatible; MSIE6.0; Windows NT 5.0; .NET CLR 1.1.4322)",

0.7:"Mozilla/5.0 (iPhone; CPU iPhone OS 7_0_3 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B511 Safari/9537.53",

0.8:"Mozilla/5.0 (Linux; Android 4.2.1; Galaxy Nexus Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19",

0.9:"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36",

1:" ",}

self.ip_slice_list = [10, 29, 30, 46, 55, 63, 72, 87, 98,132,156,124,167,143,187,168,190,201,202,214,215,222]

self.url_path_list = ["login.php","view.php","list.php","upload.php","admin/login.php","edit.php","index.html"]

self.http_refer = [ "http://www.baidu.com/s?wd={query}","http://www.google.cn/search?q={query}","http://www.sogou.com/web?query={query}","http://one.cn.yahoo.com/s?p={query}","http://cn.bing.com/search?q={query}"]

self.search_keyword = ["spark","hadoop","hive","spark mlib","spark sql"]

def sample_ip(self):

slice = random.sample(self.ip_slice_list, 4) #从ip_slice_list中随机获取4个元素,作为一个片断返回

return ".".join([str(item) for item in slice]) # todo

def sample_url(self):

return random.sample(self.url_path_list,1)[0]

def sample_user_agent(self):

dist_uppon = random.uniform(0, 1)

return self.user_agent_dist[float('%0.1f' % dist_uppon)]

# 主要搜索引擎referrer参数

def sample_refer(self):

if random.uniform(0, 1) > 0.2: # 只有20% 流量有refer

return "-"

refer_str=random.sample(self.http_refer,1)

query_str=random.sample(self.search_keyword,1)

return refer_str[0].format(query=query_str[0])

def sample_one_log(self,count = 3):

time_str = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())

while count >1:

query_log = "{ip} - - [{local_time}] \"GET /{url} HTTP/1.1\" 200 0 \"{refer}\" \"{user_agent}\" \"-\"".format(ip=self.sample_ip(),local_time=time_str,url=self.sample_url(),refer=self.sample_refer(),user_agent=self.sample_user_agent())

print query_log

count = count -1

if __name__ == "__main__":

web_log_gene = WebLogGeneration()

#while True:

# time.sleep(random.uniform(0, 3))

web_log_gene.sample_one_log(random.uniform(10, 100))

反复调用生成日志并上传至HDFS的python脚本的自动化脚本:genLog.sh

#!/bin/bash

# HDFS命令

HDFS="/usr/local/myhadoop/hadoop-2.7.3/bin/hadoop fs"

# Streaming程序监听的目录,注意跟后面Streaming程序的配置要保持一致

streaming_dir=”/spark/streaming”

# 清空旧数据

$HDFS -rm "${streaming_dir}"'/tmp/*' > /dev/null 2>&1

$HDFS -rm "${streaming_dir}"'/*' > /dev/null 2>&1

# 一直运行

while [ 1 ]; do

./sample_web_log.py > test.log

# 给日志文件加上时间戳,避免重名

tmplog="access.`date +'%s'`.log"

# 先放在临时目录,再move至Streaming程序监控的目录下,确保原子性

# 临时目录用的是监控目录的子目录,因为子目录不会被监控

$HDFS -put test.log ${streaming_dir}/tmp/$tmplog

$HDFS -mv ${streaming_dir}/tmp/$tmplog ${streaming_dir}/

echo "`date +"%F %T"` put $tmplog to HDFS succeed"

sleep 1

done

Spark Streaming程序用于流式计算分析:

// 导入类

import org.apache.spark.SparkConf

import org.apache.spark.streaming.{Seconds, StreamingContext}

// 设计计算的周期,单位秒

val batch = 10

/*

* 这是bin/spark-shell交互式模式下创建StreamingContext的方法

* 非交互式请使用下面的方法来创建

*/

val ssc = new StreamingContext(sc, Seconds(batch))

/*

// 非交互式下创建StreamingContext的方法

val conf = new SparkConf().setAppName("NginxAnay")

val ssc = new StreamingContext(conf, Seconds(batch))

*/

/*

* 创建输入DStream,是文本文件目录类型

* 本地模式下也可以使用本地文件系统的目录,比如 file:///home/spark/streaming

*/

val lines = ssc.textFileStream("hdfs:///spark/streaming")

/*

* 下面是统计各项指标,调试时可以只进行部分统计,方便观察结果

*/

// 1. 总PV

lines.count().print()

// 2. 各IP的PV,按PV倒序

// 空格分隔的第一个字段就是IP

lines.map(line => {(line.split(" ")(0), 1)}).reduceByKey(_ + _).transform(rdd => {

rdd.map(ip_pv => (ip_pv._2, ip_pv._1)).

sortByKey(false).

map(ip_pv => (ip_pv._2, ip_pv._1))

}).print()

// 3. 搜索引擎PV

val refer = lines.map(_.split("\"")(3))

// 先输出搜索引擎和查询关键词,避免统计搜索关键词时重复计算

// 输出(host, query_keys)

val searchEnginInfo = refer.map(r => {

val f = r.split('/')

val searchEngines = Map(

"www.google.cn" -> "q",

"www.yahoo.com" -> "p",

"cn.bing.com" -> "q",

"www.baidu.com" -> "wd",

"www.sogou.com" -> "query"

)

if (f.length > 2) {

val host = f(2)

if (searchEngines.contains(host)) {

val query = r.split('?')(1)

if (query.length > 0) {

val arr_search_q = query.split('&').filter(_.indexOf(searchEngines(host)+"=") == 0)

if (arr_search_q.length > 0)

(host, arr_search_q(0).split('=')(1))

else

(host, "")

} else {

(host, "")

}

} else

("", "")

} else

("", "")

})

// 输出搜索引擎PV

searchEnginInfo.filter(_._1.length > 0).map(p => {(p._1, 1)}).reduceByKey(_ + _).print()

// 4. 关键词PV

searchEnginInfo.filter(_._2.length > 0).map(p => {(p._2, 1)}).reduceByKey(_ + _).print()

// 5. 终端类型PV

lines.map(_.split("\"")(5)).map(agent => {

val types = Seq("iPhone", "Android")

var r = "Default"

for (t

if (agent.indexOf(t) != -1)

r = t

}

(r, 1)

}).reduceByKey(_ + _).print()

// 6. 各页面PV

lines.map(line => {(line.split("\"")(1).split(" ")(1), 1)}).reduceByKey(_ + _).print()

// 启动计算,等待执行结束(出错或Ctrl-C退出)

ssc.start()

ssc.awaitTermination()

将Debug日志重定向至文件:spark-shell 2>spark-shell-debug.log

总结

本次实验主要分为两个部分:

首先利用[python脚本]+[bash脚本]模拟持续生成了真实HTTP服务器中产生的日志文件;

然后利用[Spark Steaming]程序对指定目录下的文件进行了PV的动态分析。

知识点:

①使用python模拟日志

②bash脚本

③Spark Streaming程序

疑问:

scala中的map()函数?

scala中的reduceByKey()函数?

× 其它

权限设置

sudo : 暂时切换到超级用户模式以执行超级用户权限,提示输入密码时该密码为当前用户的密码,而不是超级账户的密码。不过有时间限制,Ubuntu默认为一次时长15分钟。

su : 切换到某某用户模式,提示输入密码时该密码为切换后账户的密码,用法为“su 账户名称”。如果后面不加账户时系统默认为root账户,密码也为超级账户的密码。没有时间限制。

sudo -i: 为了频繁的执行某些只有超级用户才能执行的权限,而不用每次输入密码,可以使用该命令。提示输入密码时该密码为当前账户的密码。没有时间限制。执行该命令后提示符变为“#”而不是“$”。想退回普通账户时可以执行“exit”或“logout” 。

bash中 2>&1 & 的解释

0 : STDIN_FILENO 标准输入(一般是键盘)

1 : 标准输出(一般是显示屏,准确的说是用户终端控制台)

2 : 标准错误(出错信息输出)

2 > &1 & 意识是将标准错误重定向到标准输出,前一个&标识1为标准输出而不是文件,后一个&表示后台运行

$HDFS -rm "${streaming_dir}"'/tmp/*' > /dev/null 2>&1

两个部分:

$HDFS -rm "${streaming_dir}"'/tmp/*'重定向到/dev/null

2重定向到1

其中/dev/null为空设备,也就是前面执行的结果不要有任何信息输出

输入输出可以重定向

重定向输入就是在命令中指定具体的输入来源,譬如 cat < test.c 将test.c重定向为cat命令的输入源。

输出重定向是指定具体的输出目标以替换默认的标准输出,譬如ls > 1.txt将ls的结果从标准输出重定向为1.txt文本。

有时候会看到如 ls >> 1.txt这类的写法,> 和 >> 的区别在于:> 用于新建而>>用于追加。

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值