
纲要微服务日志收集的挑战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的基本工作流程可视化存储与分析采集层日志源日志文件日志文件慢查询日志访问日志推送结构化数据查询与读取开发人员微服务A微服务BMySQLRedisLogstash数据采集与过滤Elasticsearch索引与存储Kibana仪表盘展示分析问题与监控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 与 KibanaElasticsearch与Kibana通常可以先行部署因为二者可以脱离Logstash独立运行并相互配合。下面是一个简单的docker-compose.yml配置示例version:3.8services:elasticsearch:image:elasticsearch:7.17.10container_name:elasticsearchenvironment:-discovery.typesingle-node-ES_JAVA_OPTS-Xms512m -Xmx512mports:-9200:9200volumes:-./elasticsearch/data:/usr/share/elasticsearch/datanetworks:-elkkibana:image:kibana:7.17.10container_name:kibanaports:-5601:5601environment:-ELASTICSEARCH_HOSTShttp://elasticsearch:9200depends_on:-elasticsearchnetworks:-elknetworks:elk:driver:bridge在项目根目录执行docker-compose up -d即可启动。启动过程中Elasticsearch需要一定时间来初始化可以通过访问http://服务器IP:9200验证其状态。当返回JSON格式的节点信息时表示启动成功。Kibana则通过http://服务器IP:5601访问。配置与启动 LogstashLogstash的核心在于其配置文件它定义了数据从哪来input、如何加工filter以及送往哪里output。典型的logstash.conf结构如下input { # 定义数据源 } filter { # 定义数据处理逻辑 } output { # 定义数据输出目标 }单一日志采集MySQL 慢查询日志首先准备一份MySQL慢查询日志mysql-slow.log日志内容示例# Time: 2026-07-09T10:00:00.000000Z # UserHost: root[root] localhost [] # Query_time: 12.345678 Lock_time: 0.000123 Rows_sent: 1 Rows_examined: 100000 SET timestamp1752487200; 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# UserHost: %{USER:user}\[%{USER:host}\] %{HOSTNAME:client_host} \[\]\s# Query_time: %{NUMBER:query_time:float}\sLock_time: %{NUMBER:lock_time:float}\sRows_sent: %{NUMBER:rows_sent:int}\sRows_examined: %{NUMBER:rows_examined:int}\sSET 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 } } }配置说明inputfile插件读取指定路径的日志文件start_position beginning表示首次从头读取之后会记录偏移量以支持断点续传multilinecodec 将以# Time:开头的行作为新日志的起始之前的内容合并到上一条日志。filtergrok插件使用预定义和自定义正则表达式将非结构化日志解析为字段如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:1000Elasticsearch容器内运行用户 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管道设计使其能够轻松应对多种日志格式的采集与处理需求。在实际项目中只需根据业务需要扩展配置即可实现大规模日志的集中管理和可视化为微服务系统的运维和优化提供强有力的数据支持。