透過 ElasticSearch + Fluentd + GeoIP Plugin 實現訪客流量分析地圖
前陣子需要一種地圖報表,像是 Google Analytics 的那種世界地圖,可以看出來訪客與流量來自哪裡,以便進行訪客流量分析。雖然用 GA 或 OpenSource Piwik 也可以做的到,但是一些不是 Web Page 的 API 的呼叫還要另外整合 Record API,同時也不方便同時統計一大推 Virtual Host。想想其實透過 Web Server Access Log 也可以做到一樣的效果,剛好前陣子,我把所有的 Log 都餵進 ElasticSearch 資料庫進行儲存,透過 Kibana 建立一些常用的檢測報表,可以同時蒐集與整合分析好幾台主機的 Log,不管是 Apache, Nginx, NodeJS 都可以一起進來,集中管理還蠻方便的,完整的 Log Server 建置可以參考這一篇文章的介紹。今天的介紹會用到 Fluentd 來讀取 Log File,蒐集後透過 GeoIP Plugin 解析 Remote Address,換算成地理座標位置,最後傳送到 ElasticSearch 集中儲存。在此記錄一下實現步驟,以後好回顧使用。其實改用 log-stash 更簡單更方便,只是我那時候剛好比較熟 Fluentd,log-stash 剛碰不久,未來有心得再分享了。
安裝 Fluentd, GeoIP Plugin 與 ElasticSearch Plugin
由於我有不同 Linux Distribution,因此介紹一下 CentOS 與 Ubuntu 的安裝方式。
CentOS 安裝 Fluentd (td-agent)
sudo curl -L https://toolbelt.treasuredata.com/sh/install-redhat-td-agent2.sh | sh sudo td-agent-gem install fluent-plugin-elasticsearch sudo sed -i.`date +%F` 's/TD_AGENT_USER\=td\-agent/TD_AGENT_USER\=root/g;s/TD_AGENT_GROUP\=td\-agent/TD_AGENT_GROUP\=root/g' /etc/init.d/td-agent sudo mv /etc/td-agent/td-agent.conf /etc/td-agent/td-agent.conf.orig && mkdir /etc/td-agent/td-agent.conf.d sudo cp /dev/null /etc/td-agent/td-agent.conf sudo echo '@include td-agent.conf.d/*.conf' > /etc/td-agent/td-agent.conf
CentOS 安裝 GeoIP Library 與 Fluentd GeoIP Plugin
sudo yum install GeoIP-devel sudo yum install GeoIP-GeoLite-data-extra.noarch sudo td-agent-gem install fluent-plugin-geoip
Ubuntu 安裝 Fluentd (td-agent)
sudo curl -L https://toolbelt.treasuredata.com/sh/install-ubuntu-trusty-td-agent2.sh | sh sudo apt-get -y install libgeoip-dev sudo td-agent-gem install fluent-plugin-elasticsearch sudo sed -i.`date +%F` 's/TD_AGENT_USER\=td\-agent/TD_AGENT_USER\=root/g;s/TD_AGENT_GROUP\=td\-agent/TD_AGENT_GROUP\=root/g' /etc/init.d/td-agent sudo mv /etc/td-agent/td-agent.conf /etc/td-agent/td-agent.conf.orig && mkdir /etc/td-agent/td-agent.conf.d sudo cp /dev/null /etc/td-agent/td-agent.conf sudo echo '@include td-agent.conf.d/*.conf' > /etc/td-agent/td-agent.conf
Ubuntu 16.04 安裝 GeoIP Library 與 Fluentd GeoIP Plugin
sudo apt-get install build-essential libgeoip-dev libmaxminddb-dev sudo apt-get install geoip-database-extra sudo td-agent-gem install fluent-plugin-geoip
Ubuntu 14.04 安裝 GeoIP Library 與 Fluentd GeoIP Plugin
sudo apt-get install make ruby-dev libcurl4-gnutls-dev libgeoip-dev autoconf sudo apt-get install geoip-database libtool shtool sudo td-agent-gem install fluent-plugin-geoip
建立 Access Log 專用的 Index Template
ElasticSearch 有一個專門用來存放地理位置的資料型態,叫做「geo_point」,在倒資料之前要先準備好 Mapping 資訊,Mapping 有點像是 RDBMS 中的 Schema,設定 Mapping 是為了讓 ElasticSearch 知道用什麼方式建立索引。由於 Fluentd 預設使用的 index 名稱是以日期來命名,因此需要借助 Index Template 來自動建立新索引的 Mapping。ElasticSearch API 如下:
PUT _template/logstash { "template":"logstash-*", "settings":{ }, "mappings":{ "log":{ "properties":{ "location":{ "type":"geo_point" }, "size":{ "type":"number" }, "remote":{ "type":"ip" } } } } }
透過 Kibana Dev Tools 執行畫面如下:
如此,未來如果有建立 logstash- 開頭的索引,就會自動套用以上 Mapping,這裡比較重要的是 location 設定成為 geo_point 用來存放「經緯度」地理資訊。
利用 ElasticSearch 搜集 Appche Log 資料並使用 Kibana 產生圖表
先編輯一個新的 td-agent 設定檔,可以由 Apache Access Log File Parse 資料存進 ElasticSearch。下述的設定檔先在 <source> Block 透過 format 找出 Line Log 記錄的 Client IP Address 並且設定為 remote 參數,接著透過 <match> Block 將設定好的 tag 傳遞給 GeoIP Library,便可由資料庫中找出 Remote IP Address 對應的地理位置資訊,並且附加到 Document geoip 與 location 中,最後傳到 ElasticSearch 進行儲存,如下:
sudo vim /etc/td-agent/td-agent.conf.d/apache.conf
設定檔內容如下:
<source> @type tail path /var/log/apache2/other_vhosts_access.log pos_file /var/log/td-agent/apache2-access.log.pos tag ori.apache.access read_from_head true format /^(?<host>[^ ]*) (?<remote>[^ ]*) - (?<user>[^ ]*)- \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?.*$/ time_format %d/%b/%Y:%H:%M:%S %z </source> <match ori.apache.access> @type geoip geoip_database /usr/share/GeoIP/GeoIPCity.dat geoip_lookup_key remote <record> location ${latitude["remote"]},${longitude["remote"]} geoip.location.lat ${latitude["remote"]} geoip.location.lon ${longitude["remote"]} geoip.country_code3 ${country_code3["remote"]} geoip.country ${country_code["remote"]} geoip.country_name ${country_name["remote"]} geoip.dma ${dma_code["remote"]} geoip.area ${area_code["remote"]} geoip.region ${region["remote"]} geoip.city ${city["remote"]} </record> remove_tag_prefix ori. add_tag_prefix es. </match> <match es.**> @type elasticsearch host 192.168.32.243 port 9200 index_name logstash-apache logstash_format true type_name ubuntu include_tag_key true flush_interval 5s </match>
設定檔完成後記得重新啟動 td-agent
service td-agent restart
我們設定每 5S 同步資料到 ElasticSearch,之後有 Log 可以先去 Kibana 看看 index 有沒有自動建出來,透過 Dev Tools 進行 Query,如下:
GET logstash-2018.01.31/_search { "query": { "match_all": {} } }
如果有問題可以查看 /var/log/td-agent/* Log File,接著在 Kibana Management 功能中先導入 logstash-* Index,如果成功就可以繼續建立圖表了。
透過 Kibana 建立 Maps Visualize 圖表
進入 Kibana 後,選擇左邊的「Visualize」接著選擇「Maps」,如下:
進入後設定「Geo Coordinates」為我們產生的 location 欄位,如果沒有出現表示 Mapping 有誤,請檢查 Mapping 是否正確。如下:
建立以後就可以看到地圖上面出現資料囉,一旦 ElasticSearch 有了 Access Log 就可以在 Kibana 建立各種類型的報表,對於雲服務的營運很有幫助。如果一些 API 的規格設計就遵循 REST 風格,那麼在 Access Log 就會有更多資訊可以分析,以後報表不需要再手刻了,靠這些工具進行流量分析就可以省下不少時間囉。