日志分析系統(tǒng)ELK搭建
ELK
ELK是日志收集、索引與檢索三件套,包含了三個(gè)組件
- ElasticSearch
- Logstash
- Kibana
其中ElasticSearch完成日志的索引,并提供查詢接口,Logstash完成日志的收集,Kibana則提供可視化展示
有了ELK,我們不再需要到線上的每一臺(tái)機(jī)器上grep日志,而且能可視化查詢?nèi)魏文阆氩樵兊娜罩拘畔ⅰMㄟ^Kibana能非常直接漂亮的展示很多信息,ELK還能作為監(jiān)控系統(tǒng)使用。先看看效果圖:

機(jī)器要求
三臺(tái)機(jī)器,機(jī)器的配置視線上日志量而定
ES集群:三臺(tái)機(jī)器
Logstash:一臺(tái)機(jī)器
Kibana:一臺(tái)機(jī)器
其中一臺(tái)機(jī)器不存儲(chǔ)ES數(shù)據(jù),這臺(tái)機(jī)器同時(shí)安裝了ES、Logstash和Kibana
架構(gòu)
系統(tǒng)架構(gòu)圖如下

- Shipper安裝在每一臺(tái)需要收集日志的客戶機(jī)上,即需要在每一臺(tái)客戶機(jī)上安裝logstash
- Redis作為中轉(zhuǎn)
- Indexer安裝在服務(wù)器上
- Kibana提供可視化展示
軟件版本
ElasticSearch:5.0.2
Logstash:5.1.1
Kibana:5.0.2
1. Java
1.1 Java版本要求
java版本要求為1.8+,最低版本為1.8
1.2 Centos Java版本升級(jí)
查看java版本
java -version
如果版本號(hào)達(dá)不到要求則需要升級(jí)java版本
1.2.1 下載java 1.8 jdk
前往地址http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
下載tar.gz結(jié)尾的jdk文件進(jìn)行下載
1.2.2 上傳至服務(wù)器
使用rz命令將下載的jdk8上傳到服務(wù)器的/usr/lib/jvm 目錄下
使用命令解壓
tar -xzf jdk-8u111-linux-x64.tar.gz
1.2.3 加入到alternatives列表中
alternatives --install /usr/bin/java java /usr/lib/jvm/jdk1.8.0_111/bin/java 400
1.2.4 更改java版本號(hào)
alternatives --config java
選擇java 8對(duì)應(yīng)的序號(hào)即可。
1.2.5 查看java版本號(hào)
1.2.6 卸載系統(tǒng)自帶jdk
如果不卸載會(huì)致使elasticsearch沒法運(yùn)行
詳見:http://linux.it.net.cn/CentOS/server/set/2014/1006/6242.html
2. 安裝Elasticsearch
切記不要以root身份安裝
安裝教程:https://www.elastic.co/guide/en/elasticsearch/reference/5.0/zip-targz.html
選擇通過tar.gz文件安裝
啟動(dòng)elasticsearch時(shí)遇到三種類型的錯(cuò)誤(WARN):
- log文件寫入無(wú)權(quán)限,解決辦法:root用戶下chmod加權(quán)限
- CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER,可以忽略,不影響啟動(dòng)
- max file descriptors,root用戶下修改配置文件vim /etc/security/limits.conf,將soft nofile和hard nofile的值全部改為65536,保存推出,重新登錄
- max virtual memory,root用戶下執(zhí)行命令sysctl -w vm.max_map_count=262144
java.lang.UnsupportedOperationException: seccomp unavailable: requires kernel 3.5+ with CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER compiled in
at org.elasticsearch.bootstrap.Seccomp.linuxImpl(Seccomp.java:349) ~[elasticsearch-5.0.2.jar:5.0.2]
at org.elasticsearch.bootstrap.Seccomp.init(Seccomp.java:630) ~[elasticsearch-5.0.2.jar:5.0.2]
at org.elasticsearch.bootstrap.JNANatives.trySeccomp(JNANatives.java:215) [elasticsearch-5.0.2.jar:5.0.2]
at org.elasticsearch.bootstrap.Natives.trySeccomp(Natives.java:99) [elasticsearch-5.0.2.jar:5.0.2]
at org.elasticsearch.bootstrap.Bootstrap.initializeNatives(Bootstrap.java:104) [elasticsearch-5.0.2.jar:5.0.2]
at org.elasticsearch.bootstrap.Bootstrap.setup(Bootstrap.java:158) [elasticsearch-5.0.2.jar:5.0.2]
at org.elasticsearch.bootstrap.Bootstrap.init(Bootstrap.java:291) [elasticsearch-5.0.2.jar:5.0.2]
at org.elasticsearch.bootstrap.Elasticsearch.init(Elasticsearch.java:121) [elasticsearch-5.0.2.jar:5.0.2]
at org.elasticsearch.bootstrap.Elasticsearch.execute(Elasticsearch.java:112) [elasticsearch-5.0.2.jar:5.0.2]
at org.elasticsearch.cli.SettingCommand.execute(SettingCommand.java:54) [elasticsearch-5.0.2.jar:5.0.2]
at org.elasticsearch.cli.Command.mainWithoutErrorHandling(Command.java:96) [elasticsearch-5.0.2.jar:5.0.2]
at org.elasticsearch.cli.Command.main(Command.java:62) [elasticsearch-5.0.2.jar:5.0.2]
at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:89) [elasticsearch-5.0.2.jar:5.0.2]
at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:82) [elasticsearch-5.0.2.jar:5.0.2]
****
ERROR: bootstrap checks failed
max file descriptors [65535] for elasticsearch process is too low, increase to at least [65536]
max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
解決完上述問題后退出重新以普通用戶身份登錄,重新啟動(dòng)elasticsearch
瀏覽器訪問http://ip:port/
這里的ip和port是在ElasticSearch的配置文件中配置的
訪問效果如下:

ElasticSearch集群配置
參考https://my.oschina.net/shyloveliyi/blog/653751
可以在同一臺(tái)機(jī)器上的不同節(jié)點(diǎn)配置集群,也可以在不同機(jī)器上配置集群,測(cè)試中采用的是后一種方式。
實(shí)際的配置如下:
cluster.name: es-cluster
node.name: node0
path.data: /tmp/elasticsearch/data
path.logs: /tmp/elasticsearch/logs
network.host: ***
http.port: 9200
discovery.zen.ping.unicast.hosts: ["***"]
該配置說(shuō)明如下:
- cluster.name,集群名,同一個(gè)集群下配置同一個(gè)名字
- node.name,節(jié)點(diǎn)名,同一個(gè)集群下不同節(jié)點(diǎn)配置不同的名稱
- path.data,數(shù)據(jù)存儲(chǔ)目錄,生產(chǎn)環(huán)境中需要指定一個(gè)容量比較大的磁盤
- path.logs,日志存儲(chǔ)目錄
- network.host,本機(jī)ip
- http.port,默認(rèn)為9200
- discovery.zen.ping.unicast.hosts,集群中其他機(jī)器的ip地址
配置完畢后重啟ES,另一臺(tái)機(jī)器上配置類似后重啟,ES即可自動(dòng)發(fā)現(xiàn)。
訪問http://ip:port/_cat/health?v查看集群狀態(tài)

