linux流式訪問日志,流式實時日志分析系統的實現原理

我們知道網站用戶訪問流量是不間斷的,基于網站的訪問日志,即 Web log 分析是典型的流式實時計算應用場景。比如百度統計,它可以做流量分析、來源分析、網站分析、轉化分析。另外還有特定場景分析,比如安全分析,用來識別 CC 攻擊、 SQL 注入分析、脫庫等。這個項目就簡單實現一個類似于百度分析的系統。

實驗原理

百度統計(tongji.baidu.com)是百度推出的一款免費的專業網站流量分析工具,能夠告訴用戶訪客是如何找到并瀏覽用戶的網站的,以及在網站上瀏覽了哪些頁面。這些信息可以幫助用戶改善訪客在其網站上的使用體驗,不斷提升網站的投資回報率。

百度統計提供了幾十種圖形化報告,包括:趨勢分析、來源分析、頁面分析、訪客分析、定制分析等多種統計分析服務。

這里我們參考百度統計的功能,基于 Spark Streaming 簡單實現一個分析系統,使之包括以下分析功能。流量分析。一段時間內用戶網站的流量變化趨勢,針對不同的 IP 對用戶網站的流量進行細分。常見指標是總 PV 和各 IP 的PV。

來源分析。各種搜索引擎來源給用戶網站帶來的流量情況,需要精確到具體搜索引擎、具體關鍵詞。通過來源分析,用戶可以及時了解哪種類型的來源為其帶來了更多訪客。常見指標是搜索引擎、關鍵詞和終端類型的 PV 。

網站分析。各個頁面的訪問情況,包括及時了解哪些頁面最吸引訪客以及哪些頁面最容易導致訪客流失,從而幫助用戶更有針對性地改善網站質量。常見指標是各頁面的 PV 。

1 日志實時采集

Web log 一般在 HTTP 服務器收集,比如 Nginx access 日志文件。一個典型的方案是 Nginx 日志文件 + Flume + Kafka + Spark Streaming,如下所述:接收服務器用 Nginx ,根據負載可以部署多臺,數據落地至本地日志文件;

每個 Nginx 節點上部署 Flume ,使用 tail -f 實時讀取 Nginx 日志,發送至 KafKa 集群;

Spark Streaming 程序實時消費 Kafka 集群上的數據,實時分析,輸出;

結果寫入 MySQL 數據庫。

當然,還可以進一步優化,比如 CGI 程序直接發日志消息到 Kafka ,節省了寫訪問日志的磁盤開銷。這里主要專注 Spark Streaming 的應用,所以我們不做詳細論述。

2 流式分析系統實現

我們簡單模擬一下數據收集和發送的環節,用一個 Python 腳本隨機生成 Nginx 訪問日志,并通過腳本的方式自動上傳至 HDFS ,然后移動至指定目錄。 Spark Streaming 程序監控 HDFS 目錄,自動處理新的文件。

生成 Nginx 日志的 Python 代碼如下,保存為文件 sample_web_log.py 。#!/usr/bin/env?python#?-*-?coding:?utf-8?-*-import?random

import?timeclass?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?-1if?__name__?==?"__main__":

web_log_gene?=?WebLogGeneration()????#while?True:

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

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

這是一條日志的示例,為一行形式,各字段間用空格分隔,字符串類型的值用雙引號包圍:46.202.124.63?-?-?[2015-11-26?09:54:27]?"GET?/view.php?HTTP/1.1"?200?0?"http://www.google.cn/search?q=hadoop"?"Mozilla/5.0?(compatible;?MSIE?10.0;?Windows?NT?6.2;?Trident/6.0)"?"-"

然后需要一個簡單的腳本來調用上面的腳本以隨機生成日志,上傳至 HDFS ,然后移動到目標目錄:#!/bin/bash

#?HDFS命令?HDFS="/usr/local/myhadoop/hadoop-2.6.0/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?1done

Spark Streaming 程序代碼如下所示,可以在 bin/spark-shell 交互式環境下運行,如果要以 Spark 程序的方式運行,按注釋中的說明調整一下 StreamingContext 的生成方式即可。啟動 bin/spark-shell 時,為了避免因 DEBUG 日志信息太多而影響觀察輸出,可以將 DEBUG 日志重定向至文件,屏幕上只顯示主要輸出,方法是./bin/spark-shell 2>spark-shell-debug.log://?導入類import?org.apache.spark.SparkConfimport?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.?總PVlines.count().print()//?2.?各IP的PV,按PV倒序//???空格分隔的第一個字段就是IPlines.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.?搜索引擎PVval?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

