大資料視覺化之Nginx伺服器日誌分析及視覺化展示(Nginx+flume+HDFS+Spark+Highcharts)
專案說明:
本專案為一個web程式,能夠利用大資料技術,對nginx伺服器的訪問日誌進行圖形化展示。當訪問此程式時,可以看到nginx日誌中統計出來的全天分時網站點選量等資訊的圖表展示。每條Nginx日誌的平均大小為250位元組左右,假設每天產生1億條訪問日誌,日誌檔案的總大小約為230GB,本程式適合對此類海量日誌資料進行分析和統計工作,並快速得出統計結果。
程式執行環境:
- 採用三臺虛擬機器來模擬真實環境下的Hadoop高可用叢集服務。主機名和ip地址分別為master1-192.168.49.128、master2-192.168.49.129、slave1-192.168.49.130。
- 在master1和master2上分別安裝flume資料匯入工具、Nginx伺服器以及Spark2。
專案架構圖:
實現過程:
第一步:搭建分散式Nginx伺服器環境,在兩臺虛擬機器上分別配置Nginx伺服器以及flume,將兩臺Nginx伺服器的日誌檔案統一匯入到HDFS上的同一個目錄下(此專案為HDFS上的/flume/collector1目錄)。
master1的flume配置檔案如下:
tail1.sources=src1
tail1.channels=ch1
tail1.sinks=sink1
tail1.sources.src1.type=exec
tail1.sources .src1.command=tail -F /var/log/nginx/access.log
tail1.sources.src1.channels=ch1
tail1.channels.ch1.type=memory
tail1.channels.ch1.capacity=500
tail1.sinks.sink1.type=avro
tail1.sinks.sink1.hostname=192.168.49.128
tail1.sinks.sink1.port=6000
tail1.sinks.sink1.batch-size=1
tail1.sinks.sink1.channel=ch1
collector1.sources =src1
collector1.channels=ch1
collector1.sinks=sink1
collector1.sources.src1.type=avro
collector1.sources.src1.bind=192.168.49.128
collector1.sources.src1.port=6000
collector1.sources.src1.channels=ch1
collector1.channels.ch1.type=memory
collector1.channels.ch1.capacity=500
collector1.sinks.sink1.type=hdfs
collector1.sinks.sink1.hdfs.path=/flume/collector1
collector1.sinks.sink1.hdfs.filePrefix=access_log
collector1.sinks.sink1.hdfs.writeFormat=Text
collector1.sinks.sink1.channel=ch1
collector1.sinks.sink1.hdfs.fileType=DataStream
master2的flume配置檔案如下:
tail1.sources=src1
tail1.channels=ch1
tail1.sinks=sink1
tail1.sources.src1.type=exec
tail1.sources.src1.command=tail -F /var/log/nginx/access.log
tail1.sources.src1.channels=ch1
tail1.channels.ch1.type=memory
tail1.channels.ch1.capacity=500
tail1.sinks.sink1.type=hdfs
tail1.sinks.sink1.hdfs.path=/flume/collector1
tail1.sinks.sink1.hdfs.filePrefix=access_log
tail1.sinks.sink1.hdfs.writeFormat=Text
tail1.sinks.sink1.channel=ch1
tail1.sinks.sink1.hdfs.fileType=DataStream
日誌檔案匯入後的結果如下圖:
第二步:使用Spark提取相關的日誌資料項並分析。(本文中以Nginx伺服器中的按時間統計瀏覽量為例進行說明)
Nginx日誌格式樣例如下:
192.168.49.123 - - [25/Nov/2017:17:05:11 +0800] "GET /ip/part-00000 HTTP/1.1" 200 364 "http://192.168.49.128/project/index.html" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0" "-"
192.168.49.1 - - [22/Nov/2017:09:34:03 +0800] "GET /nginx-logo.png HTTP/1.1" 200 368 "http://192.168.49.129/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0" "-"
192.168.49.1 - - [22/Nov/2017:09:35:56 +0800] "GET /poweredby.png HTTP/1.1" 200 2811 "http://192.168.49.129/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36" "-"
192.168.49.1 - - [22/Nov/2017:09:45:56 +0800] "GET /nginx-logo.png HTTP/1.1" 200 368 "http://192.168.49.129/" "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2" "-"
採用Spark將日誌檔案通過冒號進行分割並提取第二部分,從而提取到小時數,統計之後將最終結果以TXT文字檔案的形式寫入Nginx伺服器下的time目錄中。關鍵程式碼如下:
log.map(lambda line:line.split(':')[1]).map(lambda line:(line,1)).reduceByKey(lambda a1,a2:a1+a2).sortByKey(lambda a1,a2:a1+a2).map(lambda (key,value):(int(key),value)).repartition(1).saveAsTextFile("file:///usr/share/nginx/html/time")
分析後生成的TXT文字檔案的內容如下,檔名為part-00000:
(9, 419)
(10, 237)
(11, 1614)
(12, 438)
(14, 15)
(15, 114)
(16, 318)
第三步:在Highcharts中呼叫統計和分析生成的TXT檔案中的統計結果,進行圖表的繪製與展示。採用ajax來讀取資料。
先附上JavaScript程式碼:
<script language="JavaScript">
$(document).ready(function() {
var title = {
style: {
fontSize: '37px'
},
text: 'Ngnix伺服器天訪問量分佈'
};
var subtitle = {
text: '來源:隨機生成'
};
var xAxis = {
title: {
text: '訪問時間(小時)'
},
categories: count2()
};
var yAxis = {
title: {
text: '訪問量(次)'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
};
var tooltip = {
valueSuffix: '次'
}
var legend = {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
borderWidth: 0
};
var series = [{
name: 'Nginx',
data: count()
}];
var json = {};
json.title = title;
json.subtitle = subtitle;
json.xAxis = xAxis;
json.yAxis = yAxis;
json.tooltip = tooltip;
json.legend = legend;
json.series = series;
$('#container2').highcharts(json);
});
</script>
X軸xAxis的資料來源採用count2函式來從檔案中讀取。count2函式程式碼如下:
function count2() {
var rst;
$.ajax({
type: "get",
async: false,
url: "/time/part-00000",
success: function(data) {
var a1 = data.split(')');
var key = "";
for(i = 0; i < a1.length - 1; i++) {
if(i == 0) {
key = key + (a1[i].split(',')[0]).substr(1) + ",";
} else {
key = key + (a1[i].split(',')[0]).substr(2);
if(i < a1.length - 2) {
key = key + ",";
}
}
}
rst = eval('[' + key + ']');
}
});
return rst;
}
Y軸中每一項的值series採用count函式從檔案中讀取,count函式程式碼如下:
function count() {
var rst;
$.ajax({
type: "get",
async: false,
url: "/time/part-00000",
success: function(data) {
var a1 = data.split(')');
var b1 = "";
var key = "";
for(i = 0; i < a1.length - 1; i++) {
b1 = b1.concat(a1[i].split(',')[1]);
if(i < a1.length - 2) {
b1 = b1 + ",";
}
}
for(i = 0; i < a1.length - 1; i++) {
if(i == 0) {
key = key + (a1[i].split(',')[0]).substr(1) + ",";
} else {
key = key + (a1[i].split(',')[0]).substr(2);
if(i < a1.length - 2) {
key = key + ",";
}
}
}
rst = eval('[' + b1 + ']');
}
});
return rst;
}
第四步:編寫spark指令碼,在每次執行程式之前刪掉原來產生的結果檔案,參考程式碼如下:
import shutil
import os
path="/usr/share/nginx/html/time"
if os.path.exists(path):
shutil.rmtree(path)
第五步:設定Linux的計劃任務,通過crontab -e命令,在一定的間隔時間內,重新執行Spark程式,更新統計結果,實現資料的實時統計與展示。
最終效果如下圖所示: