日志集中管理的工程需求
在网站运维和DevOps实践中,分布式系统的日志分散在数十甚至上百台服务器上。传统SSH登录逐台grep的方式效率极低,且无法做跨服务关联分析。ELK(Elasticsearch+Logstash+Kibana)栈是日志分析领域的事实标准,支持TB级日志的全文检索、聚合分析和可视化仪表盘。本文覆盖从单节点部署到生产可用的完整配置流程。
Elasticsearch集群部署配置
Elasticsearch是ELK的存储和检索引擎,基于Lucene构建。生产环境建议至少3节点集群以保障高可用。
# docker-compose.yml - 3节点ES集群
version: '3.8'
services:
es-node1:
image: elasticsearch:8.13.0
environment:
- node.name=es-node1
- cluster.name=elk-cluster
- discovery.seed_hosts=es-node2,es-node3
- cluster.initial_master_nodes=es-node1,es-node2,es-node3
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms16g -Xmx16g"
- xpack.security.enabled=true
- xpack.security.transport.ssl.enabled=true
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- es-data1:/usr/share/elasticsearch/data
- ./certs:/usr/share/elasticsearch/config/certs
ports:
- "9200:9200"
es-node2:
image: elasticsearch:8.13.0
environment:
- node.name=es-node2
- cluster.name=elk-cluster
- discovery.seed_hosts=es-node1,es-node3
- cluster.initial_master_nodes=es-node1,es-node2,es-node3
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms16g -Xmx16g"
- xpack.security.enabled=true
volumes:
- es-data2:/usr/share/elasticsearch/data
es-node3:
image: elasticsearch:8.13.0
environment:
- node.name=es-node3
- cluster.name=elk-cluster
- discovery.seed_hosts=es-node1,es-node2
- cluster.initial_master_nodes=es-node1,es-node2,es-node3
- "ES_JAVA_OPTS=-Xms16g -Xmx16g"
volumes:
- es-data3:/usr/share/elasticsearch/data
volumes:
es-data1:
es-data2:
es-data3:
关键配置说明:
discovery.seed_hosts:种子节点列表,用于集群发现cluster.initial_master_nodes:首次启动时参与master选举的节点bootstrap.memory_lock=true:锁定堆内存,防止swap导致性能下降ES_JAVA_OPTS:JVM堆大小设置为物理内存的50%,不超过32GB
Logstash日志采集与过滤管道
Logstash负责日志收集、解析和转发。对于Nginx访问日志,需要配置Grok模式解析。在生产环境中,建议用Filebeat替代Logstash做日志采集(更轻量),Logstash仅做复杂解析。
# logstash.conf - Nginx访问日志解析管道
input {
beats {
port => 5044
}
}
filter {
# 解析Nginx combined格式日志
grok {
match => {
"message" => '%{IPORHOST:client_ip} - %{DATA:user} \[%{HTTPDATE:timestamp}\] "%{WORD:method} %{URIPATHPARAM:uri} HTTP/%{NUMBER:http_version}" %{NUMBER:status_code} %{NUMBER:bytes} "%{DATA:referer}" "%{DATA:user_agent}"'
}
overwrite => ["message"]
}
# 解析User-Agent
useragent {
source => "user_agent"
target => "ua"
}
# GeoIP地理位置
geoip {
source => "client_ip"
target => "geo"
}
# 时间戳处理
date {
match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]
target => "@timestamp"
}
# 添加环境标签
mutate {
add_field => {
"environment" => "production"
"application" => "web-frontend"
}
remove_field => ["user_agent", "timestamp"]
}
}
output {
elasticsearch {
hosts => ["https://es-node1:9200"]
user => "elastic"
password => "${ES_PASSWORD}"
ssl => true
index => "nginx-logs-%{+YYYY.MM.dd}"
}
}
Logstash管道三段式结构:input定义数据来源,filter做解析和转换,output写入Elasticsearch。Grok模式本质上是用命名正则提取字段,是日志分析的核心环节。
Filebeat轻量采集器配置
Filebeat部署在每台应用服务器上,负责实时读取日志文件并转发到Logstash或直接写入Elasticsearch:
# filebeat.yml
filebeat.inputs:
- type: filestream
id: nginx-access
paths:
- /var/log/nginx/access.log
fields:
log_type: nginx-access
fields_under_root: true
- type: filestream
id: app-log
paths:
- /opt/app/logs/*.log
fields:
log_type: application
multiline:
type: pattern
pattern: '^\d{4}-\d{2}-\d{2}'
match: before
negate: true
output.logstash:
hosts: ["logstash:5044"]
loadbalance: true
bulk_max_size: 2048
# 自动注册模板
setup.template.enabled: true
setup.template.name: "nginx-logs"
setup.template.pattern: "nginx-logs-*"
multiline配置用于处理Java堆栈跟踪等多行日志,将不以日期开头的行合并到前一行。
Kibana索引模式与可视化仪表盘
Kibana提供日志搜索和可视化界面。安装完成后需要创建索引模式(Index Pattern)来定义时间字段:
# Kibana配置
server.port: 5601
server.host: "0.0.0.0"
elasticsearch.hosts: ["https://es-node1:9200"]
elasticsearch.username: "kibana_system"
elasticsearch.password: "${KIBANA_PASSWORD}"
在Kibana中创建索引模式:
# 通过API创建索引模式
curl -X POST "http://kibana:5601/api/index_patterns/index_pattern" -H "kbn-xsrf: true" -H "Content-Type: application/json" -d '{
"index_pattern": {
"title": "nginx-logs-*",
"timeFieldName": "@timestamp"
}
}'
常用可视化类型:
- Lens(柱状图/折线图):按时间维度统计请求量、状态码分布
- 饼图:HTTP状态码占比、User-Agent类型分布
- 坐标地图:基于GeoIP的请求来源地理位置分布
- 数据表:慢请求排行、错误日志明细
ILM索引生命周期管理
日志索引持续增长会消耗大量磁盘空间。ILM(Index Lifecycle Management)自动管理索引的滚动、压缩和删除:
# 创建ILM策略:日志保留30天,超过50GB滚动
PUT _ilm/policy/nginx-logs-policy
{
"policy": {
"phases": {
"hot": {
"actions": {
"rollover": {
max_size": "50gb",
max_age": "1d"
},
"set_priority": { "priority": 100 }
}
},
"warm": {
"min_age": "7d",
"actions": {
"shrink": { "number_of_shards": 1 },
"forcemerge": { "max_num_segments": 1 },
"set_priority": { "priority": 50 }
}
},
"delete": {
"min_age": "30d",
"actions": {
"delete": {}
}
}
}
}
}
# 绑定索引模板到ILM策略
PUT _index_template/nginx-logs
{
"index_patterns": ["nginx-logs-*"],
"template": {
"settings": {
"index.lifecycle.name": "nginx-logs-policy",
"number_of_shards": 3,
"number_of_replicas": 1,
"refresh_interval": "5s"
}
}
}
hot阶段支持高频率写入,warm阶段压缩索引降低存储成本,delete阶段自动清理过期数据。这种分层策略在CI/CD流水线和监控告警体系中是标准实践。
故障应急响应中的日志查询
生产故障时,快速定位错误日志是应急响应的核心。Kibana KQL查询语法:
# 查找5xx错误且响应时间超过5秒的请求
status_code >= 500 AND request_time > 5
# 按URI分组统计错误数
# 在Kibana Lens中:
# X轴: uri.keyword (Terms)
# Y轴: Count
# 过滤: status_code >= 500
# 查找特定IP的所有请求
client_ip: "203.0.113.50"
# 查找慢查询Top 10
# 按request_time降序排序,查看明细
在混沌工程实践中,可以通过ELK验证故障注入后的系统行为。例如注入网络延迟后,观察Nginx日志中504超时错误的增长趋势和影响范围。
性能调优与容量规划
ELK集群的常见性能问题及解决方案:
- 写入延迟高:增加
refresh_interval到30s,批量写入减小索引刷新频率 - 查询慢:使用filter替代query(filter可缓存),增加shard数量到数据量的1-2倍
- 内存不足:监控JVM heap使用率,超过75%触发GC频繁时需扩容
- 磁盘满:调整ILM策略缩短保留期,或启用cold tier使用对象存储
日志量估算:单台Nginx服务器日均产生约500MB日志,100台服务器每月约1.5TB。按3副本计算需要约4.5TB存储,考虑30天保留期和warm阶段压缩,实际需要约3TB可用存储空间。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/elk-ri-zhi-fen-xi-ping-tai-da-jian-shi-zhan/