("",?"")

})//?輸出搜索引擎PVsearchEnginInfo.filter(_._1.length?>?0).map(p?=>?{(p._1,?1)}).reduceByKey(_?+?_).print()//?4.?關鍵詞PVsearchEnginInfo.filter(_._2.length?>?0).map(p?=>?{(p._2,?1)}).reduceByKey(_?+?_).print()//?5.?終端類型PVlines.map(_.split("\"")(5)).map(agent?=>?{

val?types?=?Seq("iPhone",?"Android")????var?r?=?"Default"

for?(t?

r?=?t

}

(r,?1)

}).reduceByKey(_?+?_).print()//?6.?各頁面PVlines.map(line?=>?{(line.split("\"")(1).split("?")(1),?1)}).reduceByKey(_?+?_).print()//?啟動計算,等待執行結束(出錯或Ctrl-C退出)ssc.start()

ssc.awaitTermination()

打開兩個終端,一個調用上面的 bash 腳本模擬提交日志,一個在交互式環境下運行上面的 Streaming 程序。你可以看到各項指標的輸出,比如某個批次下的輸出為(依次對應上面的 6 個計算項):

總PV-------------------------------------------

Time:?1448533850000?ms

-------------------------------------------

44374

各IP的PV,按PV倒序-------------------------------------------?Time:?1448533850000?ms

-------------------------------------------?(72.63.87.30,30)

(63.72.46.55,30)

(98.30.63.10,29)

(72.55.63.46,29)

(63.29.10.30,29)

(29.30.63.46,29)

(55.10.98.87,27)

(46.29.98.30,27)

(72.46.63.30,27)

(87.29.55.10,26)

搜索引擎PV-------------------------------------------?Time:?1448533850000?ms?-------------------------------------------?(cn.bing.com,1745)

(www.baidu.com,1773)

(www.google.cn,1793)

(www.sogou.com,1845)

關鍵詞PV-------------------------------------------

Time:?1448533850000?ms

-------------------------------------------

(spark,1426)

(hadoop,1455)

(spark?sql,1429)

(spark?mlib,1426)

(hive,1420)

終端類型PV-------------------------------------------

Time:?1448533850000?ms

-------------------------------------------

(Android,4281)

(Default,35745)

(iPhone,4348)

各頁面PV-------------------------------------------

Time:?1448533850000?ms

-------------------------------------------

(/edit.php,6435)

(/admin/login.php,6271)

(/login.php,6320)

(/upload.php,6278)

(/list.php,6411)

(/index.html,6309)

(/view.php,6350)

查看數據更直觀的做法是用圖形來展示,常見做法是將結果寫入外部 DB ,然后通過一些圖形化報表展示系統展示出來。比如對于終端類型,我們可以用餅圖展示。

對于連續的數據,我們也可以用拆線圖來展示趨勢。比如某頁面的PV。

除了常規的每個固定周期進行一次統計,我們還可以對連續多個周期的數據進行統計。以統計總 PV 為例,上面的示例是每 10 秒統計一次,可能還需要每分鐘統計一次,相當于 6 個 10 秒的周期。我們可以利用窗口方法實現,不同的代碼如下://?窗口方法必須配置checkpint,可以這樣配置:?ssc.checkpoint("hdfs:///spark/checkpoint")

//?這是常規每10秒一個周期的PV統計?lines.count().print()

//?這是每分鐘(連續多個周期)一次的PV統計?lines.countByWindow(Seconds(batch*6),?Seconds(batch*6)).print()

使用相同的辦法運行程序之后,我們首先會看到連續 6 次 10 秒周期的 PV 統計輸出:-------------------------------------------

Time:?1448535090000?ms

-------------------------------------------

1101

-------------------------------------------

Time:?1448535100000?ms

-------------------------------------------

816

-------------------------------------------

Time:?1448535110000?ms

-------------------------------------------

892

-------------------------------------------

Time:?1448535120000?ms