node.total=2表示集群中有兩個(gè)節(jié)點(diǎn)
集群配置完畢后,集群間的數(shù)據(jù)是共享的。即使其中任何一臺(tái)機(jī)器掛了,通過另一臺(tái)機(jī)器也能訪問全部的數(shù)據(jù)。
查看集群master狀態(tài)
http://ip:port/_cat/master?pretty
ElasticSearch刪除索引
使用命令
curl -XDELETE 'http://ip:port/logstash-2016.12.12?pretty'
其中l(wèi)ogstash-2016.12.12為索引名
查看ElasticSearch所有索引
ES后臺(tái)運(yùn)行
一般來(lái)說(shuō)我們不希望關(guān)閉終端時(shí),ES進(jìn)程中止,這時(shí)需要以后臺(tái)運(yùn)行的方式運(yùn)行ES
./elasticsearch -d
安裝xpack
鏈接https://www.elastic.co/downloads/x-pack
按照教程來(lái)就行,如果下載比較慢,可以先下載到本地然后上傳到服務(wù)器。
使用本地文件安裝的命令:
./elasticsearch-plugin install file:///search/odin/xpackfilename
注意:安裝完xpack后會(huì)導(dǎo)致訪問es需要認(rèn)證,可以在配置文件中將其關(guān)閉,在elasticsearch.yml中添加如下配置
# x-pack
xpack.security.enabled: false
xpack.monitoring.enabled: true
xpack.graph.enabled: false
xpack.watcher.enabled: false
重啟es即可
3. 安裝logstash
logstash要求java版本為1.8及以上
安裝過程為下載tar.gz文件后上傳至服務(wù)器
3.1 配置文件
在logstash的config同級(jí)目錄下新建etc文件夾用于存放配置文件,新建配置文件es-test.conf,內(nèi)容如下:
input
{
file
{
path =>"/home/contentdev/elk/test.log"
}
}
output
{
elasticsearch{
hosts => ["ip:port"]
index => "logstash-%{type}-%{+YYYY.MM.dd}"
}
}
具體的釋義見https://www.elastic.co/products/logstash
大致解釋如下:
- input:從指定的文件中讀取內(nèi)容
- output:存儲(chǔ)至指定的es中,index為索引名,自定義
3.2 測(cè)試配置文件語(yǔ)法是否正確
執(zhí)行命令:
./logstash -t -f ../etc/es-test.conf
測(cè)試過程中可能遇到如下錯(cuò)誤:
Could not find any executable java binary. Please install java in your PATH or set JAVA_HOME.
使用命令打印出JAVA_HOME的值:
echo $JAVA_HOME
看看是否正確,如果不正確,則切換到root角色登錄,修改配置文件/etc/profile,在末尾設(shè)置JAVA_HOME
export JAVA_HOME=/usr/lib/jvm/jdk1.8.0_111
export PATH=$PATH:$JAVA_HOME/bin
設(shè)置完后執(zhí)行命令
source /etc/profile
重新以普通用戶的身份登錄,再次執(zhí)行測(cè)試命令即可
3.3 正式啟動(dòng)logstash
以后臺(tái)執(zhí)行的方式啟動(dòng)
nohup ./logstash -f ../etc/redis-test.conf --config.reload.automatic &
3.4 寫入測(cè)試數(shù)據(jù)
向/home/contentdev/elk/test.log中寫入測(cè)試數(shù)據(jù)
3.5 訪問elasticsearch
訪問elasticsearch驗(yàn)證數(shù)據(jù)是否被存儲(chǔ)
3.6 使用grok解析日志
關(guān)于logstash中的grok插件正則表達(dá)式的例子詳見:http://blog.csdn.net/liukuan73/article/details/52318243
3.7 服務(wù)端logstash配置文件
服務(wù)端的logstash可能需要從redis中讀取多個(gè)key的日志信息存儲(chǔ)到不同的ES索引中,這時(shí)可以在配置文件中使用type來(lái)表示。
input
{
redis { type => "A-nginx-log" host => "***" port => ** password => "***" data_type => "list" key => "A_nginx_log"}
redis { type => "B-nginx-log" host => "***" port => *** password => "***" data_type => "list" key => "B_nginx_log" }
}
output
{
elasticsearch{
hosts => ["ip:port"]
index => "%{type}-%{+YYYY.MM.dd.HH}"
}
}
最終的索引名會(huì)包含type,ES的索引名最好能包含日期,這樣方便歸類以及按日期刪除
elasticsearch中的hosts最好是配置為不存儲(chǔ)數(shù)據(jù)的那臺(tái)機(jī)器。
3.8 安裝xpack
安裝命令跟es安裝xpack類似,安裝完畢后需要在配置文件logstash.yml最后加上一行
xpack.monitoring.elasticsearch.url: "http://**:9200"
4. 安裝kibana
安裝流程詳見:https://www.elastic.co/guide/en/kibana/current/targz.html
安裝完畢后需要配置config下的kibana.yml配置文件,配置一下幾項(xiàng)即可:
- server.port:5601,打開注釋即可
- server.host,配置本機(jī)ip,啟動(dòng)后可以通過ip+端口訪問
- elasticsearch.url,配置es的域名(ip)+端口
- kibana.index,打開注釋即可

4.1 啟動(dòng)kibana
cd到bin目錄,執(zhí)行下面的命令
nohup ./kibana &
4.2 訪問web頁(yè)面
如果es中已經(jīng)存在index,kibana會(huì)自動(dòng)展示出來(lái)
4.3 安裝xpack
同elasticsearch安裝xpack教程一樣
安裝完畢后即可在左側(cè)看到monitoring等新面板
5. Redis
Redis在ELK系統(tǒng)中可以扮演兩種角色:消息訂閱和消息中轉(zhuǎn)。Redis存在的意義是為了解決log寫入ES的瓶頸。
- 消息訂閱。自行g(shù)oogle
- 消息中轉(zhuǎn)。該模式下,shipper將日志內(nèi)容寫入到redis中,indexer從redis中讀取并存入ES
本次搭建采用第二種模式。需要說(shuō)明的是,indexer從redis中讀取相應(yīng)的數(shù)據(jù)后會(huì)將其刪除,不會(huì)導(dǎo)致redis中數(shù)據(jù)的堆積
6. ELK系統(tǒng)監(jiān)控與報(bào)警
ELK系統(tǒng)可能出現(xiàn)的問題
-
進(jìn)程死亡
-
ES進(jìn)程死亡,如果是logstash indexer寫入的機(jī)器ES進(jìn)程死亡,會(huì)導(dǎo)致數(shù)據(jù)無(wú)法存入ES,但不清楚redis中的數(shù)據(jù)能否被正常消耗
-
解決辦法:
腳本定時(shí)檢查ES進(jìn)程是否存活,死亡則郵件報(bào)警
-
-
logstash shipper進(jìn)程死亡,會(huì)導(dǎo)致客戶機(jī)的日志無(wú)法被收集
-
解決辦法:
腳本定時(shí)檢查進(jìn)程是否存活
-
-
logstash indexer進(jìn)程死亡,會(huì)導(dǎo)致redis中暫存的數(shù)據(jù)堆積,撐爆redis
- 解決辦法:
- 腳本定時(shí)檢查ES進(jìn)程是否存活,死亡則郵件報(bào)警
- redis用量預(yù)警,如果系統(tǒng)運(yùn)行正常,redis的用量應(yīng)該是在一個(gè)比較穩(wěn)定的數(shù)值,異常時(shí)會(huì)導(dǎo)致redis用量激增
- 解決辦法:
-
-
機(jī)器宕機(jī)
- 檢查redis用量
-
ES數(shù)據(jù)存儲(chǔ)磁盤空間不足
- 使用監(jiān)控腳本監(jiān)控磁盤用量并配置報(bào)警
總的來(lái)說(shuō),系統(tǒng)異??梢酝ㄟ^以下方式發(fā)現(xiàn)
- 腳本檢查進(jìn)程存活狀態(tài)
- redis用量是否正常
- 監(jiān)控腳本上報(bào)磁盤使用量
7. ES數(shù)據(jù)定期刪除
如果不刪除ES數(shù)據(jù),將會(huì)導(dǎo)致ES存儲(chǔ)的數(shù)據(jù)越來(lái)越多,磁盤滿了之后將無(wú)法寫入新的數(shù)據(jù)。這時(shí)可以使用腳本定時(shí)刪除過期數(shù)據(jù)。
#/bin/bash
#es-index-clear
#只保留15天內(nèi)的日志索引
LAST_DATA=`date -d "-15 days" "+%Y.%m.%d"`
#刪除上個(gè)月份所有的索引
curl -XDELETE 'http://ip:port/*-'${LAST_DATA}'*'
可以視個(gè)人情況調(diào)整保留的天數(shù),這里的ip和port同樣設(shè)置為不存儲(chǔ)數(shù)據(jù)的那臺(tái)機(jī)器。該腳本只需要在ES中一臺(tái)機(jī)器定時(shí)運(yùn)行即可。
crontab -e添加定時(shí)任務(wù):
0 1 * * * /search/odin/elasticsearch/scripts/es-index-clear.sh
每天的凌晨一點(diǎn)清除索引。
8. 其他
- 存儲(chǔ)到ES的數(shù)據(jù)會(huì)有一個(gè)字段名為@timestamp,該時(shí)間戳和北京時(shí)間差了8小時(shí),不需要進(jìn)行調(diào)整,Kibana在展示的時(shí)候會(huì)自動(dòng)加上8小時(shí)