纲要
- 微服务日志收集的挑战
ELK技术栈概述Elasticsearch:搜索引擎与数据存储Logstash:日志采集与处理Kibana:数据可视化
- ELK 工作流程
- 基于
Docker构建 ELK 架构- 环境准备与目录结构
- 启动
Elasticsearch与Kibana - 配置与启动
Logstash- 核心配置文件结构:
input、filter、output - 单一日志采集示例:
MySQL慢查询日志 - 多日志源采集示例:结合
Redis访问日志 - 使用
grok语法进行日志解析
- 核心配置文件结构:
- 验证日志流转
- 常见问题与调试技巧
- 总结
微服务日志收集的挑战
在微服务架构中,系统被拆分为多个独立的服务,例如用户服务、订单服务,同时还可能包含MySQL、Redis等基础组件。每个服务在运行过程中都会产生自己的日志文件。
当我们需要排查问题或进行性能优化时,就必须收集并分析这些分散的日志。由于日志散落在不同的服务节点上,且彼此之间缺乏关联,如何高效、统一地收集与分析日志就成为了一个核心挑战。
ELK技术栈正是为了解决这一难题而生的。它提供了一整套从采集、存储到可视化的解决方案,帮助开发人员快速构建日志分析平台。
ELK 技术栈概述
ELK是三个开源软件的首字母缩写:
Elasticsearch:一个基于 Lucene 的分布式搜索和分析引擎,用于集中存储和索引日志数据。Logstash:一个服务端数据处理管道,能够从多个来源采集数据、转换数据,并将数据发送到指定目标。Kibana:一个可视化平台,负责将Elasticsearch中的数据通过仪表盘、图表等形式展现出来。
核心工作流程
下图展示了ELK的基本工作流程:
Logstash从各个服务的日志文件或系统指标中采集数据,这一过程通常由配置文件定义,也可使用轻量级的Filebeat作为日志采集代理。- 采集到的日志经过
Logstash的filter插件进行解析、清洗和格式化。 - 处理后的数据被推送到
Elasticsearch集群中进行存储和索引。 Kibana连接到Elasticsearch,提供可视化界面和仪表盘,开发人员可以实时监控系统状态和分析日志。
基于 Docker 构建 ELK 架构
在实际开发中,我们通常会借助Docker来快速搭建和部署ELK环境,从而保证各组件之间的一致性,并简化配置管理。
环境准备与目录结构
首先在项目目录中创建必要的文件夹和配置文件。推荐的目录结构如下:
elk-stack/ ├── docker-compose.yml ├── elasticsearch/ │ └── data/ # 挂载数据目录,需要提前设置权限 ├── logstash/ │ ├── config/ │ │ └── logstash.conf # Logstash 核心配置 │ └── logs/ # 放置示例日志文件,如 mysql-slow.log └── kibana/由于Elasticsearch容器在启动时需要写入数据目录,必须确保宿主机上的挂载目录有足够的权限。可以通过以下命令设置:
chmod-R777./elasticsearch/data启动 Elasticsearch 与 Kibana
Elasticsearch与Kibana通常可以先行部署,因为二者可以脱离Logstash独立运行并相互配合。
下面是一个简单的docker-compose.yml配置示例:
version:'3.8'services:elasticsearch:image:elasticsearch:7.17.10container_name:elasticsearchenvironment:-discovery.type=single-node-"ES_JAVA_OPTS=-Xms512m -Xmx512m"ports:-"9200:9200"volumes:-./elasticsearch/data:/usr/share/elasticsearch/datanetworks:-elkkibana:image:kibana:7.17.10container_name:kibanaports:-"5601:5601"environment:-ELASTICSEARCH_HOSTS=http://elasticsearch:9200depends_on:-elasticsearchnetworks:-elknetworks:elk:driver:bridge在项目根目录执行docker-compose up -d即可启动。启动过程中Elasticsearch需要一定时间来初始化,可以通过访问http://<服务器IP>:9200验证其状态。
当返回JSON格式的节点信息时表示启动成功。Kibana则通过http://<服务器IP>:5601访问。
配置与启动 Logstash
Logstash的核心在于其配置文件,它定义了数据从哪来(input)、如何加工(filter)以及送往哪里(output)。典型的logstash.conf结构如下:
input { # 定义数据源 } filter { # 定义数据处理逻辑 } output { # 定义数据输出目标 }单一日志采集:MySQL 慢查询日志
首先准备一份MySQL慢查询日志(mysql-slow.log),日志内容示例:
# Time: 2026-07-09T10:00:00.000000Z # User@Host: root[root] @ localhost [] # Query_time: 12.345678 Lock_time: 0.000123 Rows_sent: 1 Rows_examined: 100000 SET timestamp=1752487200; SELECT * FROM orders WHERE user_id = 123 AND status = 'pending';为了解析这种多行格式的日志,我们需要在Logstash配置中同时指定文件输入、多行处理规则以及使用grok语法进行字段提取。完整配置如下(路径按实际挂载调整):
input { file { path => "/usr/share/logstash/logs/mysql-slow.log" type => "mysql-slow" start_position => "beginning" # 多行合并规则:以 "# Time:" 开头的行作为一条日志的开始 codec => multiline { pattern => "^# Time:" negate => true what => "previous" } } } filter { if [type] == "mysql-slow" { # 使用 grok 解析慢查询日志 grok { match => { "message" => "^# Time: %{TIMESTAMP_ISO8601:timestamp}\s+# User@Host: %{USER:user}\[%{USER:host}\] @ %{HOSTNAME:client_host} \[\]\s+# Query_time: %{NUMBER:query_time:float}\s+Lock_time: %{NUMBER:lock_time:float}\s+Rows_sent: %{NUMBER:rows_sent:int}\s+Rows_examined: %{NUMBER:rows_examined:int}\s+SET timestamp=%{NUMBER:set_timestamp:int};\s+%{GREEDYDATA:sql_query}" } } # 将 query_time 转换为毫秒方便分析 mutate { convert => { "query_time" => "float" } } # 删除原始 message 字段(可选) remove_field => ["message", "set_timestamp"] } } output { if [type] == "mysql-slow" { elasticsearch { hosts => ["http://elasticsearch:9200"] index => "mysql-slow-%{+YYYY.MM.dd}" } # 同时输出到控制台用于调试 stdout { codec => rubydebug } } }配置说明:
- input:
file插件读取指定路径的日志文件,start_position => "beginning"表示首次从头读取,之后会记录偏移量以支持断点续传;multilinecodec 将以# Time:开头的行作为新日志的起始,之前的内容合并到上一条日志。 - filter:
grok插件使用预定义和自定义正则表达式将非结构化日志解析为字段,如query_time、sql_query等。mutate用于类型转换和字段裁剪。grok语法可借助 Grok Debugger 在线调试。 - output:将解析后的数据按天索引写入
Elasticsearch,同时输出到控制台方便观察。
多日志源采集:结合 Redis 访问日志
在实际项目中,Logstash往往需要同时采集多种类型的日志。通过在配置中为不同来源打上type标签,再结合if条件判断,可以很容易地实现多源处理。
假设我们新增Redis的访问日志(redis-access.log),内容示例:
2026-07-09 10:05:03.123 1.2.3.4 SET mykey myvalue 2026-07-09 10:05:04.567 5.6.7.8 GET mykey更新后的logstash.conf可扩展为:
input { file { path => "/usr/share/logstash/logs/mysql-slow.log" type => "mysql-slow" start_position => "beginning" codec => multiline { pattern => "^# Time:" negate => true what => "previous" } } file { path => "/usr/share/logstash/logs/redis-access.log" type => "redis-access" start_position => "beginning" } } filter { if [type] == "mysql-slow" { grok { ... } # 同上 } if [type] == "redis-access" { grok { match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{IP:client_ip} %{WORD:command} %{GREEDYDATA:args}" } } date { match => ["timestamp", "yyyy-MM-dd HH:mm:ss.SSS"] target => "@timestamp" } } } output { if [type] == "mysql-slow" { elasticsearch { hosts => ["http://elasticsearch:9200"] index => "mysql-slow-%{+YYYY.MM.dd}" } } if [type] == "redis-access" { elasticsearch { hosts => ["http://elasticsearch:9200"] index => "redis-access-%{+YYYY.MM.dd}" } } stdout { codec => rubydebug } }通过为每个input指定不同的type,在filter和output阶段用if [type] == "..."分支处理,就可以灵活地扩展多种日志的采集流程,而不会相互干扰。
启动 Logstash
在将logstash.conf写好并放入./logstash/config/后,需要将其添加到docker-compose.yml中:
logstash:image:logstash:7.17.10container_name:logstashvolumes:-./logstash/config/logstash.conf:/usr/share/logstash/pipeline/logstash.conf:ro-./logstash/logs:/usr/share/logstash/logsdepends_on:-elasticsearchnetworks:-elkcommand:logstash-f /usr/share/logstash/pipeline/logstash.conf注意:Logstash启动较慢,因为它是基于JRuby的 JVM 程序,需要等待初始化完成。可以通过docker logs -f logstash观察启动日志。当控制台输出开始解析日志记录时,即表示运行正常。
验证日志流转
- 访问
Kibana控制台(http://<服务器IP>:5601)。 - 进入Management → Stack Management → Index Patterns,创建索引模式,例如
mysql-slow-*、redis-access-*。 - 在Discover页面即可看到解析好的日志数据,字段如
query_time、sql_query、client_ip等都可被用来过滤和聚合。 - 之后可以创建仪表盘,对慢查询次数、耗时分布等进行可视化监控。
常见问题与调试技巧
- 权限问题:
Elasticsearch容器无法写入挂载的数据目录。解决:使用chmod 777或更改目录属主为1000:1000(Elasticsearch容器内运行用户 uid 通常为 1000)。 Logstash启动缓慢:JVM 启动需要时间,可以通过调整 JVM 堆大小(如LS_JAVA_OPTS=-Xmx512m -Xms512m)来加速。- 配置不生效:检查配置文件的缩进和引号,确保
path指向容器内部的正确路径(而非宿主机路径)。可在logstash.conf中加入stdout { codec => rubydebug }来本地调试。 grok匹配失败:利用 Grok Debugger 在线测试,逐步调整模式。- 多行合并错误:
multilinecodec 的pattern必须能匹配日志的第一行,negate与what的组合要符合预期。
总结
通过Docker我们可以快速构建起一套功能完善的ELK日志收集系统。Logstash灵活的input-filter-output管道设计,使其能够轻松应对多种日志格式的采集与处理需求。
在实际项目中,只需根据业务需要扩展配置即可实现大规模日志的集中管理和可视化,为微服务系统的运维和优化提供强有力的数据支持。