概述
當(dāng)前互聯(lián)網(wǎng)應(yīng)用中,萬(wàn)維網(wǎng)(World Wide Web)應(yīng)用占據(jù)了絕大部分的份額。萬(wàn)維網(wǎng)應(yīng)用對(duì)外提供服務(wù)需要架設(shè)Web服務(wù)器軟件。典型的Web服務(wù)器軟件有Apache、Nginx等。Web服務(wù)器軟件在運(yùn)行過(guò)程中會(huì)寫(xiě)入各種日志到磁盤(pán)文件中。例如,Apache Web服務(wù)器軟件運(yùn)行過(guò)程中,會(huì)產(chǎn)生access.log文件,記錄用戶訪問(wèn)日志。
繁忙的Web服務(wù)器軟件每天產(chǎn)生大量的日志記錄。日積月累之后,這些日志所占據(jù)的存儲(chǔ)會(huì)變得非常大。此時(shí),單機(jī)無(wú)法滿足分析處理日志的需求。因此,我們需要將日志文件存儲(chǔ)在HDFS分布式文件系統(tǒng)中。使用開(kāi)源的Apache Flume軟件,能夠從Web服務(wù)器集群導(dǎo)入日志到HDFS集群。
通過(guò)Apache Flume采集到HDFS的日志文件是原始的格式,這種格式通常并不利于分析統(tǒng)計(jì)。因此,下一步要做的是對(duì)日志文件進(jìn)行預(yù)處理,產(chǎn)生更規(guī)整的數(shù)據(jù)。這個(gè)過(guò)程可以使用MapReduce來(lái)進(jìn)行,從HDFS中讀取原始日志文件,處理之后的數(shù)據(jù)仍然存放在HDFS上。
經(jīng)過(guò)前面的準(zhǔn)備,接下來(lái)可以對(duì)日志數(shù)據(jù)進(jìn)行分析和統(tǒng)計(jì)了。最開(kāi)始,人們直接使用MapReduce進(jìn)行統(tǒng)計(jì)的工作。但是很快,大家發(fā)現(xiàn)編寫(xiě)MapReduce程序是一件很麻煩的事情,而且,部分?jǐn)?shù)據(jù)分析人員不具備Java編程的能力。為了解決這個(gè)問(wèn)題,Apache Hive軟件被創(chuàng)建出來(lái)。借助Apache Hive,可以使用SQL語(yǔ)言讀寫(xiě)和管理HDFS上的數(shù)據(jù)。在本次實(shí)踐的最后一個(gè)環(huán)節(jié),你將使用Apache Hive,對(duì)預(yù)處理之后的規(guī)整數(shù)據(jù)進(jìn)行分析統(tǒng)計(jì)。
總體流程架構(gòu)如圖:
監(jiān)控日志文件
日志文件數(shù)據(jù)是某個(gè)高校WWW服務(wù)器七個(gè)月的HTTP請(qǐng)求數(shù)據(jù) (時(shí)間是從1995/6/1 00:00:00到1995/12/31 23:59:59)。日志數(shù)據(jù)分別存在文件xaa、xab、xac中,首先將它保存到/home/ubuntu/com_experiment目錄中。
1. 啟動(dòng)hadoop進(jìn)行實(shí)驗(yàn)操作:
hadoop namenode -format
start-all.sh
jps
成功啟動(dòng)如圖:
2. 在/home/ubuntu目錄下創(chuàng)建flume.conf文件,內(nèi)容配置如下(注:本地路徑與hdfs路徑):
# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# 定義源: spooldir
a1.sources.r1.type = spooldir
# 指定監(jiān)控目錄(本地路徑)
a1.sources.r1.spoolDir = /home/ubuntu/com_experiment
a1.sources.r1.decodeErrorPolicy = IGNORE
# Describe the sink(hdfs路徑)
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = /flume/20220706/
a1.sinks.k1.hdfs.fileType = DataStream
a1.sinks.k1.hdfs.useLocalTimeStamp = true
a1.sinks.k1.hdfs.rollSize = 0
a1.sinks.k1.hdfs.rollCount = 0
# Use a channel which buffers events in memory
a1.channels.c1.type = memory
# Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
3. 運(yùn)行flume配置的命令,代碼如下:
flume-ng agent -f /home/ubuntu/flume.conf -n a1
運(yùn)行結(jié)果如圖:
Apache Flume是一種分布式的可靠的系統(tǒng),主要用于高效地收集、聚合和移動(dòng)大量來(lái)自不同來(lái)源的日志數(shù)據(jù)到一個(gè)集中的數(shù)據(jù)存儲(chǔ)區(qū)??梢酝ㄟ^(guò)運(yùn)行“flume-ng -h”了解上述命令各選項(xiàng)的含義。
4. 日志導(dǎo)入到HDFS后,查看HDFS目錄下某個(gè)文件的前幾條內(nèi)容:
#查看HDFS目錄內(nèi)容的命令
hdfs dfs -ls /flume/20220706
HDFS目錄內(nèi)容部分如圖:
#查看HDFS目錄下某文件的前幾行內(nèi)容的命令
hdfs dfs -cat /flume/20220706/FlumeData.1657070180143 | head -n 3
查看HDFS目錄下某文件的前三行內(nèi)容如圖:
日志數(shù)據(jù)預(yù)處理
日志文件導(dǎo)入HDFS之后,為了方便Hive加載和分析數(shù)據(jù),需要進(jìn)一步對(duì)日志文件進(jìn)行預(yù)處理,產(chǎn)生格式整齊的數(shù)據(jù)文件。
原日志示例如圖:
這是典型的Apache服務(wù)器軟件的日志格式。每一行記錄用戶對(duì)Web服務(wù)器的一次訪問(wèn)。一條記錄有七個(gè)欄位,各欄位之間使用空格字符分隔。各欄位的含義如下:
- 遠(yuǎn)程主機(jī)IP:該欄是請(qǐng)求的請(qǐng)求方IP地址。其示例值為:131.235.141.48。
- E-mail:該欄現(xiàn)在已經(jīng)棄用,其值恒為“-”。
- 登錄名:該欄現(xiàn)在已經(jīng)棄用,其值恒為“-”。
- 請(qǐng)求時(shí)間:該欄是接收到請(qǐng)求的時(shí)間。時(shí)間信息用方括號(hào)包圍,而且采用所謂的 “公共日志格式” 或 “標(biāo)準(zhǔn)英文格式” 。時(shí)間信息最后的 “-0600” 表示服務(wù)器所處時(shí)區(qū)位于UTC之前的6小時(shí)。
- HTTP請(qǐng)求信息:該欄是典型的 ”METHOD RESOURCE PROTOCOL” ,即 ”方法 資源 協(xié)議”。METHOD是一般瀏覽器通過(guò)GET或POST方法來(lái)傳輸表單信息,RESOURCE是指瀏覽者向服務(wù)器請(qǐng)求的文檔地址,即URL。PROTOCOL通常是HTTP,后面再加上版本號(hào)。
- 狀態(tài)代碼:該欄是請(qǐng)求信息的狀態(tài)。一般地說(shuō),以2開(kāi)頭的狀態(tài)代碼表示成功,以3開(kāi)頭的狀態(tài)代碼表示由于各種不同的原因用戶請(qǐng)求被重定向到了其他位置,以4開(kāi)頭的狀態(tài)代碼表示客戶端存在某種錯(cuò)誤,以5開(kāi)頭的狀態(tài)代碼表示服務(wù)器遇到了某個(gè)錯(cuò)誤。
- 發(fā)送字節(jié)數(shù):該欄是發(fā)送給客戶端的總字節(jié)數(shù)。通過(guò)檢查該數(shù)值是否和實(shí)際文件的大小相同,可以知道這次傳輸是否被打斷。把日志記錄中的這些值加起來(lái)就可以得知服務(wù)器在一天、一周或者一月內(nèi)發(fā)送了多少數(shù)據(jù)。其示例值為:2273。
日志處理后示例如圖:
作出的處理如下:
- 丟棄第2欄和第3欄
- 第5欄—HTTP請(qǐng)求信息拆分為三個(gè)字段,分別表示:方法、資源、協(xié)議
- 將文件轉(zhuǎn)換為csv格式,即每個(gè)字段之間使用英文逗號(hào)分隔
其中輸入是Flume導(dǎo)入到HDFS的目錄,輸出結(jié)果存放于HDFS的另外一個(gè)目錄。
1.了解到日志數(shù)據(jù)需要如何處理后,使用MapReduce進(jìn)行處理,只需map即可,代碼如下:
#路徑/home/ubuntu/map.py
import sys
import csv
with open("Output.csv",'w',encoding='utf-8',newline="") as file:
for line in sys.stdin:
if line[0] != '':
line = line.strip()
line = line.replace('- - ', '').replace('[', '').replace(']', '').replace('"', '').replace('"', '')
line = line.replace(' ', ',')
line = line.replace(',-', ' -')
print(line)
file.write(line)
file.write('\n')
2.然后使用Hadoop-streaming運(yùn)行MapReduce的命令,代碼如下:
$HADOOP_HOME/bin/hadoop jar \
$HADOOP_HOME/share/hadoop/tools/lib/hadoop-streaming-2.7.3.jar \
-files "/home/ubuntu/map.py" \
-input /flume/20220706/* \
-output /20220706/out001 \
-mapper "python3 map.py"
成功執(zhí)行MapReduce結(jié)果如圖:
數(shù)據(jù)處理后部分如圖:
#查看該目錄下前五行內(nèi)容
hdfs dfs -cat /20220706/out001/* | tail -n 5
日志數(shù)據(jù)分析與統(tǒng)計(jì)
日志數(shù)據(jù)預(yù)處理后,使用Hive為HDFS上的csv文件建表并使用HQL分析問(wèn)題。
Apache Hive是一種建立在Hadoop文件系統(tǒng)上的數(shù)據(jù)倉(cāng)庫(kù)架構(gòu),并對(duì)存儲(chǔ)在HDFS中的數(shù)據(jù)進(jìn)行分析和管理。Hive通過(guò)一種類似SQL的查詢語(yǔ)言(稱為HiveSQL,簡(jiǎn)稱HQL)分析與管理數(shù)據(jù)。
#首先,進(jìn)入Hive操作
hive
#然后,創(chuàng)logdata表對(duì)應(yīng)日志數(shù)據(jù)處理后的字段
create table if not exists logdata(ip string,request_time string,method string,url string,state int,num int)row format delimited fields terminated by',';
#再將處理后輸出的數(shù)據(jù)導(dǎo)入到logdata表
load data inpath '/20220706/out001/part-00000' into table logdata;
最后成功執(zhí)行結(jié)果如圖:
1.IP地址(域名) 訪問(wèn)次數(shù)最多
select ip from(select ip,rank()over(order by sum desc)as rank from(select ip,COUNT(*)as sum from logdata group by ip order by sum desc)a)b where b.rank=1;
結(jié)果如圖:
2.IP地址(域名) 產(chǎn)生的流量最大
select a.ip from(select distinct b.ip,b.newtable from(select ip,sum(num) over(partition by ip)newtable from logdata)b order by b.newtable desc)a limit 1;
結(jié)果如圖:
3.產(chǎn)生流量最大的前10% IP地址(域名)
select a.ip from(select *,ntile(10) over(order by b.newtable desc) d from(select distinct c.ip,c.newtable from(select ip,sum(num) over(partition by ip)newtable from logdata)c)b)a;
結(jié)果如圖:
4.統(tǒng)計(jì)每個(gè)月的流量
select distinct a.month,a.month_total from(select substr(request_time,4,8)as month,sum(num) over(partition by substr(request_time,4,8))month_total from logdata)a where a.month_total is not NULL;
結(jié)果如圖:
5.統(tǒng)計(jì)每個(gè)月的流量 month_total 、當(dāng)年的總流量 year_total及每月流量占比 ( month_total /year_total )
select distinct year,mon,year_total,month_total,month_total/year_total from(select*,sum(num)over(partition by mon)month_total from(select*,substr(request_time,4,3)as mon from(select*,sum(num)over(partition by year)year_total from(select*,substr(request_time,8,4)as year from logdata)a)b)c)d where year_total is not NULL;
結(jié)果如圖:
6.日志記錄的時(shí)期,一共有多少錯(cuò)誤的請(qǐng)求?(響應(yīng)碼以4或5開(kāi)頭)
select count(state) from logdata where state like '4%' or state like '5%';
結(jié)果如圖:
7.
查詢每個(gè)月中錯(cuò)誤請(qǐng)求的次數(shù)
select distinct a.month,a.erro_total from(select substr(request_time,4,8)as month,count(state) over(partition by substr(request_time,4,8))erro_total from logdata where state like '4%' or state like '5%')a;
結(jié)果如圖:
查詢每個(gè)月中請(qǐng)求的總次數(shù)
select distinct b.month,b.total from(select substr(request_time,4,8)as month,count(state) over(partition by substr(request_time,4,8))total from logdata)b where total != 0;
結(jié)果如圖:
嵌套獲取每個(gè)月錯(cuò)誤請(qǐng)求占當(dāng)月總請(qǐng)求數(shù)量的占比
select aa.month,aa.erro_total/bb.total from(select distinct a.month,a.erro_total from(select substr(request_time,4,8)as month,count(state) over(partition by substr(request_time,4,8))erro_total from logdata where state like '4%' or state like '5%')a)aa ,(select distinct b.month,b.total from(select substr(request_time,4,8)as month,count(state) over(partition by substr(request_time,4,8))total from logdata)b where total != 0)bb where aa.month==bb.month;
結(jié)果以科學(xué)計(jì)算法的方式表示如圖:
日志數(shù)據(jù)可視化
將上一步5的分析結(jié)果保存到本地文件并進(jìn)行數(shù)據(jù)可視化。
數(shù)據(jù)可視化的功能是幫助人們更好地分析數(shù)據(jù),具有較高的識(shí)別效率,有效明確地傳遞信息,可以強(qiáng)化認(rèn)知理解,能夠幫助人們提高理解與處理數(shù)據(jù)的效率
1.將第五題查詢結(jié)果保存到本地,代碼如下:
insert overwrite local directory '/home/ubuntu/20220706_ComExperiment/' row format delimited fields terminated by ',' select b.month,b.month_total/b.year_total from(select distinct a.month_total,a.year_total,substr(a.request_time,4,8)as month from(select *,sum(num) over(partition by substr(request_time,4,8))month_total,sum(num) over(partition by substr(request_time,8,4))year_total from logdata)a)b where year_total is not NULL;
成功執(zhí)行結(jié)果如圖:
查看文件如圖:
查看內(nèi)容如圖:
2.用分頁(yè)組件Tab實(shí)現(xiàn)餅圖與折線圖,代碼如下:
from pyecharts import options as opts
from pyecharts.charts import Line, Tab, Pie
import pandas as pd
data = pd.read_csv('/home/ubuntu/20220706_ComExperiment/000000_0', header=None)
data.columns = ['year_month', 'rate']
year_month = data['year_month'].tolist()
rate = data['rate'].tolist()
def line_markpoint() -> Line:
c = (
Line()
.add_xaxis(year_month)
.add_yaxis(
"year_month",
rate,
label_opts=opts.LabelOpts(is_show=False),
markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_="min")]),
)
.set_global_opts(title_opts=opts.TitleOpts(title="Line-MarkPoint圖"))
)
return c
def pie_rosetype() -> Pie:
v = year_month
c = (
Pie()
.add(
"year_month",
[list(z) for z in zip(v, rate)],
radius=["30%", "75%"],
center=["25%", "50%"],
rosetype="radius",
label_opts=opts.LabelOpts(is_show=False),
)
.set_global_opts(title_opts=opts.TitleOpts(title="Pie-玫瑰圖"))
)
return c
tab = Tab()
tab.add(line_markpoint(), "line_markpoint")
tab.add(pie_rosetype(), "pie_rosetype")
tab.render("/home/ubuntu//tab_base.html")
結(jié)果如圖:
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-779816.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-779816.html
到了這里,關(guān)于猿創(chuàng)征文|Hadoop大數(shù)據(jù)技術(shù)綜合實(shí)驗(yàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!