簡介
對於日誌來說,最常見的需求就是收集、存儲、查詢、展示,開源社區正好有相對應的開源項目:logstash(收集)、elasticsearch(存儲+搜索)、kibana(展示),我們將這三個組合起來的技術稱之爲ELK,所以說ELK指的是Elasticsearch、Logstash、Kibana技術棧的結合。ELK對外作爲一個日誌管理系統的開源方案,能夠可靠和安全地從任何格式的任何來源獲取數據,並實時搜索、分析和可視化。
1 Elasticsearch
elasticsearch是一個高可擴展的、開源的、全文本搜索和分析的引擎。它能夠近乎實時地存儲,檢索和分析大量數據,通常用作底層引擎/技術,爲具有複雜搜索特性和需求的應用程序提供動力。
elasticsearch的底層是開源庫 Lucene。但是,你沒法直接用 Lucene,必須自己寫代碼去調用它的接口。Elastic 是 Lucene 的封裝,提供了 REST API 的操作接口,開箱即用。
1.1節點和集羣
elasticsearch 本質上是一個分佈式數據庫,允許多臺服務器協同工作,每臺服務器可以運行多個 elasticsearch 實例。單個 elasticsearch 實例稱爲一個節點(node)。一組節點構成一個集羣(cluster)。
1.2索引(Index)
elasticsearch 會索引所有字段,經過處理後寫入一個反向索引(Inverted Index)。查找數據的時候,直接查找該索引。所以,elasticsearch 數據管理的頂層單位就叫做 Index(索引)。它是單個數據庫的同義詞。每個 Index (即數據庫)的名字必須是小寫。
下面的命令可以查看當前節點的所有 Index。
curl -X GET ‘http://localhost:9200/_cat/indices?v’
1.3文檔(Document)
索引裏面的單條記錄稱爲文檔(Document),多個文檔就組成了一個索引。文檔是用JSON格式表示。同一個索引的文檔不要求有相同的結構(scheme),但是最好保持相同,這樣有利於提高搜索效率。一個簡單的文檔示例:
{
“user”: “張三”,
“profession”: “java工程師”,
}
1.4 碎片和副本
索引可能存儲大量數據,超出單個節點的硬件限制。例如,一個包含10億個文檔的索引佔用了1TB的磁盤空間,它可能不適合於單個節點的磁盤,或者可能太慢,無法單獨爲單個節點提供搜索請求。爲了解決這個問題,Elasticsearch提供了將索引細分爲多個碎片的功能。當你創建索引時,可以簡單地定義你想要的碎片的數量。每個碎片本身都是一個功能齊全、獨立的“索引”,可以駐留在集羣中的任何節點上。
總而言之,每個索引可以分成多個碎片。一個索引也可以被複制零次(意思是沒有副本)或多次。一但複製,每個索引將具有主碎片(原始碎片)和複製碎片(主碎片的副本)。在創建索引時,每個索引可以定義碎片和副本的數量。默認情況下,Elasticsearch中的每個索引分配5個主碎片和1個副本。
關於elasticsearch的深入瞭解請參考elastic官方網站:https://www.elastic.co/cn/
2 Logstash
Logstash是一個開源數據收集引擎,具有實時管道功能。Logstash可以動態地將來自不同數據源的數據統一起來,並將數據標準化到你所選擇的目的地。
2.1管道
logstash的事件處理管道通常具有一個或多個的輸入插件、過濾器、輸出插件。logstash的事件處理通常分爲三個階段:輸入→過濾器→輸出。
2.2輸入
數據往往以各種各樣的形式,或分散或集中地存在於很多系統中。Logstash 支持各種輸入選擇 ,可以在同一時間從衆多常用來源捕捉事件。能夠以連續的流式傳輸方式,輕鬆地從您的日誌、指標、Web 應用、數據存儲以及各種 AWS 服務採集數據。
logstash使用輸入插件實現數據導入。常用的輸入插件如下:
插件 | 說明 |
---|---|
tcp | 從TCP套接字讀取事件 |
http | 從http請求中讀取事件 |
file | 從文件中讀取 |
beats | 從Elastic Beats框架接收事件 |
kafka | 從kafka中讀取 |
rabbitmq | 從rabbitmq中讀取 |
redis | 從Redis實例讀取事件 |
log4j | 從Log4j SocketAppender對象通過TCP讀取事件 |
elasticsearch | 從Elasticsearch集羣讀取 |
jdbc | 從jdbc數據中讀取 |
websocket | 從網絡套接字讀取事件 |
Filebeat客戶端是一個輕量級的、資源友好的工具,它從服務器上的文件中收集日誌,並將這些日誌轉發到你的Logstash實例以進行處理。Filebeat設計就是爲了可靠性和低延遲。Filebeat在主機上佔用的資源很少,而且Beats input插件將對Logstash實例的資源需求降到最低。
關於更多輸入插件參照:
https://www.elastic.co/guide/en/logstash/current/input-plugins.html
2.3 過濾器
數據從源傳輸到存儲庫的過程中,Logstash 過濾器能夠解析各個事件,識別已命名的字段以構建結構,並將它們轉換成通用格式,以便更輕鬆、更快速地分析和實現商業價值。
Logstash 能夠動態地轉換和解析數據,不受格式或複雜度的影響。常用的過濾器如下:
1.grok插件:解析並構造任意文本。Grok是目前Logstash中將非結構化日誌數據解析爲結構化和可查詢內容的最佳方式。有了內置於Logstash的120種模式,很可能會找到滿足需求的模式!
2.ruby插件: 官方對ruby插件的介紹是無所不能。ruby插件可以使用任何的ruby語法,無論是邏輯判斷,條件語句,循環語句,還是對字符串的操作,對EVENT對象的操作,都是極其得心應手的。
3.mutate插件: mutate插件是用來處理數據的格式的。
4.json插件:這個插件也是極其好用的一個插件,現在我們的日誌信息,基本都是由固定的樣式組成的,我們可以使用json插件對其進行解析,並且得到每個字段對應的值。
更多過濾器插件請參考:
https://www.elastic.co/guide/en/logstash/current/filter-plugins.html
2.4 輸出
輸出是Logstash管道的最後階段。事件可以通過多個輸出,但是一旦所有輸出處理完成,事件就完成了它的執行。 Logstash有很多輸出選擇,最常用的是輸出到elasticsearch。常見的輸出還有:
1.elasticsearch
2.File
3.Emial
4.http
5.Kafka
6.Redis
7.MongoDB
8.Rabbitmq
9.Syslog
10.Tcp
11.Websocket
12.Zabbix
13.Stdout
14.Csv
更多輸出插件請參照:
https://www.elastic.co/guide/en/logstash/current/output-plugins.html
3 Kibana
Kibana 是一款開源的數據分析和可視化平臺,它是 Elastic Stack 成員之一,設計用於和 Elasticsearch 協作。您可以使用 Kibana 對 Elasticsearch 索引中的數據進行搜索、查看、交互操作。您可以很方便的利用圖表、表格及地圖對數據進行多元化的分析和呈現。
Kibana 可以使大數據通俗易懂。它很簡單,基於瀏覽器的界面便於您快速創建和分享動態數據儀表板來追蹤 Elasticsearch 的實時數據變化。
更多資料請參考:
https://www.elastic.co/guide/cn/kibana/current/index.html
4 ELK實戰
此方案大致思路如下:
1.應用將日誌傳入kafka。
2.logstash在kafka上消費(讀取)日誌內容,寫入elasticsearch。
3.kibana讀elasticsearch,做對應的展示。
這樣的好處是:
1)幾乎不用做特別大的修改,只需做一定的配置工作即可完成日誌收集;
2)日誌內容輸入kafka幾乎沒有什麼瓶頸,可以做到解耦,另外kafka的擴展性能很好,也很簡單;
3)收集的日誌幾乎是實時的;
4)整體的擴展性很好,很容易消除瓶頸,例如elasticsearch分片、擴展都很容易。
方案架構圖如下:
4.1 使用docker-compose安裝ELK組件
本示例依賴於:
- jdk8
- docker 18.06.1
- docker-compose 1.24.1
- 編寫docker-compose.yml 文件
安裝兩個elasticsearch集羣,kibana,logstash
vim docker-compose.yml
文件內容如下:
version: '3'
services:
elasticsearch:
image: elasticsearch:7.5.2
container_name: jdyp-elasticsearch
environment:
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- node.name=elasticsearch
- cluster.name=docker-elasticsearch-cluster
- xpack.security.enabled=false
- discovery.zen.minimum_master_nodes=1
- discovery.zen.ping.unicast.hosts=ip:9300, ip:9301
- http.cors.enabled=true
- http.cors.allow-origin="*"
volumes:
- esdata:/usr/share/elasticsearch/data
hostname: elasticsearch
network_mode: host
restart: always
ports:
- 9200:9200
- 9300:9300
es-slave:
image: elasticsearch:7.5.2
container_name: jdyp-es-slave
environment:
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- node.name=es-slave
- cluster.name=docker-elasticsearch-cluster
- xpack.security.enabled=false
- discovery.zen.minimum_master_nodes=1
- discovery.zen.ping.unicast.hosts=ip:9300, ip:9301
- http.cors.enabled=true
- http.cors.allow-origin="*"
volumes:
- esdata2:/usr/share/elasticsearch/data
hostname: es-slave
network_mode: host
restart: always
ports:
- 9201:9200
- 9301:9300
kibana:
image: kibana:7.5.2
container_name: jdyp-kibana
hostname: kibana
network_mode: host
environment:
- ELASTICSEARCH_URL=http://ip:9200
- ELASTICSEARCH_HOSTS=http://ip:9200
depends_on:
- elasticsearch
- es-slave
restart: always
ports:
- "5601:5601"
logstash:
image: logstash:7.5.2
container_name: jdyp-logstash
command: logstash -f /etc/logstash/conf.d/logstash.conf
volumes:
- ./logstash:/etc/logstash/conf.d
- /opt/logs/:/opt/build/
environment:
- elasticsearch.hosts=http://ip:9200
# 解決logstash監控連接報錯
- xpack.monitoring.elasticsearch.hosts=http://ip:9200
hostname: logstash
network_mode: host
restart: always
depends_on:
- elasticsearch
- es-slave
ports:
- 9600:9600
- 5044:5044
volumes:
esdata:
driver: local
esdata2:
driver: local
2.編寫logstash配置文件
本方案將日誌從kafka輸入,存儲到elasticsearch。
在docker-compose.yml文件目錄下的logstash文件下編寫logstash.conf文件。
vim ./logstash/logstash.conf
文件內容如下:
input {
tcp {
port => 5044
codec => "json"
}
kafka {
bootstrap_servers => "http://ip:9092" #kafka地址
topics=>["applog"]
}
}
filter {
json {
source => "message"
}
}
output{
elasticsearch {
hosts => ["ip:9200"] #elastic地址
action => "index"
index => "keyway-log-%{+YYYY.MM.dd}"
}
stdout {
codec => rubydebug
}
}
3.啓動
在docker-compose.yml同級目錄下使用命令:docker-compose up -d
如果系統中沒有鏡像會先去拉取鏡像,耗時較長需要等待,另外可以配置國內鏡像加速器加快鏡像的拉取速度,這裏選擇阿里雲的鏡像加速器。
阿里雲:https://dev.aliyun.com/search.html
注意阿里雲需要登錄,每個人對應一個地址。登錄之後在鏡像那搜索docker:
然後選擇鏡像加速器:
獲取加速地址後,輸入命令:vim /etc/docker/daemon.json
複製獲取的地址:
{
"registry-mirrors": ["https://你的地址"]
}
保存退出,然後重啓docker:
sudo systemctl daemon-reload
sudo systemctl restart docker
等待完成後輸入 docker ps 查看部署的容器,如果存在則說明部署成功了。然後輸入 curl:http://localhost://127.0.0.1:9200,如果出現如下界面則說明elasticsearch部署成功:
接下來在瀏覽器輸入 ip:5601,如果出現以下界面則說明kibana安裝成功:
另外。由於日誌採用kafka輸入,因此還需要安裝kafka
- 部署kafka
編寫docker-compose.yml文件
cd /opt/docker/kafka (可以是任意你想要的目錄)
vim docker-compose.yml
文件內容如下:
version: '3'
services:
zookeeper:
image: wurstmeister/zookeeper
container_name: jdyp-zoo1
ports:
- "2181:2181"
network_mode: host
kafka:
image: wurstmeister/kafka
container_name: jdyp-kafka
depends_on:
- zookeeper
network_mode: host
ports:
- "9092:9092"
environment:
KAFKA_BROKER_ID: 5
KAFKA_ZOOKEEPER_CONNECT: 192.168.7.211:2181
KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://192.168.7.211:9092 #宿主機監聽端口
volumes:
- /var/run/docker.sock:/var/run/docker.sock
在docker-compose.yml同級目錄下執行命令:docker-compose up -d
執行完後,可以通過命令 docker ps查看容器是否啓動成功,啓動成功後可以進入容器測試kafka功能是否正常。
進入容器指令:docker exec -it kafka的容器id /bin/bash
此次,Spring Cloud整合ELK的準備工作就完成了。
4.2 Spring Cloud集成 ELK
Spring Cloud版本:Spring cloud Finchley.SR2
4.2.1 pom文件引入依賴
<!--引入logback日誌輸出配置,這時由於kafka綁定的是日誌事件-->
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>5.2</version>
</dependency>
<dependency>
<groupId>com.github.danielwegener</groupId>
<artifactId>logback-kafka-appender</artifactId>
<version>0.1.0</version>
</dependency>
4.2.2 配置文件
添加logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
<appender name="KafkaAppender" class="com.github.danielwegener.logback.kafka.KafkaAppender">
<encoder class="com.github.danielwegener.logback.kafka.encoding.LayoutKafkaMessageEncoder">
<layout class="net.logstash.logback.layout.LogstashLayout" >
<includeContext>true</includeContext>
<includeCallerData>true</includeCallerData>
<customFields>{"system":"service-1"}</customFields>
<!-- <fieldNames class="net.logstash.logback.fieldnames.ShortenedFieldNames"/>-->
</layout>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"><!-- 只打印info及其以上的日誌 -->
<level>INFO</level>
<!--<onMatch>ACCEPT</onMatch>-->
<!--<onMismatch>DENY</onMismatch>-->
</filter>
<!--kafka topic -->
<topic>applog</topic>
<keyingStrategy class="com.github.danielwegener.logback.kafka.keying.HostNameKeyingStrategy" />
<deliveryStrategy class="com.github.danielwegener.logback.kafka.delivery.AsynchronousDeliveryStrategy" />
<producerConfig>bootstrap.servers=ip:9092</producerConfig>
</appender>
<root level="info">
<appender-ref ref="KafkaAppender"/>
</root>
</configuration>
注意: bootstrap.servers=ip:9092填寫你自己的kafka所在服務器的ip地址
application指定日誌文件:
logging:
config: classpath:logback.xml
至此,Spring Cloud整合ELK已經弄好了。調用微服務接口,然後就可以在kibana上看到日誌信息,如圖所示: