搭建ELK日誌平臺(單機)

Ren發表於2021-12-20

系統版本:Ubuntu 16.04.7 LTS
軟體架構:Filebeat+Kafka+Logstash+Elasticsearch+Kibana+Nginx
軟體版本:Filebeat-7.16.0、Kafka-2.11-1.0.0、Logstash-7.16.0、Elasticsearch-7.16.0、Kibana-1.76.0
主機效能:CPU:4c3.8Ghz、MEM:16GB、DISK:1TB
部署方式:單機
索引規劃:按[主機環境]-[專案名稱]-[日期]建立索引。
主題規劃:按[主機環境]-[專案名稱]建立主題。
注意事項:
ELK中所有服務元件建議使用相容的相同版本。
由於Filebeat和Logstash對Kafka的相容性,Kafka推薦使用1.0~2.0版本。

1. 在搭建之前的一些操作

1、建立工作目錄

root@yw-elk:~# mkdir /data/elk/elasticsearch
root@yw-elk:~# mkdir /data/elk/logstash
root@yw-elk:~# mkdir /data/elk/kafka
root@yw-elk:~# mkdir /data/elk/kibana

2. Elasticsearch(儲存日誌)

用於資料儲存。
通常儲存來自於Logstash處理後的日誌資料,以及Kibana管理控制檯管理ES的互動資料,或者Beats擴充套件整合的資料。
Elasticsearch一個索引中可儲存的文件數量為20億。

1、解壓二進位制包

root@yw-elk:~# cd /data/elk/elasticsearch
root@yw-elk:/data/elk/elasticsearch# tar xzvf elasticsearch-7.16.0-linux-x86_64.tar.gz

2、配置Elasticsearch

預設情況下單節點的ES只允許建立999/1000個索引,我們生產+測試環境共有6個專案,每個專案的日誌按天存,一天一個索引,則一年的索引總數=365*6=2190。所以我們需要擴大"cluster.max_shards_per_node"該項的值。

root@yw-elk:/data/elk/elasticsearch# cd elasticsearch-7.16.0/
root@yw-elk:/data/elk/elasticsearch/elasticsearch-7.16.0# vim config/elasticsearch.yml
cluster.name: my-application
node.name: node-1
node.master: true
node.data: true
path.data: /data/elk/elasticsearch/elasticsearch-7.16.0/data
path.logs: /data/elk/elasticsearch/elasticsearch-7.16.0/logs
bootstrap.memory_lock: true
network.host: 127.0.0.1
http.port: 9200
transport.port: 9300
discovery.type: single-node
discovery.seed_hosts: ["127.0.0.1"]
gateway.recover_after_nodes: 1
action.destructive_requires_name: true
cluster.routing.allocation.disk.threshold_enabled: false
cluster.max_shards_per_node: 10000
# 設定叢集中節點最大分片數量,即單個節點可建立的最大索引數量。預設為1000。

## x-pack ###
xpack.security.enabled: true

3、設定JVM堆記憶體大小為4GB

root@yw-elk:/data/elk/elasticsearch/elasticsearch-7.16.0# vim config/jvm.options
-Xms4g
-Xmx4g

4、建立執行使用者

root@yw-elk:/data/elk/elasticsearch/elasticsearch-7.16.0# useradd -M elk
root@yw-elk:/data/elk/elasticsearch/elasticsearch-7.16.0# chown -R elk.elk /data/elk/elasticsearch/elasticsearch-7.16.0

5、執行Elasticsearch

root@yw-elk:/data/elk/elasticsearch/elasticsearch-7.16.0# nohup sudo -u elk bin/elasticsearch &
root@yw-elk:~# netstat -lnupt |grep 9200
tcp6       0      0 127.0.0.1:9200          :::*                    LISTEN      19021/java    

6、建立內建賬戶的密碼

內建賬戶說明:

  • elastic,一個內建的超級使用者。關聯角色superuser。
  • apm_system,用於Elastic APM在Elasticsearch中儲存監控資訊時使用的使用者。關聯角色apm_system。
  • kibana,用於Kibana連線Elasticsearch並與之通訊(已過時的內建使用者)。關聯角色kibana_system。
  • kibana_system,使用者Kibana連線Elasticsearch並與之通訊。關聯角色kibana_system。
  • logstash_system,用於Logstash在Elasticsearch中儲存監控資訊時使用。關聯角色logstash_system。
  • beats_system,用於Beats在Elasticsearch中儲存監控資訊時使用。關聯角色beats_system。
  • remote_monitoring_user ,用於Metricbeat在Elasticsearch中收集和儲存監控資訊時使用。關聯remote_monitoring_agent和remote_monitoring_collector角色 。
root@yw-elk:/data/elk/elasticsearch/elasticsearch-7.16.0# bin/elasticsearch-setup-passwords interactive
password: xxxxx

7、使用賬號訪問Elasticsearch(列出所有索引)

無需手動建立索引,索引由Logstash自動建立。
Elasticsearch預設最大索引數量為999,所以在建立索引的時候,建議一個專案對應一個索引。

root@yw-elk:/data/elk/elasticsearch/elasticsearch-7.16.0# curl -X GET -u elastic:xxx http://127.0.0.1:9200/_cat/indices?v
health status index            uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   .geoip_databases TCYNKgxLQCCzztI-5O410Q   1   0         42            0     41.1mb         41.1mb
green  open   .security-7      XkfwEgRVQcOnl3IpqKNOxg   1   0          7            0     25.7kb         25.7kb

3. Kibana(日誌搜尋與展示)

Elasticsearch的Web圖形化操作管理控制檯。

1、解壓二進位制包

root@yw-elk:~# cd /data/elk/kibana
root@yw-elk:/data/elk/kibana# tar xzvf kibana-7.16.0-linux-x86_64.tar.gz

2、配置Kibana

root@yw-elk:/data/elk/kibana# cd kibana-7.16.0-linux-x86_64
root@yw-elk:/data/elk/kibana/kibana-7.16.0-linux-x86_64# vim config/kibana.yml
server.port: 5601
server.host: "127.0.0.1"
server.publicBaseUrl: "http://elk.xxx.net"
elasticsearch.hosts: ["http://127.0.0.1:9200"]
elasticsearch.username: "kibana_system"
elasticsearch.password: "xxx"
logging.dest: /data/elk/kibana/kibana-7.16.0-linux-x86_64/logs/kibana.log
i18n.locale: "zh-CN"

3、使用elk使用者啟動Kibana

root@yw-elk:/data/elk/kibana# chown -R elk.elk kibana-7.16.0-linux-x86_64
root@yw-elk:/data/elk/kibana# cd kibana-7.16.0-linux-x86_64/
root@yw-elk:/data/elk/kibana/kibana-7.16.0-linux-x86_64# nohup sudo -u elk bin/kibana &
root@yw-elk:/data/elk/kibana/kibana-7.16.0-linux-x86_64# netstat -lnupt |grep 5601
tcp        0      0 127.0.0.1:5601          0.0.0.0:*               LISTEN      13060/node     

4、安裝並配置Nginx反代Kibana

root@yw-elk:~# apt-get -y install nginx
root@yw-elk:~# vim /etc/nginx/conf.d/elk.conf
server {
    listen       80;
    server_name  elk.xxx.net;
    location / {
            proxy_pass http://127.0.0.1:5601;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    error_page 404 /404.html;
    location = /40x.html {
    }
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    }
}
root@yw-elk:~# systemctl restart nginx
root@yw-elk:~# systemctl enable nginx 

5、使用瀏覽器訪問

訪問地址:http://elk.xxx.com
使用超級管理員"elastic"賬號密碼登入

4. Kafka(訊息佇列)

Kafka是一個訊息佇列MQ服務,非同步傳輸日誌資料。
Kafka減輕了Logstash的壓力,Logstash有多少能力處理訊息,則就從Kafka中消費訊息。
這裡為了安全性考慮,增加了SASL基礎認證功能。
SASL(Simple Authentication and Security Layer)簡單的身份驗證和安全層,使用明文使用者密碼的方式保證Kafka的安全。

1、安裝JDK

執行Kafka需要JDK環境的支援。

root@yw-elk:~# mkdir /data/elk/jdk
root@yw-elk:~# cd  /data/elk/jdk
root@yw-elk:/data/elk/jdk# tar xzvf Jdk-8u211-linux-x64.tar.gz
root@yw-elk:/data/elk/jdk# vim /etc/profile
# jdk
export JAVA_HOME=/data/elk/jdk/jdk1.8.0_211
export PATH=$JAVA_HOME/bin:$PATH
root@yw-elk:/data/elk/jdk# source /etc/profile
root@yw-elk:/data/elk/jdk# java -version
java version "1.8.0_211"
Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)

2、解壓二進位制包

root@yw-elk:/data/elk# cd /data/elk/kafka/
root@yw-elk:/data/elk/kafka# tar xzvf kafka_2.11-1.0.0.tgz

3、建立相關資料目錄

root@yw-elk:/data/elk/kafka# cd kafka_2.11-1.0.0/
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# mkdir kafka_data
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# mkdir zk_data

4、配置並啟動Zookeeper

Kafka二進位制包中已經整合Zookeeper了,Zookeeper是Kafka的註冊中心,用於實現消費者與代理節點之間的路由和負載平衡等工作,生產者將訊息寫入到代理節點,由代理節點分發給消費者。

root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim config/zookeeper.properties
dataDir=/data/elk/kafka/kafka_2.11-1.0.0/zk_data
# zookeeper的資料目錄。
clientPort=2181
# zookeeper監聽埠。
maxClientCnxns=0
# 最大客戶端併發連線數量。

### SASL ###
# 開啟ZookeeperClient支援SASL認證
authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider
requireClientAuthScheme=sasl
jaasLoginRenew=3600000

root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# bin/zookeeper-server-start.sh -daemon /data/elk/kafka/kafka_2.11-1.0.0/config/zookeeper.properties
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# netstat -lnupt |grep 2181
tcp6       0      0 :::2181                 :::*                    LISTEN      1086/java  

5、配置Kafka服務端(Broker)

Broker,代理節點,即Kafka服務端。

root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim config/server.properties
############################# Server Basics #############################
broker.id=0
# BrokerID,用於Kafka叢集中代理節點的全域性唯一編號。
message.max.bytes=10000000
# 設定單個訊息的最大值,預設為1M。
# delete.topic.enble=true
# 設定允許對Topic進行刪除操作,否則無法刪除Topic。只有開啟此項的時候Topic才會被真正刪除,否則Topic僅
# 只是被標記為刪除而已。為了安全性考慮的結果。
# auto.create.topics.enable=true
# 設定當生產者要推送訊息的Topic不存在時自動建立對應的Topic。預設為true。
### SASL ###
security.inter.broker.protocol=SASL_PLAINTEXT
# Broker之間通訊所使用的的協議。
sasl.enabled.mechanisms=PLAIN
# 啟用Kafka伺服器簡單安全認證機列表。這個列表可以包括一個可用的安全提供者的任意機置。只有GSSAPI(通用安全服務應用介面)是預設啟用的。
sasl.mechanism.inter.broker.protocol=PLAIN
# 用於內部的broker通訊的簡單身份驗證和安全層機置。預設為通用安全服務應用程式介面。
# authorizer.class.name=kafka.security.auth.SimpleAclAuthorizer
# 開啟簡單的ACL訪問控制功能。
# allow.everyone.if.no.acl.found=true
# 在ACL中,如果列表中沒找到任何ACL規則,表預設允許所有使用者操作。
super.users=User:admin
# 設定Broker的超級管理使用者為admin。

############################# Socket Server Settings #############################
listeners=SASL_PLAINTEXT://:9092
# 設定套接字監聽器所使用的安全協議和埠。PLAINTEXT是Kafka預設使用的協議。這邊將其修改為SASL_PLAINTEXT協議,為了增加基於SASL的身份認證功能。
advertised.listeners=SASL_PLAINTEXT://47.96.96.60:9092
# 設定將Kafka的地址通告給生產者和消費者,如果不設定該項,則預設使用listeners的值。
# 由於我這邊是公網環境,想要生產者和消費者與Kafka正常通訊,則需要設定該項為公網地址,這才可以正常工
# 作。
num.network.threads=3
# Broker接收網路請求所開啟的執行緒數量。
num.io.threads=8
# Broker用於處理請求的執行緒數量,其中可能包括磁碟IO。
socket.send.buffer.bytes=102400
# 套接字傳送資料的緩衝區大小,單位為位元組。
socket.receive.buffer.bytes=102400
# 套接字接受資料的緩衝區大小,單位為位元組。
socket.request.max.bytes=104857600
############################# Log Basics #############################
# 套接字接受單個請求的最大大小(防止OOM)。
log.dirs=/data/elk/kafka/kafka_2.11-1.0.0/kafka_data
# Broker日誌和資料儲存目錄路徑。
num.partitions=1
# 每個Topic的預設日誌分割槽數量,更多的分割槽將允許更多的並行度,這也將導致會產生更多的檔案,但可以增加每個Topic的併發效能。預設為1
num.recovery.threads.per.data.dir=1
# 在啟動和關閉Broker伺服器時,每個資料目錄(log.dirs)中日誌恢復的執行緒數量。
############################# Internal Topic Settings  #############################
# 設定內部後設資料Topic組的副本因子數量"__consumer_offsets"和"__transaction_state"。
# 除了開發測試之外,建議設定>1的值,比如3。
# 建議有幾個節點就設定為幾個副本數量。

offsets.topic.replication.factor=1
# 每個Topic的偏移值記錄都在"__consumer_offsets"這個Topic中儲存,該項用於設
# 置"__consumer_offsets"這個Topic的副本數量。以增加可靠性。
transaction.state.log.replication.factor=1
# 儲存事務狀態日誌的Topic"__transaction_state"的副本數量。
transaction.state.log.min.isr=1
# 覆蓋事務狀態日誌Topic中的min.insync.replicas配置。
# "min.insync.replicas"用於保證事務寫入認為成功的最小副本數量,如果寫入操作不能滿足該要求,則生產者會引發一個異常"NotEnoughReplicas或NotEnoughReplicasAfterAppend"。
############################# Log Retention Policy #############################
log.retention.hours=168
# 日誌(訊息)保留時間,單位為小時。
# log.retention.bytes=1073741824
# 一個基於日誌(訊息)大小的保留策略。每個Topic下每個分割槽儲存資料的最大檔案大小。
# 當log.retention.hours和log.retention.bytes都存在時,當滿足任何一個策略時都會刪除。
# 該項如果設定為-1,則表示不刪除。
log.segment.bytes=1073741824
# 日誌段檔案的最大大小,當達到此大小的時候,將建立一個新的日誌段,單位為位元組。
log.retention.check.interval.ms=300000
# 日誌保留檢查間隔時間,單位ms。
############################# Zookeeper #############################
zookeeper.connect=127.0.0.0.1:2181
# zookeeper連線地址。
zookeeper.connection.timeout.ms=18000
# zookeeper連線超時時間。
############################# Group Coordinator Settings #############################
group.initial.rebalance.delay.ms=0
# 設定所有成員都加入到消費者組中需要的延遲時間,以避免出現再平衡"rebalance"事件的發生。

6、配置生產者和消費者客戶端

配置生產者和消費者客戶端,使其支援SASL安全機制。

root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim config/producer.properties
### SASL ###
security.protocol=SASL_PLAINTEXT
sasl.mechanism=PLAIN
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim config/consumer.properties
### SASL ###
security.protocol=SASL_PLAINTEXT
sasl.mechanism=PLAIN

7、為Kafka新增使用者和密碼

注:在kafka_server_jaas.conf和kafka_client_jaas.conf配置檔案中,"username"和"password"建立的使用者密碼用於Broker之間的SASL身份認證,而user_=""這個使用者使用者生產者和消費者客戶端使用。

# 建立Kafka伺服器所使用的的賬號密碼以用於基於使用者密碼的身份驗證
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim config/kafka_server_jaas.conf
KafkaServer {
    org.apache.kafka.common.security.plain.PlainLoginModule required
        username="admin"
        password="xxx"
        user_admin="xxx";
};
# 建立生產者或消費者客戶端登入所使用的使用者密碼檔案,用於登入到Kafka伺服器(broker)。
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim config/kafka_client_jaas.conf
KafkaClient {
org.apache.kafka.common.security.plain.PlainLoginModule required
    username="admin"
    password="xxx";
};
# 修改啟動指令碼檔案
# 將內容寫入到檔案的最頂部
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim bin/kafka-server-start.sh
export KAFKA_OPTS="-Djava.security.auth.login.config=/data/elk/kafka/kafka_2.11-1.0.0/config/kafka_server_jaas.conf"
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim bin/kafka-console-producer.sh
export KAFKA_OPTS="-Djava.security.auth.login.config=/data/elk/kafka/kafka_2.11-1.0.0/config/kafka_client_jaas.conf"
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim bin/kafka-console-consumer.sh
export KAFKA_OPTS="-Djava.security.auth.login.config=/data/elk/kafka/kafka_2.11-1.0.0/config/kafka_client_jaas.conf"

8、開啟Kafka JMX監控功能(可選的步驟)

建立JMX監控要使用的賬號密碼檔案"jmxremote.password"和許可權控制"jmxremote.access"檔案:

  • jmxremote.password 內容格式:
  • jmxremote.access 內容格式: <readonly|readwrite>
    注:這兩個檔案僅能使用600許可權,否則服務無法啟動。
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim config/jmxremote.password
jmxuser xxx
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim config/jmxremote.access
jmxuser readonly
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# chmod 600 config/jmxremote.*

指定在的指令碼檔案中找到以下內容,新增並修改相關內容:

root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim bin/kafka-run-class.sh
# JMX settings
if [ -z "$KAFKA_JMX_OPTS" ]; then
  KAFKA_JMX_OPTS="-Dcom.sun.management.jmxremote -Djava.rmi.server.hostname="127.0.0.1" -Dcom.sun.management.jmxremote.authenticate=true  -Dcom.sun.management.jmxremote.ssl=false  -Dcom.sun.management.jmxremote.password.file=/data/elk/kafka/kafka_2.11-1.0.0/config/jmxremote.password -Dcom.sun.management.jmxremote.access.file=/data/elk/kafka/kafka_2.11-1.0.0/config/jmxremote.access"
fi

# JMX port to use
if [  $JMX_PORT ]; then
  KAFKA_JMX_OPTS="$KAFKA_JMX_OPTS -Dcom.sun.management.jmxremote.port=$JMX_PORT"
fi
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim bin/kafka-server-start.sh
export JMX_PORT="12345"

9、啟動Kafka伺服器(Broker)

root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# bin/kafka-server-start.sh -daemon /data/elk/kafka/kafka_2.11-1.0.0/config/server.properties
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# netstat -lnupt |grep 9092
tcp6       0      0 :::9092                 :::*                    LISTEN      28738/java    
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# netstat -lnupt |grep 12345
tcp6       0      0 :::12345                :::*                    LISTEN      24280/java   

10、手動建立專案使用的Topic

這裡無需手動建立Topic,Logstash會自動建立Topic。
建立Topic:

root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# bin/kafka-topics.sh --zookeeper 127.0.0.1:2181 --create --partitions 5 --replication-factor 1 --topic production-xxx

檢視Topic列表:

root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# bin/kafka-topics.sh --zookeeper 127.0.0.1:2181 --list
__consumer_offsets
production-xxx

檢視Topic狀態資訊:

root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# bin/kafka-topics.sh --zookeeper 127.0.0.1:2181 --describe --topic production-xxx
Topic:test-th	PartitionCount:1	ReplicationFactor:1	Configs:
	Topic: test-th	Partition: 0	Leader: 0	Replicas: 0	Isr: 0

5、Filebeat(採集日誌)

Filebeart是Elastic家族中輕量級的基於檔案的採集器,用於從多臺主機上採集日誌,並傳送給Elasticsearch儲存或Logstash過濾處理。
安裝Filebeat以採集日誌,並將其傳送到Kafka訊息佇列中,由Logstash連線到Kafka獲取日誌訊息結構化處理後將其儲存到Elasticsearch。
示例日誌內容:
這是JAVA程式產生的日誌資料,其結構格式都是第一行通常都是以日期時間開頭的,當發生異常時後續的無日期開頭的行都將會屬於上一行日期開頭行的內容,這才是一條完整的JAVA日誌。
所以這裡我們使用Filebeat則需要配置多行日誌合併為一條日誌進行處理。

2018-12-03 02:15:28.049 c.t.f.w.common.stat.WebappStatUtil [INFO][WebappStatUtil.java:49][93926cbbdeca44f2b3f713b643df959a] - reqId=-8a26-1203021528-570,uri=/train/basic/station_info,code=0,duration=30,uid=-1,ip=139.214.244.179,stack=[TrainQueryService.getStationMap:0:4]
2018-12-03 18:07:36.183 c.t.f.w.c.f.ExceptionAndStatFilter [ERROR][ExceptionAndStatFilter.java:433][93926cbbdeca44f2b3f713b643df959a] - reqId=-8a26-1203180736-18, Request processing failed; nested exception is com.alibaba.fastjson.JSONException: syntax error, expect {, actual false, pos 0
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is com.alibaba.fastjson.JSONException: syntax error, expect {, actual false, pos 0
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:981) ~[spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE]

1、解壓二進位制包

root@jxota:~# cd /opt/ota/yw/filebeat
root@jxota:/opt/ota/yw/filebeat# tar xzvf filebeat-7.16.0-linux-x86_64.tar.gz
root@jxota:/opt/ota/yw/filebeat# cd filebeat-7.16.0-linux-x86_64/

2、配置Filebeat

我這邊是在測試環境下的一臺主機上配置的,可以作為示例配置。
Filebeat應該在多臺主機上執行,並所屬不同的主機環境和專案。

root@jxota:/opt/ota/yw/filebeat/filebeat-7.16.0-linux-x86_64# vim filebeat.yml
# ============================== Filebeat inputs ===============================
filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/xxx/*/*.log

  ### 新增欄位
  # 新增一些欄位以識別專案和主機環境
  fields:
    hostenv: "production"  # 主機環境
    project: "xxx"  # 所屬專案

  ### 多行選項
  # 多行選項,期望輸出連續的多行日誌,比如Java日誌。
  multiline.type: pattern
  multiline.pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}'
  # 使用正則表達匹配行。
  multiline.negate: true
  # 定義行是否被否定,若被否定,則執行"multiline.match"。
  multiline.match: after
  # 設定將匹配行與上一行(before)合併為一個事件輸出,還是將匹配行與下一行(after)合併為一個事件輸出。

# ================================== Outputs ===================================
# ...
# ------------------------------ Kafka Output -------------------------------
output.kafka:
  hosts: ["172.16.31.12:9092"]
  # 指定Kafka伺服器連線地址,我這邊由於網路環境問題,所以使用Kafka伺服器的公網主機IP地址。
 
  username: "admin"
  # 設定連線Kafka所使用的的使用者名稱
  password: "xxx"
  # 設定連線Kafka所使用的的使用者密碼

  topic: '%{[fields.hostenv]}-%{[fields.project]}'
  # 設定主題名稱
  partition.round_robin:
    group_events: 1
    reachable_only: false
  # 設定訊息寫入主題的分割槽策略:預設使用hash方法。
  # random.group_events, 隨機寫入主題的任意一個分割槽,並設定寫入分割槽時訊息事件的數量,預設為1。
  # round_robin.group_events,有序的輪詢的寫入主題分割槽,並設定寫入分割槽時訊息時間的數量,預設為1。
  # hash.hash,通過雜湊計算分割槽中的欄位列表,將匹配的欄位寫入到同一個分割槽中,如果沒有配置欄位,則使用事件鍵值。
  # - hash.random,如果無法計算雜湊或鍵值,則隨機分發事件。
  # reachable_only: 預設分割槽都嘗試向所有分割槽釋出事件,如果一個分割槽的leader在這個beat下變得不可用,輸出可能會阻塞,則開啟該項表示允許將事件傳送到可用分割槽。
  required_acks: 1
  # 設定Kafka代理要求的ACK可靠性級別:
  # 0,無響應。
  # 1,等待本地提交。
  # -1,等待所有副本提交。
  # 注:如果設定為0,則Kafka不會返回任何ACK。出現錯誤時,訊息可能會自動丟失。
  compression: gzip
  # 設定輸出壓縮編解碼器,預設為gzip。支援none、snappy、lz4和zip壓縮方式。
  compression_level: 4
  # 設定壓縮級別,預設為4。如果設定為0,則表示不壓縮。
  max_message_bytes: 10000000
  # JSON編碼訊息最大允許大小。更大的資訊將被刪除。預設是1M。該值應該小於或等於Kafka代理伺服器
  # 的"message.max.bytes"。

3、新增Filebeat到系統服務

預設情況下Filebeat無法通過nohup這種方式讓其在後臺執行,所以需要將其新增到系統服務才可後臺執行。

root@jxota:/opt/ota/yw/filebeat/filebeat-7.16.0-linux-x86_64# vim /lib/systemd/system/filebeat.service
[Unit]
Description=filebeat
Wants=network-online.target
After=network-online.target
[Service]
User=root
ExecStart=/opt/ota/yw/filebeat/filebeat-7.16.0-linux-x86_64/filebeat -c /opt/ota/yw/filebeat/filebeat-7.16.0-linux-x86_64/filebeat.yml
Restart=always
[Install]
WantedBy=multi-user.target
root@jxota:/opt/ota/yw/filebeat/filebeat-7.16.0-linux-x86_64# systemctl daemon-reload

4、啟動Filebeat

可以先使用"./filebeat -e -c filebeat.yml -d "publist""在前臺啟動,測試Filebeat(生產者)-> Kafka -> Logstash(消費方)的通訊情況。

root@jxota:/opt/ota/yw/filebeat/filebeat-7.16.0-linux-x86_64# systemctl start filebeat
root@jxota:/opt/ota/yw/filebeat/filebeat-7.16.0-linux-x86_64# systemctl status filebeat
● filebeat.service - filebeat
   Loaded: loaded (/lib/systemd/system/filebeat.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2021-12-16 15:54:47 CST; 4min 30s ago
 Main PID: 10525 (filebeat)
   CGroup: /system.slice/filebeat.service
           └─10525 /opt/th/yw/filebeat-7.16.0-linux-x86_64/filebeat -c /opt/th/yw/filebeat-7.16.0-linux-x86_64/filebeat.yml

5、設定Filebeat開機自啟

root@agent:/opt/ota/yw/filebeat/filebeat-7.16.0-linux-x86_64# systemctl enable filebeat
Synchronizing state of filebeat.service with SysV init with /lib/systemd/systemd-sysv-install...
Executing /lib/systemd/systemd-sysv-install enable filebeat

6. Logstash(處理日誌)

Logstash用於讀取從Kafka+Filebeat採集來的日誌資料,結構化處理後儲存到Elasticsearch。
示例日誌內容:

2018-12-03 02:15:28.049 c.t.f.w.common.stat.WebappStatUtil [INFO][WebappStatUtil.java:49][93926cbbdeca44f2b3f713b643df959a] - reqId=-8a26-1203021528-570,uri=/train/basic/station_info,code=0,duration=30,uid=-1,ip=139.214.244.179,stack=[TrainQueryService.getStationMap:0:4]
2018-12-03 18:07:36.183 c.t.f.w.c.f.ExceptionAndStatFilter [ERROR][ExceptionAndStatFilter.java:433][93926cbbdeca44f2b3f713b643df959a] - reqId=-8a26-1203180736-18, Request processing failed; nested exception is com.alibaba.fastjson.JSONException: syntax error, expect {, actual false, pos 0
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is com.alibaba.fastjson.JSONException: syntax error, expect {, actual false, pos 0
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:981) ~[spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:981) ~[spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:981) ~[spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE]

1、解壓二進位制包

root@yw-elk:~# cd /data/elk/logstash/
root@yw-elk:/data/elk/logstash# tar xzvf logstash-7.16.0-linux-x86_64.tar.gz

2、安裝常用外掛(可選的步驟)

檢視已安裝外掛,如果外掛沒有安裝則需要手動安裝相關外掛。
Logstash-7.16.0適用的Kafka外掛版本是10.8.1。
注:由於預設的外掛包地址下載較慢,需要修改為國內源。

root@yw-elk:/data/elk/logstash# cd logstash-7.16.0/
root@yw-elk:/data/elk/logstash/logstash-7.16.0# echo "54.235.82.130   artifacts.elastic.co" >> /etc/hosts
root@yw-elk:/data/elk/logstash/logstash-7.16.0# bin/logstash-plugin list --verbose
root@yw-elk:/data/elk/logstash/logstash-7.16.0# bin/logstash-plugin install <plugin_name>

3、調整JVM堆記憶體大小

root@yw-elk:/data/elk/logstash/logstash-7.16.0# vim config/jvm.options
-Xms4g
-Xmx4g

4、建立Kafka客戶端認證檔案

root@yw-elk:/data/elk/logstash/logstash-7.16.0# vim config/kafka_client_jaas.conf
KafkaClient {
org.apache.kafka.common.security.plain.PlainLoginModule required
    username="admin"
    password="xxx";
};

5、除錯Logstash

建立用於除錯的Logstash管道配置檔案,並啟動Logstash,檢視控制檯輸出以除錯並編寫完整的Logstash管道配置。
我們期望將一些重要的關鍵的欄位存入到Elasticsearch中!
由於從Filebeat傳送過來的資料為JSON資料,所以需要將input中的編解碼器設定為JSON。
除錯並建立Logstash管道配置檔案:

root@yw-elk:/data/elk/logstash/logstash-7.16.0# vim config/logstash.conf
# -- 輸入
input {
  kafka {
    bootstrap_servers => "127.0.0.1:9092"
    topics => ["production-xxx"]
    consumer_threads => 1

    security_protocol => "SASL_PLAINTEXT"
    sasl_mechanism => "PLAIN"
    jaas_path => "/data/elk/logstash/logstash-7.16.0/config/kafka_client_jaas.conf"

    codec => "json"
  }
}

# -- 處理
filter {
}

# -- 輸出
output {
  stdout { codec => rubydebug }
}

前臺啟動Logstash:

root@yw-elk:/data/elk/logstash/logstash-7.16.0# bin/logstash -f config/logstash.conf

未處理前的資料:

{
           "ecs" => {
        "version" => "1.12.0"
    },
      "@version" => "1",
          "host" => {
         "architecture" => "x86_64",
                  "mac" => [
            [0] "00:16:3e:12:0c:77"
        ],
        "containerized" => false,
             "hostname" => "xxx",
                   "os" => {
                "name" => "Ubuntu",
              "kernel" => "4.4.0-184-generic",
            "platform" => "ubuntu",
                "type" => "linux",
             "version" => "16.04.6 LTS (Xenial Xerus)",
            "codename" => "xenial",
              "family" => "debian"
        },
                   "id" => "92b8629fdc1ea4d3c82bfcad5eeac938",
                   "ip" => [
            [0] "172.17.0.16",
            [1] "fe80::216:3eff:fe12:c77"
        ],
                 "name" => "xxx"
    },
       "message" => "2018-12-03 18:07:36.183 c.t.f.w.c.f.ExceptionAndStatFilter [ERROR][ExceptionAndStatFilter.java:433][93926cbbdeca44f2b3f713b643df959a] - reqId=-8a26-1203180736-18, Request processing failed; nested exception is com.alibaba.fastjson.JSONException: syntax error, expect {, actual false, pos 0\norg.springframework.web.util.NestedServletException: Request processing failed; nested exception is com.alibaba.fastjson.JSONException: syntax error, expect {, actual false, pos 0\n        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:981) ~[spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE]\n        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:981) ~[spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE]\n",
           "log" => {
          "file" => {
            "path" => "/var/log/xxx/apache-tomcat-api/test.2021-10-12.log"
        },
         "flags" => [
            [0] "multiline"
        ],
        "offset" => 11557
    },
    "@timestamp" => 2021-12-13T09:55:42.278Z,
        "fields" => {
        "hostenv" => "production",
        "project" => "xxx"
    },
         "agent" => {
        "ephemeral_id" => "34bb5503-74c1-4885-9189-3ac0db6e8e2e",
            "hostname" => "xxx",
                "type" => "filebeat",
                  "id" => "8fda7277-3c33-4c05-8607-09b86bee8936",
             "version" => "7.16.0",
                "name" => "xxx"
    },
         "input" => {
        "type" => "log"
    }
}

6、使用Grok文字處理外掛處理資料

使用Grok外掛對"message"和"path"進行一些處理。
期望從"message"中得到以下欄位:

  • logDateTime,當前日誌的時間戳
  • logClassFilePath,類檔案路徑
  • logLevel,日誌級別
  • logClassFileLine,類檔案的第幾行報出來的日誌,用於問題定位
  • logReqId,請求鏈ID
  • logContent,日誌內容,具體的描述資訊
    期望從"[log][file][path]"中獲取到日誌檔案的名稱作為索引的名稱。
  • logFileName,日誌檔名稱
    自定義文字模式:可以使用Kibana中的開發工具中的GrokDebugger工具進行除錯。

    建立自定義文字模式檔案:
root@yw-elk:/data/elk/logstash/logstash-7.16.0# vim config/patterns/patterns
# message
DATETIME \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}
CLASS_FILE_PATH .*
LOG_LEVEL \[.*\]
CLASS_FILE_LINE \[.*\]
REQUEST_ID \[.*\]
LOG_CONTENT .*

Logstash管道配置:

root@yw-elk:/data/elk/logstash/logstash-7.16.0# vim config/logstash.conf
# -- 輸入
input {
  kafka {
    bootstrap_servers => "127.0.0.1:9092"
    topics => ["production-xxx"]
    consumer_threads => 1

    security_protocol => "SASL_PLAINTEXT"
    sasl_mechanism => "PLAIN"
    jaas_path => "/data/elk/logstash/logstash-7.16.0/config/kafka_client_jaas.conf"

    codec => "json"
  }
}

# -- 處理
filter {
  # 使用Grok外掛處理
  # 從"message"中提取:
  # - logDateTime,當前日誌的時間戳
  # - logClassFilePath,類檔案路徑
  # - logLevel,日誌級別
  # - logClassFileLine,類檔案的第幾行報出來的日誌,用於問題定位
  # - logReqId,請求鏈ID
  grok {
    patterns_dir => ["/data/elk/logstash/logstash-7.16.0/config/patterns"]
    match => {
      "message" => "%{DATETIME:logDateTime} %{CLASS_FILE_PATH:logClassFilePath} %{LOG_LEVEL:logLevel}%{CLASS_FILE_LINE:logClassFileLine}%{REQUEST_ID:logReqId} %{LOG_CONTENT:logContent}"
    }
  }

  # 使用Mutate外掛處理
  # 從"[log][file][path]"中提取:
  # - logFileName,日誌檔名稱
  # 並刪除一些不重要的欄位"logContent"
  mutate {
    split => ["[log][file][path]", "/"]
    add_field => { "logFileName" => "%{[log][file][path][-1]}" }
    remove_field => ["logContent"]
  }
  mutate {
    join => ["[log][file][path]", "/"]
  }

  # 使用Mutate外掛處理
  # 從"logDateTime"中提取:
  # - logDate,日誌記錄中的日期
  mutate {
    split => ["logDateTime", " "]
    add_field => { "logDate" => "%{[logDateTime][0]}" }
  }
  mutate {
    join => ["logDateTime", " "]
  }

   # 使用Date外掛處理
   # 使用日誌的時間作為記錄的時間戳"@timestamp",保證日誌時序
   date {
     match => ["logDateTime", "ISO8601"]
     target => "@timestamp"
   }
}

# -- 輸出
output {
  stdout { codec => rubydebug }
}

結構化處理後結果:

{
            "logReqId" => "[93926cbbdeca44f2b3f713b643df959a]",
               "agent" => {
                "name" => "xxx",
            "hostname" => "xxx",
        "ephemeral_id" => "34bb5503-74c1-4885-9189-3ac0db6e8e2e",
             "version" => "7.16.0",
                "type" => "filebeat",
                  "id" => "8fda7277-3c33-4c05-8607-09b86bee8936"
    },
                 "ecs" => {
        "version" => "1.12.0"
    },
          "@timestamp" => 2021-12-13T09:51:02.255Z,
              "fields" => {
        "project" => "xxx",
        "hostenv" => "production"
    },
                 "log" => {
         "flags" => [
            [0] "multiline"
        ],
          "file" => {
            "path" => "/var/log/xxx/apache-tomcat-api/test.2021-10-12.log"
        },
        "offset" => 10784
    },
         "logDateTime" => "2018-12-03 18:07:36.183",
         "logDate" => "2018-12-03",
            "logLevel" => "[ERROR]",
               "input" => {
        "type" => "log"
    },
                "host" => {
                 "name" => "xxx",
                   "ip" => [
            [0] "172.17.0.16",
            [1] "fe80::216:3eff:fe12:c77"
        ],
                  "mac" => [
            [0] "00:16:3e:12:0c:77"
        ],
             "hostname" => "xxx",
        "containerized" => false,
                   "os" => {
                "name" => "Ubuntu",
              "kernel" => "4.4.0-184-generic",
            "codename" => "xenial",
            "platform" => "ubuntu",
              "family" => "debian",
             "version" => "16.04.6 LTS (Xenial Xerus)",
                "type" => "linux"
        },
         "architecture" => "x86_64",
                   "id" => "92b8629fdc1ea4d3c82bfcad5eeac938"
    },
             "message" => "2018-12-03 18:07:36.183 c.t.f.w.c.f.ExceptionAndStatFilter [ERROR][ExceptionAndStatFilter.java:433][93926cbbdeca44f2b3f713b643df959a] - reqId=-8a26-1203180736-18, Request processing failed; nested exception is com.alibaba.fastjson.JSONException: syntax error, expect {, actual false, pos 0\norg.springframework.web.util.NestedServletException: Request processing failed; nested exception is com.alibaba.fastjson.JSONException: syntax error, expect {, actual false, pos 0\n        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:981) ~[spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE]\n        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:981) ~[spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE]\n",
            "@version" => "1",
    "logClassFilePath" => "c.t.f.w.c.f.ExceptionAndStatFilter",
         "logFileName" => "test.2021-10-12.log",
    "logClassFileLine" => "[ExceptionAndStatFilter.java:433]"
}

7、將處理完成後的結果儲存到Elasticsearch中(最後完整的管道配置)

期望將日誌資料寫入到專案關聯的的索引中"%{[fields][hostenv]}-%{[fields][project]}"。

root@yw-elk:/data/elk/logstash/logstash-7.16.0# vim config/logstash.conf
# -- 輸入
input {
  kafka {
    bootstrap_servers => "127.0.0.1:9092"
    topics => ["production-xxx"]
    consumer_threads => 5

    security_protocol => "SASL_PLAINTEXT"
    sasl_mechanism => "PLAIN"
    jaas_path => "/data/elk/logstash/logstash-7.16.0/config/kafka_client_jaas.conf"

    codec => "json"
  }
}

# -- 處理
filter {
  # 使用Grok外掛處理
  # 從"message"中提取:
  # - logDateTime,當前日誌的時間戳
  # - logClassFilePath,類檔案路徑
  # - logLevel,日誌級別
  # - logClassFileLine,類檔案的第幾行報出來的日誌,用於問題定位
  # - logReqId,請求鏈ID
  grok {
    patterns_dir => ["/data/elk/logstash/logstash-7.16.0/config/patterns"]
    match => {
      "message" => "%{DATETIME:logDateTime} %{CLASS_FILE_PATH:logClassFilePath} %{LOG_LEVEL:logLevel}%{CLASS_FILE_LINE:logClassFileLine}%{REQUEST_ID:logReqId} %{LOG_CONTENT:logContent}"
    }
  }

  # 使用Mutate外掛處理
  # 從"[log][file][path]"中提取:
  # - logFileName,日誌檔名稱
  # 並刪除一些不重要的欄位"logContent"
  mutate {
    split => ["[log][file][path]", "/"]
    add_field => { "logFileName" => "%{[log][file][path][-1]}" }
    remove_field => ["logContent"]
  }
  mutate {
    join => ["[log][file][path]", "/"]
  }

  # 使用Mutate外掛處理
  # 從"logDateTime"中提取:
  # - logDate,日誌記錄中的日期
  mutate {
    split => ["logDateTime", " "]
    add_field => { "logDate" => "%{[logDateTime][0]}" }
  }
  mutate {
    join => ["logDateTime", " "]
  }

   # 使用Date外掛處理
   # 使用日誌的時間作為記錄的時間戳"@timestamp",保證日誌時序
   date {
     match => ["logDateTime", "ISO8601"]
     target => "@timestamp"
   }
}


# -- 輸出
output {
  # stdout { codec => rubydebug }
  # 如果"logDate"中的值不是日期,則將其存到指定的索引裡面
  if [logDate] =~ "^\d{4}-\d{2}-\d{2}" {
    elasticsearch {
      hosts => "127.0.0.1:9200"
      user => "elastic"
      password => "lgWZDNRmTaXwkO4s"
      manage_template => false
      index => "%{[fields][hostenv]}-%{[fields][project]}-%{[logDate]}" 
      document_type => "%{[@metadata][type]}" 
    }
  } else {
    elasticsearch {
      hosts => "127.0.0.1:9200"
      user => "elastic"
      password => "xxx"
      manage_template => false
      index => "%{[fields][hostenv]}-%{[fields][project]}-unkown"
      document_type => "%{[@metadata][type]}"
    }
  }
}

8、設定服務配置

修改Logstash的API監聽埠配置,避免預設的埠範圍隨機一個埠,埠可用於監控服務是否工作正常。

root@yw-elk:/data/elk/logstash/logstash-7.16.0# vim config/logstash.yml
api.http.port: 9600

9、啟動Logstash

root@yw-elk:/data/elk/logstash/logstash-7.16.0# nohup bin/logstash -f config/logstash.conf --config.reload.automatic &
root@yw-elk:/data/elk/logstash/logstash-7.16.0# netstat -lnupt |grep 9600
tcp6       0      0 127.0.0.1:9600          :::*                    LISTEN      27192/java   

7、搭建完成

1、檢視Elasticsearch

可以看到Elasticsearch中已經自動建立了索引,並且日誌已經存進去了。
root@yw-elk:~# curl -X GET -u elastic:xxxx http://127.0.0.1:9200/_cat/indices?v
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open production-xxx-2021-12-12 NBrMgp9wS3-K_WsP9iUh-g 1 1 12 0 67.2kb 67.2kb
...

2、在Kibana上建立索引模式檢索日誌

索引模式是通過萬用字元表示式關聯的多個索引的集合。
操作步驟:Stack Management -> 索引模式 -> 建立索引模式

附錄-官方文件

參考官方文件:https://www.elastic.co/guide/index.html

附錄-工作元件關係圖

附錄-Kibana排序檢視日誌(使用Logstash修改@timestamp)

由於多個應用的日誌非同步向ES中寫入,對於寫入的記錄是無序的,Kibana僅提供一個@timestamp可操作排序。
由於預設記錄的時間戳是使用的當前系統時間,對採用系統時間戳記錄進行排序意義不大。
這個時候如果想要使用@timestamp排序後檢視得到的日誌是有序的話,則只需要擷取日誌中的時間戳將其轉換為內建欄位@timestamp所使用的即可,即日誌時間=@timestamp。
Logstash管道配置如下:

# -- 輸入
input {
  kafka {
    bootstrap_servers => "127.0.0.1:9092"
    topics => ["production-xxx"]
    consumer_threads => 1

    security_protocol => "SASL_PLAINTEXT"
    sasl_mechanism => "PLAIN"
    jaas_path => "/data/elk/logstash/logstash-7.16.0/config/kafka_client_jaas.conf"

    codec => "json"
  }
}

# -- 處理
filter {
  # 使用Grok外掛處理
  # 從"message"中提取:
  # - logDateTime,當前日誌的時間戳
  # - logClassFilePath,類檔案路徑
  # - logLevel,日誌級別
  # - logClassFileLine,類檔案的第幾行報出來的日誌,用於問題定位
  # - logReqId,請求鏈ID
  grok {
    patterns_dir => ["/data/elk/logstash/logstash-7.16.0/config/patterns"]
    match => {
      "message" => "%{DATETIME:logDateTime} %{CLASS_FILE_PATH:logClassFilePath} %{LOG_LEVEL:logLevel}%{CLASS_FILE_LINE:logClassFileLine}%{REQUEST_ID:logReqId} %{LOG_CONTENT:logContent}"
    }
  }
  
  # 使用Mutate外掛處理
  # 從"[log][file][path]"中提取:
  # - logFileName,日誌檔名稱
  # 並刪除一些不重要的欄位
  mutate {
    split => ["[log][file][path]", "/"]
    add_field => { "logFileName" => "%{[log][file][path][-1]}" }
    remove_field => ["logContent"]
  }
  mutate {
    join => ["[log][file][path]", "/"]
  }

   # 使用Date外掛處理
   # 使用日誌的時間作為記錄的時間戳"@timestamp",保證日誌時序
   date {
     match => ["logDateTime", "ISO8601"]
     target => "@timestamp"
   }
}

# -- 輸出
output {
  elasticsearch {
    hosts => "127.0.0.1:9200"
    user => "elastic"
    password => "xxx"
    manage_template => false
    index => "%{[fields][hostenv]}-%{[fields][project]}-%{logFileName}" 
    document_type => "%{[@metadata][type]}" 
  }
}

Kibana中排序操作:

附錄-Filebeat重新收集之前的日誌

在Filebeat的工作目錄下的"data"目錄中記錄了filebeat收集日誌的偏移值記錄。
只需要清除"data"目錄下的所有檔案,重啟Filebeat即可。

root@agent:/opt/ota/yw/filebeat/filebeat-7.16.0-linux-x86_64# rm -rf data/*

附錄-Kafka如何合理的設定Topic的分割槽數量

分割槽越多,則表示資料庫目錄下會存放更多的目錄和檔案,並行的分割槽數也代表著在系統中會開啟更多的控制程式碼數量。
在生產者端的配置中有個batch.size大小,預設為16KB,它會為每個分割槽緩衝訊息,當訊息滿了以後再打包批量傳送到Borker,分割槽數量越多也意味著會存在更多的緩衝區,即佔用更多的記憶體大小。
在消費者端會建立對應分割槽數量的執行緒去消費訊息,則表示並行的執行緒,執行緒之間上下文切換也會造成系統資源的開銷。
所以合理的設定Topic的分割槽數量是非常重要的。
Kafka預設整合了效能測試的工具"kafka-producer-perf-test.sh"和"kafka-consumer-perf-test.sh"可以測試Topic的每秒可處理訊息的吞吐量、延遲。可以根據測試結果合理的建立分割槽數量。
示例:
假定一條日誌訊息的資料大小為2000位元組,業務系統一個節點每秒產生1000條日誌,則你期望在1秒鐘就可以儲存到Kafka中,則期望的吞吐量是20001000節點數量=目標吞吐量,我這邊有10個節點,則我期望的目標吞吐量為20MB/s。
下面我建立了一個分割槽的Topic,並使用生產端和消費端效能壓測工具進行壓力測試。
可以看到經過以下測試的結果,一個分割槽的Topic的處理訊息的吞吐量是2.8MB/s,則分割槽數量=目標吞吐量/效能壓測的吞吐量。

1、建立測試用的Topic

root@yw-elk:~# cd /data/elk/kafka/kafka_2.11-1.0.0/
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# bin/kafka-topics.sh --zookeeper 127.0.0.1:2181 --create --partitions 1 --replication-factor 1 --topic test
Created topic "test".

2、使用生產者效能測試工具"kafka-producer-perf-test.sh"進行壓測

注:由於這邊使用SASL認證,所以需要修改下指令碼。

root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim bin/kafka-producer-perf-test.sh
export KAFKA_OPTS="-Djava.security.auth.login.config=/data/elk/kafka/kafka_2.11-1.0.0/config/kafka_client_jaas.conf"
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# bin/kafka-producer-perf-test.sh --producer.config config/producer.properties --topic test --num-records 10000 --throughput -1 --print-metrics   --record-size 2000 --producer-props acks=1
# 選項:
# --topic TOPIC                               指定要生產訊息所使用的的Topic
# --num-records NUM-RECORDS                   要生產的訊息的總數量
# --throughput THROUGHPUT                     設定最大訊息吞吐量:總訊息數量/秒。-1表示不設定。
# --producer.config CONFIG-FILE               指定生產者配置檔案
# --producer-props                            手動指定配置,acks=1表示不允許丟訊息
# --print-metrics                             在測試結束後列印指標
# --record-size RECORD-SIZE                   每條訊息的大小,單位為位元組
7713 records sent, 1542.3 records/sec (2.94 MB/sec), 2059.4 ms avg latency, 4814.0 max latency.
10000 records sent, 1489.646954 records/sec (2.84 MB/sec), 2882.56 ms avg latency, 6501.00 ms max latency, 2814 ms 50th, 6132 ms 95th, 6430 ms 99th, 6497 ms 99.9th.

3、使用消費端效能測試工具"kafka-producer-perf-test.sh"進行壓測

注:由於這邊使用SASL認證,所以需要修改下指令碼。

root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim bin/kafka-consumer-perf-test.sh
export KAFKA_OPTS="-Djava.security.auth.login.config=/data/elk/kafka/kafka_2.11-1.0.0/config/kafka_client_jaas.conf"
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# bin/kafka-consumer-perf-test.sh --broker-list 127.0.0.1:9092 --consumer.config config/consumer.properties --threads 1 --topic test --messages 10000 
# 選項:
# --broker-list            Kafka伺服器列表
# --consumer.config        消費者配置檔案
# --threads                執行緒數量
# --topic                  測試使用的主題
# --messages               要處理的訊息總數
start.time, end.time, data.consumed.in.MB, MB.sec, data.consumed.in.nMsg, nMsg.sec, rebalance.time.ms, fetch.time.ms, fetch.MB.sec, fetch.nMsg.sec
2021-12-15 10:31:43:790, 2021-12-15 10:31:49:541, 16.5634, 2.8801, 10484, 1822.9873, 34, 5717, 2.8972, 1833.8289

附錄-開啟Kafka JMX監控功能

1、建立JMX監控要使用的賬號密碼檔案

建立JMX監控要使用的賬號密碼檔案"jmxremote.password"和許可權控制"jmxremote.access"檔案:

  • jmxremote.password 內容格式:
  • jmxremote.access 內容格式: <readonly|readwrite>
    注:這兩個檔案僅能使用600許可權,否則服務無法啟動。
root@yw-elk:/data/elk/kafka/cmak-3.0.0.5# cd /data/elk/kafka/kafka_2.11-1.0.0/
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim config/jmxremote.password
jmxuser xxx
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim config/jmxremote.access
jmxuser readonly
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# chmod 600 config/jmxremote.*

2、修改相關指令碼

在指定的指令碼檔案中找到以下內容,新增並修改相關內容。

root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim bin/kafka-run-class.sh
# JMX settings
if [ -z "$KAFKA_JMX_OPTS" ]; then
  KAFKA_JMX_OPTS="-Dcom.sun.management.jmxremote -Djava.rmi.server.hostname="127.0.0.1" -Dcom.sun.management.jmxremote.authenticate=true  -Dcom.sun.management.jmxremote.ssl=false  -Dcom.sun.management.jmxremote.password.file=/data/elk/kafka/kafka_2.11-1.0.0/config/jmxremote.password -Dcom.sun.management.jmxremote.access.file=/data/elk/kafka/kafka_2.11-1.0.0/config/jmxremote.access"
fi

# JMX port to use
if [  $JMX_PORT ]; then
  KAFKA_JMX_OPTS="$KAFKA_JMX_OPTS -Dcom.sun.management.jmxremote.port=$JMX_PORT"
fi
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# vim bin/kafka-server-start.sh
export JMX_PORT="12345"

3、重啟Kafka

root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# netstat -lnupt |grep 9092
tcp6       0      0 :::9092                 :::*                    LISTEN      12324/java
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# kill -15 12324
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# bin/kafka-server-start.sh  -daemon /data/elk/kafka/kafka_2.11-1.0.0/config/server.properties
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# netstat -lnupt |grep 9092
tcp6       0      0 :::9092                 :::*                    LISTEN      24280/java    
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# netstat -lnupt |grep 12345
tcp6       0      0 :::12345                :::*                    LISTEN      24280/java    

附錄-Kafka Manger(Kafka視覺化監控管理工具)

Kafka Manger是一個由雅虎開源的Kafka視覺化監控管理工具,由於商標的問題,與Apache產生了商業糾紛,現今階段已經更名為CMAK了。

1、安裝JDK11

CMAK-3.0.0.5需要JDK11的支援。

root@yw-elk:~# cd /data/elk/jdk/
root@yw-elk:/data/elk/jdk# tar xzvf jdk-11.0.13_linux-x64_bin.tar.gz

2、解壓CMAK二進位制包

root@yw-elk:/data/elk/jdk/jdk-11.0.13# cd /data/elk/kafka/
root@yw-elk:/data/elk/kafka# unzip cmak-3.0.0.5.zip

3、配置CMAK

root@yw-elk:/data/elk/kafka# cd cmak-3.0.0.5
root@yw-elk:/data/elk/kafka/cmak-3.0.0.5# vim conf/application.conf
kafka-manager.zkhosts="127.0.0.1:2181"
# kafka-manager連線zookeeper的連線地址。
cmak.zkhosts="127.0.0.1:2181"
# cmak連線zookeeper的連線地址。
basicAuthentication.enabled=true
# 開啟基本認證功能。訪問CMAK時需要輸入賬號密碼。
basicAuthentication.username="admin"
# 設定基本認證時要使用的賬號
basicAuthentication.password="xxx"
# 設定基本認證時要使用的賬號密碼

4、配置消費者屬性

開啟消費者支援SASL認證。
Kafka沒有配置SASL認證,可以不用執行此步驟。

root@yw-elk:/data/elk/kafka/cmak-3.0.0.5# vim conf/consumer.properties
### SASL ###
security.protocol=SASL_PLAINTEXT
sasl.mechanism=PLAIN

5、啟動CMAK服務

啟動CMAK服務可能需要會兒時間,請耐心等待。

root@yw-elk:/data/elk/kafka/cmak-3.0.0.5# nohup bin/cmak -Dconfig.file=/data/elk/kafka/cmak-3.0.0.5/conf/application.conf -Dhttp.port=8080 -java-home /data/elk/jdk/jdk-11.0.13 &
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# netstat -lnupt |grep 8080
tcp6       0      0 :::8080                 :::*                    LISTEN      22868/java

6、配置Nginx反向代理

配置完成後,需要配置域名解析。

root@yw-elk:/data/elk/kafka/cmak-3.0.0.5# vim /etc/nginx/conf.d/elk.conf
# kafka-manager
server {
    listen       80;
    server_name  kafka-manager.xxx.net;
    location / {
            proxy_pass http://127.0.0.1:8080;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    error_page 404 /404.html;
    location = /40x.html {
    }
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    }
}
root@yw-elk:/data/elk/kafka/cmak-3.0.0.5# nginx -s reload

7、訪問到CMAK

8、新增Kafka叢集

這裡一定要注意,填寫SASL配置的時候必須填寫內容,而不是指定配置檔案

9、解決在CMAK新增Kafka叢集的時候報以下錯誤問題

root@yw-elk:/data/elk/kafka/cmak-3.0.0.5# cd /data/elk/kafka/kafka_2.11-1.0.0/
root@yw-elk:/data/elk/kafka/kafka_2.11-1.0.0# bin/zookeeper-shell.sh 127.0.0.1:2181
Connecting to 127.0.0.1:2181
Welcome to ZooKeeper!
] create /kafka-manager/mutex ""
] create /kafka-manager/mutex/locks ""
] create /kafka-manager/mutex/leases ""
] ls /
[cluster, controller, brokers, zookeeper, kafka-acl, kafka-acl-changes, admin, isr_change_notification, log_dir_event_notification, controller_epoch, kafka-manager, consumers, latest_producer_id_block, config]
] quit

10、檢視消費組中的訊息堆積情況

  • LogSize,當前佇列大小偏移值。
  • Consumer Offset,當前消費訊息的偏移值。
  • Lag,滯後的訊息數量。

相關文章