背景
我們這邊應用部署的環(huán)境比較復雜枉侧,主要有以下幾種:
- 機器直接部署
- 通過kubernates集群部署
部署環(huán)境不統(tǒng)一官紫,導致查看應用日志很不方便肛宋。
業(yè)界日志系統(tǒng)架構
-
Collector的作用是:
- 清洗、匯聚數(shù)據(jù)束世,減少對于后端集群的壓力酝陈。
- 安全,不允許Agent直連kafka等內部集群毁涉,保證一定的安全性沉帮,即使后端發(fā)生調整也能保證對于Agent連接、認證方式的穩(wěn)定贫堰。
-
MQ的作用是削峰填谷穆壕、解耦、多次消費其屏。
組件選擇
選擇組件喇勋,我們這邊主要是從以下幾個方面進行考量的:
- 組件對應的開源生態(tài)完整、活躍度高
- 運維成本
- 易部署漫玄、性能好
Agent: 主要比較下相對熟悉的Logstash和filebeat茄蚯。
指標 Logstash filebeat Log-pilot 內存 大 小 背壓敏感協(xié)議 否 是 插件 多 多 功能 從多種輸入端采集并實時解析和轉換數(shù)據(jù)并輸出到多種輸出端 傳輸 支持收集容器的標準輸出日志和文件 輕重 重 輕 輕 過濾功能 強大的過濾功能 有過濾功能但較弱 Log-pilot支持不同的插件收集日志( Filebeat Plugin與Fluentd Plugin ) 集群 單節(jié)點 單節(jié)點 單節(jié)點 輸出到多個接收方 支持 支持 支持 原理 Logstash使用管道的方式進行日志的搜集和輸出,分為輸入input-->處理filter(不是必須的)-->輸出output睦优,每個階段都有不同的替代方式 開啟進程后會啟動一個或者多個探測器(prospectors)去檢測指定的日志目錄或者文檔建,對于探測器找出的每個日志文件,filebeat啟動收割進程(harvester),每個收割進程讀取一個日志文件的新內容壮不,并發(fā)送這些新的日志數(shù)據(jù)到處理程序(spooler)汗盘,處理程序會集合這些事件,最后filebeat會發(fā)送集合的數(shù)據(jù)到你指定的地點 一個好的agent應該是資源占用少询一,性能好隐孽,不依賴別的組件,可以獨立部署健蕊。而Logstash明顯不符合這幾點要求菱阵,也許正是基于這些考慮elastic推出了Filebeat。目前l(fā)og-pilot文檔相對較少缩功,如果要對filebeat做特定的配置晴及,需要重新對log-pilot鏡像配置完以后重打鏡像(譬如異常日志多行合并),且目前l(fā)og-pilot阿里目前已經不再維護了嫡锌,社區(qū)活躍度不夠虑稼。綜上所述琳钉,還是采用原生的Filebeat進行日志收集。
Collector暫時不用蛛倦,直接來看看MQ
MQ:
filebeat的輸出管道類型包括:
Elasticsearch Service歌懒、Elasticsearch、Logstash溯壶、Kafka及皂、Redis、File且改、Console目前的方案采用的是kafka作削峰填谷躲庄、解耦。
ETL:采用Logstash
Storage and Search:采用ElasticSearch钾虐、Kibana
到這里噪窘,基本可以看出我們的架構如下:
具體實現(xiàn)
Agent日志收集方案:
k8s日志收集filebeat日志收集方案:
編號 | 方案 | 優(yōu)點 | 缺點 |
---|---|---|---|
1 | 每個app的鏡像中都集成日志收集組件 | 部署方便,kubernetes的yaml文件無須特別配置效扫,可以為每個app自定義日志收集配置 | 強耦合倔监,不方便應用和日志收集組件升級和維護且會導致鏡像過大 |
2 | 單獨創(chuàng)建一個日志收集組件跟app的容器一起運行在同一個pod中 | 低耦合,擴展性強菌仁,方便維護和升級 | 需要對kubernetes的yaml文件進行單獨配置浩习,略顯繁瑣 |
3 | 將所有的Pod的日志都掛載到宿主機上,每臺主機上單獨起一個日志收集Pod | 完全解耦济丘,性能最高谱秽,管理起來最方便 | 需要統(tǒng)一日志收集規(guī)則,目錄和輸出方式 |
4 | 將所有的Pod的日志掛載到nfs-server上摹迷,在nfs-server上單獨啟一個日志收集Pod | 是方案3的升級版 | 需要統(tǒng)一日志收集規(guī)則疟赊,目錄和輸出方式,如果日志收集pod失效峡碉,會導致整個日志收集停止近哟,影響范圍比方案3大 |
綜合以上優(yōu)缺點,我們選擇使用方案三鲫寄。
統(tǒng)一日志格式:
日志類型 | 描述 | 日志包含的因子 | 日志格式 | 備注 |
---|---|---|---|---|
biz日志 | 用于業(yè)務中打印的info/warn | 全局鏈路線程號吉执、消費者IP、提供者IP地来、調用者應用名稱戳玫、消費者應用名稱、客戶號未斑、接口名稱咕宿、具體日志輸出的所在行、日志打印的內容 | 僅在代碼中l(wèi)ogger.info/warn輸出才會打印 | |
err 日志 | 用于業(yè)務輸出的error | 全局鏈路線程號、消費者IP荠列、提供者IP类浪、調用者應用名稱、消費者應用名稱肌似、客戶號费就、接口名稱、具體日志輸出的所在行川队、日志打印的堆棧信息 | 僅在代碼中l(wèi)ogger.error輸出才會打印 | |
io 日志 | 用于接口的輸入輸出參數(shù) | 全局鏈路線程號力细、消費者IP、提供者IP固额、調用者應用名稱眠蚂、消費者應用名稱、客戶號斗躏、接口名稱逝慧、具體日志輸出的所在行、輸入輸出的參數(shù)啄糙、接口耗時 | 僅配置了注解笛臣,出入參才不會打印 | |
monitor日志 | 用于監(jiān)控接口耗時、接口數(shù)據(jù)量 | 全局鏈路線程號隧饼、消費者IP沈堡、提供者IP、調用者應用名稱燕雁、消費者應用名稱诞丽、客戶號、接口名稱拐格、具體日志輸出的所在行僧免、數(shù)據(jù)量、接口耗時禁荒、結果標識(成功 or 失敗 ) | 默認全部打印 |
需要解決的問題:
1猬膨、日志歷史歸檔壓縮(未做)
2、日志敏感數(shù)據(jù)脫敏(未做)
3呛伴、異步日志打印
目前已對日志格式做了調整,增加了異步日志谒所,且將日志文件放到nacos上热康,可動態(tài)配置。
日志打印時間 | 線程號 | traceId | [調用方IP | 調用方 | 提供方IP | 提供方] | [請求url] | 日志打印類 [日志打印行號] - 日志內容
Filebeat配置:
vim /opt/filebeat-6.8.9-linux-x86_64/filebeat-all.yml
文件內容如下:
fields:
ip_inside: 10.210.100.141
fields_under_root: true
filebeat.config.inputs:
enabled: true
path: /opt/filebeat-6.8.9-linux-x86_64/conf/*/*.yml
reload.enabled: true
reload.period: 10s
logging.files:
keepfiles: 3
name: filebeat
path: /opt/filebeat-6.8.9-linux-x86_64/log/
logging.level: info
logging.to_files: true
output.kafka:
bluk_max_size: 4096
compression: gzip
compression_level: 7
hosts:
- 10.210.98.112:9092
partition.round_robin:
reachable_only: true
required_acks: 1
timeout: 45
topic: 'bi-sit'
worker: 1
processors:
- drop_fields:
fields: ["prospector","beat","host","source","log"]
queue.mem:
events: 4096
flush.min_events: 512
flush.timeout: 5s
參數(shù)說明:
序號 | 參數(shù) | 說明 |
---|---|---|
1 | fields.ip_inside | 存儲日志的宿主機IP |
2 | filebeat.config.inputs.path | 宿主機日志采集配置文件劣领,統(tǒng)一在/opt/filebeat-6.8.9-linux-x86_64/conf文件夾下 |
3 | output.kafka.topic | 日志在Kafka中使用的Topic |
4 | output.kafka.hosts | Kafka宿主機IP和Port姐军,檢測當前日志宿主機與Kafka宿主機是否可正常通信:telnet 10.210.98.112 9092 |
日志采集配置:
mkdir /opt/filebeat-6.8.9-linux-x86_64/conf
新建各個級別日志采集配置文件
以bi系統(tǒng)測試環(huán)境為例:新建文件夾:bi-sit
mkdir /opt/filebeat-6.8.9-linux-x86_64/conf/bi-sit
新建info日志采集配置文件bqx-bi-info.yml,文件內容如下:
- enabled: true
exclude_files:
- .gz$
fields:
log_type: err
server_name: bqx-bi
tags : bi-sit
fields_under_root: true
multiline.match: after
multiline.negate: true
multiline.pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2},[0-9]{3}
paths:
- /u01/bqx-bi/logs/info/bqx-bi-service-info*.log
type: log
參數(shù)說明:
序號 | 參數(shù) | 說明 |
---|---|---|
1 | fields.server_name | 服務名稱 |
2 | fields.tags | 服務標簽 |
3 | paths | 對應級別日志所在的路徑 |
Logstash配置:
# Sample Logstash configuration for creating a simple
# Beats -> Logstash -> Elasticsearch pipeline.
input {
kafka{
bootstrap_servers => ["10.210.3.68:9092"]
client_id => "logger"
group_id => "logger"
auto_offset_reset => "latest"
consumer_threads => 5
decorate_events => true
topics => ["logger"]
codec => json {
charset => "UTF-8" }
}
kafka{
bootstrap_servers => ["10.210.3.68:9092"]
client_id => "activity"
group_id => "activity"
auto_offset_reset => "latest"
consumer_threads => 1
decorate_events => true
topics => ["activity"]
codec => json {
charset => "UTF-8" }
}
kafka{
bootstrap_servers => ["10.210.3.68:9092"]
client_id => "mysqlslowlog"
group_id => "mysqlslowlog"
auto_offset_reset => "latest"
consumer_threads => 1
decorate_events => true
topics => ["mysqlslowlog"]
codec => json {
charset => "UTF-8" }
}
kafka{
bootstrap_servers => ["10.210.3.68:9092"]
client_id => "bi-prd"
group_id => "bi-prd"
auto_offset_reset => "latest"
consumer_threads => 2
decorate_events => true
topics => ["bi-prd"]
codec => json {
charset => "UTF-8" }
}
}
filter {
grok{
match => ["message","(?<logdate>%{YEAR}-%{MONTHNUM}-%{MONTHDAY} %{TIME})",
"message","# Time: (?<time>[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2})"
]
}
date{
match => [ "logdate", "yyyy-MM-dd HH:mm:ss,SSS"]
locale => "en"
timezone => "Asia/Shanghai"
}
mutate{
remove_field => ["logdate","@metadata"]
}
}
output {
elasticsearch {
hosts => ["http://10.210.3.68:9200"]
index => "%{[tags]}-log-%{+YYYY.MM.dd}"
user => "es用戶名"
password => "es密碼"
#ssl => true
#ssl_certificate_verification => false
}
}
output中user和password,如果有用戶名和密碼的話奕锌,需要設置著觉,沒有可以去掉
針對過期的index需要通過定時任務將對應的index刪除掉
腳本如下:
#!/bin/bash
#刪除早于15天的ES集群的索引
function delete_indices() {
param=$(echo $1)
#截取索引的日期部分(用于下面的日期比較是否小于15日),我的索引是com-字符串后面的部分為日期惊暴, 比如: www.test.com-2020.08.08
dateValue=$(echo ${param#*com-})
#截取日期的前部分作為索引的名稱(后續(xù)需要替換-為.饼丘, 然后和日期拼接起來成為一個真正的索引名稱,用于刪除)
name=$(echo $2)
echo "name=$name date=$dateValue"
comp_date=`date -d "15 day ago" +"%Y-%m-%d"`
date1="$dateValue 00:00:00"
date2="$comp_date 00:00:00"
t1=`date -d "$date1" +%s`
t2=`date -d "$date2" +%s`
if [ $t1 -le $t2 ]; then
echo "$1時間早于$comp_date辽话,進行索引刪除"
#轉換一下格式肄鸽,將類似www-test-com格式轉化為www.test.com
#轉換一下格式,將類似2020-10-01格式轉化為2020.10.01
format_date=`echo $dateValue| sed 's/-/\./g'`
#拼接成索引名稱
indexName="$name-$format_date"
curl -u admin:admin -k -XDELETE http://10.210.3.68:9200/$indexName
#刪除索引
echo "$indexName刪除成功"
fi
}
curl -u admin:admin -k http://10.210.3.68:9200/_cat/indices?v | awk -F" " '{print $3}' |egrep prod|awk -F"-" '{print $NF}' | egrep "[0-9]*\.[0-9]*\.[0-
9]*" | sort | uniq | sed 's/\./-/g'| while read LINE
do
#調用索引刪除函數(shù)油啤, 結果打印到日志
delete_indices $LINE prod-log >> /home/logs/delete_indices.log
done
curl -u admin:admin -k http://10.210.3.68:9200/_cat/indices?v | awk -F" " '{print $3}' |egrep activity|awk -F"-" '{print $NF}' | egrep "[0-9]*\.[0-9]*\
.[0-9]*" | sort | uniq | sed 's/\./-/g'| while read LINE
do
#調用索引刪除函數(shù)典徘, 結果打印到日志
delete_indices $LINE activity-log >> /home/logs/delete_indices.log
done
匹配邏輯需要根據(jù)你自己的索引規(guī)范來做適當調整