ELK 日志分析平台
大约 7 分钟约 2244 字
ELK 日志分析平台
简介
ELK Stack(Elasticsearch + Logstash + Kibana)是一套开源的日志收集、存储、分析和可视化解决方案。Elasticsearch 负责海量数据的存储与搜索,Logstash 完成日志的采集与处理,Kibana 提供直观的数据可视化界面。配合 Filebeat 轻量级日志采集器,ELK 能够构建从日志采集到可视化分析的全链路日志管理体系。
特点
Elasticsearch 配置
集群配置
# config/elasticsearch.yml
cluster.name: elk-production
node.name: es-node-1
node.roles: [master, data, ingest]
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
# 网络配置
network.host: 0.0.0.0
http.port: 9200
transport.port: 9300
# 集群发现
discovery.seed_hosts: ["es-node-1:9300", "es-node-2:9300", "es-node-3:9300"]
cluster.initial_master_nodes: ["es-node-1", "es-node-2", "es-node-3"]
# 内存配置
bootstrap.memory_lock: true
# 索引生命周期管理
xpack.security.enabled: true
xpack.security.enrollment.enabled: true
xpack.security.http.ssl.enabled: true
xpack.security.transport.ssl.enabled: trueJVM 与系统调优
# config/jvm.options
## 堆内存设置(建议不超过物理内存的 50%,最大不超过 31GB)
-Xms8g
-Xmx8g
## GC 配置
-XX:+UseG1GC
-XX:G1ReservePercent=25
-XX:InitiatingHeapOccupancyPercent=30# 系统参数调优
# /etc/security/limits.conf
# elasticsearch soft memlock unlimited
# elasticsearch hard memlock unlimited
# elasticsearch soft nofile 65536
# elasticsearch hard nofile 65536
# /etc/sysctl.conf
# vm.max_map_count=262144
sysctl -p
# 查看 Elasticsearch 集群健康状态
curl -u elastic:password http://localhost:9200/_cluster/health?pretty
# 查看节点信息
curl -u elastic:password http://localhost:9200/_cat/nodes?v
# 查看索引列表
curl -u elastic:password http://localhost:9200/_cat/indices?v索引模板与生命周期
// 索引模板 — 日志索引
PUT _index_template/logs-template
{
"index_patterns": ["app-logs-*"],
"template": {
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"refresh_interval": "5s",
"analysis": {
"analyzer": {
"log_analyzer": {
"type": "pattern",
"pattern": "\\W+"
}
}
}
},
"mappings": {
"properties": {
"timestamp": { "type": "date" },
"level": { "type": "keyword" },
"service": { "type": "keyword" },
"message": { "type": "text", "analyzer": "log_analyzer" },
"trace_id": { "type": "keyword" },
"host": { "type": "keyword" },
"request_path": { "type": "keyword" },
"response_time_ms": { "type": "float" },
"status_code": { "type": "integer" }
}
}
}
}// 索引生命周期策略(ILM)
PUT _ilm/policy/logs-policy
{
"policy": {
"phases": {
"hot": {
"min_age": "0ms",
"actions": {
"rollover": {
"max_age": "1d",
"max_primary_shard_size": "50gb"
},
"set_priority": { "priority": 100 }
}
},
"warm": {
"min_age": "7d",
"actions": {
"shrink": { "number_of_shards": 1 },
"forcemerge": { "max_num_segments": 1 },
"set_priority": { "priority": 50 }
}
},
"cold": {
"min_age": "30d",
"actions": {
"set_priority": { "priority": 0 }
}
},
"delete": {
"min_age": "90d",
"actions": {
"delete": {}
}
}
}
}
}Logstash 日志处理
Logstash 管道配置
# pipeline/logstash.conf
input {
beats {
port => 5044
host => "0.0.0.0"
}
# 也可直接从文件读取
file {
path => "/var/log/nginx/access.log"
start_position => "beginning"
tags => ["nginx"]
}
# 从 Kafka 读取
kafka {
bootstrap_servers => "kafka:9092"
topics => ["app-logs"]
group_id => "logstash-consumer"
consumer_threads => 4
}
}
filter {
# 解析 Nginx 访问日志
if "nginx" in [tags] {
grok {
match => {
"message" => '%{IPORHOST:remote_addr} - %{DATA:remote_user} \[%{HTTPDATE:time_local}\] "%{WORD:method} %{DATA:request} HTTP/%{NUMBER:http_version}" %{INT:status} %{INT:body_bytes_sent} "%{DATA:http_referer}" "%{DATA:http_user_agent}"'
}
remove_field => ["message"]
}
# 从请求中提取响应时间
mutate {
convert => {
"status" => "integer"
"body_bytes_sent" => "integer"
}
}
}
# 解析 JSON 格式的应用日志
if [tags][0] == "app" {
json {
source => "message"
target => "parsed"
}
# 提取字段
mutate {
rename => {
"[parsed][level]" => "log_level"
"[parsed][service]" => "service_name"
"[parsed][traceId]" => "trace_id"
}
}
}
# 添加地理信息
if [remote_addr] {
geoip {
source => "remote_addr"
target => "geoip"
}
}
# 添加时间戳
date {
match => ["time_local", "dd/MMM/yyyy:HH:mm:ss Z"]
target => "@timestamp"
}
}
output {
# 输出到 Elasticsearch
elasticsearch {
hosts => ["https://es-node-1:9200"]
user => "elastic"
password => "${ES_PASSWORD}"
index => "app-logs-%{+YYYY.MM.dd}"
ssl_certificate_verification => false
}
# 调试输出(开发环境)
# stdout {
# codec => rubydebug
# }
}Logstash 性能调优
# config/logstash.yml
pipeline.workers: 4 # 工作线程数(建议等于 CPU 核心数)
pipeline.batch.size: 125 # 每批处理事件数
pipeline.batch.delay: 50 # 批次等待时间(ms)
pipeline.ordered: false # 不保证顺序以提升性能
# 队列配置
queue.type: persisted # 持久化队列(防止数据丢失)
path.queue: /var/lib/logstash/queue
queue.page_capacity: 250mb
queue.max_events: 0 # 无限制
queue.max_bytes: 1024mb # 最大队列大小Filebeat 日志采集
Filebeat 配置
# filebeat.yml
filebeat.config:
modules:
path: ${path.config}/modules.d/*.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/nginx/access.log
- /var/log/nginx/error.log
fields:
app: nginx
env: production
fields_under_root: true
tags: ["nginx"]
- type: log
enabled: true
paths:
- /opt/myapp/logs/*.log
multiline:
pattern: '^\d{4}-\d{2}-\d{2}'
negate: true
match: after
max_lines: 500
timeout: 5s
fields:
app: myapp
env: production
fields_under_root: true
tags: ["app"]
- type: container
enabled: true
paths:
- /var/lib/docker/containers/*/*.log
processors:
- add_docker_metadata:
host: "unix:///var/run/docker.sock"
# 输出到 Logstash
output.logstash:
hosts: ["logstash:5044"]
loadbalance: true
worker: 2
compression_level: 3
# 或直接输出到 Elasticsearch
# output.elasticsearch:
# hosts: ["https://es-node-1:9200"]
# username: "elastic"
# password: "${ES_PASSWORD}"
# index: "filebeat-%{[agent.version]}-%{+yyyy.MM.dd}"
processors:
- add_host_metadata:
when.not.contains.tags: forwarded
- add_cloud_metadata: ~
- add_docker_metadata: ~
- drop_fields:
fields: ["agent", "ecs", "input", "log.offset"]
ignore_missing: trueDocker Compose 部署 ELK
# docker-compose.yml
version: '3.8'
services:
elasticsearch:
image: elasticsearch:8.12.0
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- "ES_JAVA_OPTS=-Xms1g -Xmx1g"
volumes:
- esdata:/usr/share/elasticsearch/data
ports:
- "9200:9200"
networks:
- elk
logstash:
image: logstash:8.12.0
volumes:
- ./logstash/pipeline:/usr/share/logstash/pipeline
- ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml
ports:
- "5044:5044"
depends_on:
- elasticsearch
networks:
- elk
kibana:
image: kibana:8.12.0
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
ports:
- "5601:5601"
depends_on:
- elasticsearch
networks:
- elk
filebeat:
image: elastic/filebeat:8.12.0
user: root
volumes:
- ./filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml
- /var/log:/var/log:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- /var/run/docker.sock:/var/run/docker.sock
depends_on:
- logstash
networks:
- elk
volumes:
esdata:
networks:
elk:
driver: bridgeKibana 仪表盘
常用查询与聚合
// Kibana Dev Tools — 常用查询
// 搜索最近 1 小时的错误日志
GET app-logs-*/_search
{
"query": {
"bool": {
"must": [
{ "match": { "log_level": "ERROR" } },
{ "range": { "@timestamp": { "gte": "now-1h" } } }
]
}
},
"sort": [{ "@timestamp": "desc" }],
"size": 50
}
// 按服务统计错误数量
GET app-logs-*/_search
{
"size": 0,
"query": {
"term": { "log_level": "ERROR" }
},
"aggs": {
"by_service": {
"terms": { "field": "service_name", "size": 20 }
}
}
}
// 统计 API 响应时间 P99
GET app-logs-*/_search
{
"size": 0,
"aggs": {
"response_time_percentiles": {
percentiles": {
"field": "response_time_ms",
"percents": [50, 90, 95, 99]
}
}
}
}创建仪表盘
Kibana 仪表盘创建步骤:
1. 打开 Kibana -> Management -> Index Patterns
- 创建索引模式: app-logs-*
- 选择时间字段: @timestamp
2. 创建可视化(Discover -> Visualize)
- 错误日志趋势图: 折线图,按 log_level=ERROR 聚合
- 服务健康状态: 饼图,按 service_name 聚合,按 log_level 分桶
- 响应时间分布: 柱状图,按 response_time_ms 范围分桶
- 热门错误消息: 数据表,按 message 词条聚合 Top 20
3. 组合仪表盘(Dashboard -> Create)
- 添加上述可视化组件
- 配置时间范围过滤器
- 添加服务名称下拉过滤器
4. 常用 KQL 查询语法
- log_level: "ERROR"
- service_name: "user-api" and status_code >= 500
- message: *timeout*
- trace_id: "abc-123-def"优点
缺点
总结
ELK Stack 提供了从日志采集(Filebeat)到处理(Logstash)、存储(Elasticsearch)和可视化(Kibana)的完整日志管理解决方案。通过合理配置索引生命周期管理日志存储成本,利用 Logstash 的 grok 过滤器解析各类日志格式,配合 Kibana 仪表盘实现实时监控和告警,能够满足企业级日志分析的需求。建议根据日志量级选择合适的架构(小型可 Filebeat 直连 Elasticsearch),并做好索引生命周期管理以控制存储成本。
关键知识点
- DevOps 主题的核心是让交付更快、更稳、更可审计。
- 自动化不是把命令脚本化,而是把失败、回滚、权限和观测一起设计进去。
- 生产链路必须明确制品、环境、凭据、配置和责任边界。
项目落地视角
- 把流水线拆成构建、测试、制品、部署、验证和回滚几个阶段。
- 为关键步骤补齐日志、指标、通知和人工兜底点。
- 定期演练扩容、回滚、故障注入和灾备切换。
常见误区
- 只关注部署成功,不关注失败恢复和审计追踪。
- 把环境差异藏在临时脚本或人工操作里。
- 上线频率高了以后,没有标准化制品和配置管理。
进阶路线
- 继续补齐 GitOps、可观测性、平台工程和成本治理。
- 把主题和应用架构、安全、权限、备份恢复联动起来理解。
- 形成团队级平台能力,而不是每个项目重复造轮子。
适用场景
- 当你准备把《ELK 日志分析平台》真正落到项目里时,最适合先在一个独立模块或最小样例里验证关键路径。
- 适合构建自动化交付、基础设施治理、监控告警和生产发布体系。
- 当团队规模扩大、发布频率提升或环境变多时,这类主题会显著影响交付效率。
落地建议
- 所有自动化流程尽量做到幂等、可审计、可回滚。
- 把制品、变量、凭据和执行权限分层管理。
- 定期演练扩容、回滚、密钥轮换和灾备恢复。
排错清单
- 先定位失败发生在代码、构建、制品、环境还是权限层。
- 检查流水线变量、凭据、镜像标签和目标环境配置是否一致。
- 如果问题偶发,重点看并发发布、资源争抢和外部依赖抖动。
复盘问题
- 如果把《ELK 日志分析平台》放进你的当前项目,最先要验证的输入、输出和失败路径分别是什么?
- 《ELK 日志分析平台》最容易在什么规模、什么边界条件下暴露问题?你会用什么指标或日志去确认?
- 相比默认实现或替代方案,采用《ELK 日志分析平台》最大的收益和代价分别是什么?