-------------------------------------------

708

-------------------------------------------

Time:?1448535130000?ms

-------------------------------------------

881

-------------------------------------------

Time:?1448535140000?ms

-------------------------------------------

872

在這之后,有一個 1 分鐘周期的 PV 統計輸出,它的值剛好是上面 6 次計算結果的總和:-------------------------------------------

Time:?1448535140000?ms

-------------------------------------------

5270

最后

以上內容截選自實驗樓教程 【流式實時日志分析系統——《Spark 最佳實踐》】,教程主要是教你開發一個類似百度統計的系統,文章主要截選了其實驗原理部分,后面還有具體的開發部分:開發準備準備生成日志的Python代碼;

啟動Spark Shell;

實驗步驟創建日志目錄;

通過 bash 腳本生成日志;

在 Spark Streaming 中進行日志分析;

開始生成日志并查看結果;

作者:實驗樓

鏈接:https://www.jianshu.com/p/241bec487619

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/534572.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/534572.shtml
英文地址,請注明出處:http://en.pswp.cn/news/534572.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

linux無法切換shell,linux shell的切換

查看系統可用shell種類:(一般是bash shell)? ~ chsh -l/bin/sh/bin/bash/sbin/nologin/bin/dash/bin/zsh修改當前的shell:[rootGIT ~]# chsh -l/bin/sh/bin/bash/sbin/nologin/bin/dash/bin/zsh[rootGIT ~]# chshChanging shell for root.New shell [/bin/bash]: /…

64位ubuntu arm-linux-gcc,在ubuntu 64位的機器上執行arm-linux-gcc提示 no such file or directory【轉】...

解壓好了arm-linuxg-gcc 放到了$PATH路徑下, 無論怎么執行都提示說: no such file or directory,可明明有這個文件的.N遍之后, 執行了 file arm-Linux-gcc發現這個命令是32位的, 需要安裝兼容包,于是apt-get install libc6:i386 libgcc1:i386 gcc-4.6-base:i386:ia32-libslibst…

c語言for循環26個英文字母,菜鳥求助,寫一個隨機輸出26個英文字母的程序

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓#include #include // 用srand、rand函數了#include // 用time函數了#define LEN 32// 產生min~max的隨機數 (包含min和max)// rand函數產生0 ~ RAND_MAX 的隨機數// 一般上不同編譯器要求 RAND_MAX 的值(至少)為 32767#define RAN…

C語言case字句有什么作用,switch?case?語句的使用規則

【規則1-21】按字母或數字順序排列各條case語句。如果所有的case語句沒有明顯的重要性差別,那就按A-B-C或1-2-3等順序排列case語句。這樣做的話,你可以很容易的找到某條case語句。比如:switch(variable){case A://program codebreak;case B:/…

c語言怎樣用格式化文件存儲,如何用格式化的方式讀寫文件

對格式會來說,C語言的格式讀寫文件是很有要求的,在前面我們已經講解了如何去進行字符的輸入輸出,但事實真相,數據的類型是很豐富的,而且大家已經熟悉了用printf和scanf函數進行格式化的輸入輸出,他們是向終…

輸出26個英文字母c語言,菜鳥求助,寫一個隨機輸出26個英文字母的程序

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓#include #include // 用srand、rand函數了#include // 用time函數了#define LEN 32// 產生min~max的隨機數 (包含min和max)// rand函數產生0 ~ RAND_MAX 的隨機數// 一般上不同編譯器要求 RAND_MAX 的值(至少)為 32767#define RAN…

二階矩陣乘法C語言,c語言矩陣相乘

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓程序清單#include&nbspint&nbspmain(void){&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspchar&nbsp&nbsp&nbsp&nbspa[2][3];&nbsp&nbsp&nbsp&nbsp&nbsp…

c語言dll創建線程,教大家寫一個遠程線程的DLL注入,其實還是蠻簡單的……………………...

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓然后新建一個win32 application 的工程 新建c source file 寫入:#include#includeint WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd){char DllName[MAX_PATH]"C:\\P…

linux下qq怎么截圖,ubuntu 12.04使用QQ截圖安裝教程

相信用過linux系統的朋友都知道,linux下的截圖軟件是在不咋的。雖然系統本身有帶截圖工具,但是卻苦于沒有辦法在截下來的圖片上作畫圈、寫文字說明等動作。應該有不少朋友也是從windows系統下轉到linux下做開發的,不知道大家對QQ截圖這個軟件…

android對象申明,Kotlin中的對象表達式和對象聲明的具體使用

Kotlin的對象表達式與Java中的匿名內部類的主要區別:匿名內部類只能指定一個父類型,但對象表達式可以指定0~N個膚類型。一、對象表達式對象表達式的語法格式如下:object [: 0~N個父類型]{//對象表達式的類體部分}對象表達式還有如下規則&…

android+聯系服務器時間,android配置時間服務器+亞洲主要的授時服務器

我們知道,Android是通過連接指定的ntpServer來獲取網絡時間,而不同的服務器帶來的延遲也不盡相同,通常情況下,我們自然是期望盡快獲取時間,那么我們就需要對ntpServer有一定的篩選,尤其是在選擇默認的ntpSe…

android 獲取設備的mac地址,Android編程獲取設備MAC地址的實現方法

本文實例講述了Android編程獲取設備MAC地址的實現方法。分享給大家供大家參考,具體如下:/*** 獲取設備的mac地址** param ac* param callback* 成功獲取到mac地址之后會回調此方法*/public static void getMacAddress(final Activity ac, final SimpleCa…

android 資源如何下沉,關于Android業務模塊下沉的一些實踐及總結

此文已由作者徐銘陽授權網易云社區發布。歡迎訪問前言最近在做需求過程中,一些類似學校選擇、城市選擇等業務相關模塊想單獨抽離出來,遇到一些諸如模塊管理、通信方面的問題來背景最近有一個需求是學校列表,沒錯,就是我們平時總見…

android sqlite存儲數據,Android之SQLite數據存儲

關于SQLite的出生長大和壯大,這里就略去了,只記幾點比較重要的用法:SQLite所支持的數據類型:SQLite,SQLite3支持 NULL、INTEGER、REAL(浮點數字)、TEXT(字符串文本)和BLOB(二進制對象)數據類型,雖然它支持的…

android gridview滾動條位置,Android GridView滾動到指定位置

當一個列表項目很多,并且每個項目可以進入到其它Activity或者Fragment時,保存之前列表的位置是一個比較不錯的功能,今天研究了一下怎么保存瀏覽位置,發現GridView和它的父類中有4個相關的方法:public void smoothScrol…

android studio 跨進程,Android IPC機制(三)在Android Studio中使用AIDL實現跨進程方法調用...

本文首發于微信公眾號「后廠技術官」在上一篇文章Android IPC機制(二)用Messenger進行進程間通信中我們介紹了使用Messenger來進行進程間通信的方法,但是我們能發現Messenger是以串行的方式來處理客戶端發來的信息,如果有大量的消息發到服務端&#xff0…

nubia ui 5.0 android,流暢度爆棚 搭Android 5.0系統新機一覽

近期各品牌新機都不少,而且90%以上都是Android系統的手機,可見安卓手機的主導地位仍在上升。而在系統層次,Android 5.0已經逐步開始普及,近期上市新機百分百均采用了這一系統,值得一提的是定制不再“深度”&#xff0c…

signature=4d4ce610ff2d4a5f2093452c24b70492,Reading Chromatin Signatures

摘要:The article cites a study which uses a combination of chromatin immunoprecipitation and microarray analysis to explore the histone modifications, transcription-factor binding and nucleosome density in 30 megabytes of human genome. It states…

html 百分比正方形,css實現未知寬度的正方形需求

今天群里有哥們問了一下,百分比寬度的正方形如何用css實現。其實就是不定寬的正方形如何用css實現。第一個方法利用圖片的等比例縮放,用base64寫一個1*1的透明png圖片,寬度100%,這樣容器就自動被撐成一個正方形,demo如…

html引用本地圖片不能是桌面的,Img標簽與本地文件:/// URL不顯示在Microsoft Edge Web瀏覽器...

在我的桌面應用程序中,我創建了一個臨時HTML文件(旨在讓用戶打印報告),然后通過默認顯示網頁瀏覽器。這個HTML文件保存在一個臨時文件夾,例如:C:/Users/UserName/AppData/Local/TempImg標簽與本地文件:/// URL不顯示在…