FEATURED · 精选文章

ELK日志系统实战:从需求拆解到全链路追踪与监控预警

发布时间 / 2026/9/8 17:03:01
来源 / 创域科博编辑部
栏目 / 资讯中心
ELK日志系统实战:从需求拆解到全链路追踪与监控预警 1. 日志系统搭建前的需求拆解与整体思路先说个背景。我做代购系统后端也有几年了一开始根本没把日志当回事就是用print和框架自带的logger随便打打出问题了直接上服务器tail -f看。等到系统上线跑了一段时间用户量上来渠道变多才发现这套土办法彻底撑不住了。代购这个业务有个特点就是链路特别长。用户下单之后要经过采购员接单、海外买手采购、国际物流、清关、国内转运、签收这么一大串环节。每个环节都分布在不同的服务里甚至不同的服务器上。订单状态出问题的时候最痛苦的排查方式就是一台一台服务器翻日志一条一条对时间戳。有一次排查一个订单卡在“清关中”两天没动的问题我愣是手工翻了四台机器的日志最后发现是某个回调服务凌晨三点因为内存溢出自动重启了请求丢了。也就是从那一次之后我下定决心要把日志系统正经做起来。做日志系统之前我先把自己想要的几个核心能力理清楚了这里分享下我的需求拆解思路全链路追踪一个订单从下单到签收所有关键状态变更都要能串起来不能散落在各个服务的日志文件里找不着。异常主动发现系统报错、接口超时、外部渠道回调失败这些事最好能在监控页面直接看到而不是等用户投诉了才发现。业务对账辅助代购系统经常涉及多级分销、渠道返佣、采购对账日志里得有足够详细的业务字段方便出问题的时候往前追溯。检索必须快日志量上去之后grep已经没法用了。我要支持按订单号、用户ID、时间段这些维度秒级查询。基于以上需求市面上的方案其实就那么几个。要么是用云厂商自带的日志服务要么自建 ELK 这套经典组合要么用 Loki 这种轻量方案。我当时权衡了一下因为服务器已经有不少了而且数据敏感度比较高不想把日志传到云上所以自建是更合适的选择。在 ELK 和 Loki 之间我选了 ELK 而不是 Loki原因也很简单对比项ELKLoki索引能力Elasticsearch 全文检索能力强支持复杂聚合基于标签索引全文检索能力弱一些生态成熟度组件多、文档多、踩坑资料多相对年轻部分功能还在完善资源占用ES 比较吃内存整体更轻量适用场景业务日志需要深度分析、聚合统计纯日志排查、轻量监控为主代购系统的日志不只是拿来“看”的我还要做错误率统计、接口耗时分析、用户操作行为分析这些事ES 的聚合能力刚好能覆盖。所以虽然 ELK 部署更重我最后选了它。整体架构也定下来了简单清晰应用日志 - Filebeat采集- Logstash清洗/解析- Elasticsearch存储/索引- Kibana展示/分析这套架构里有个细节为什么采集端用 Filebeat 不用 Logstash因为 Logstash 是 Java 写的每台业务服务器上部署一个内存开销太大动不动就占掉 1G 以上。Filebeat 是 Go 写的资源占用小一个量级跑在业务服务器上非常轻量内存占用大概在 20MB 到 50MB 之间对业务的影响可以忽略。从拆解需求到确认方案我认为这是整个项目里最关键的一个阶段。先想清楚要解决什么问题再去选工具思路才不会跑偏。2. 日志规范与字段设计一切分析功能的基础日志分析做得好不好七分靠规范三分靠工具。这句话是我的切身感受。很多团队搭好了 ELK结果发现日志格式乱七八糟统计的时候根本没法用然后回过头来改业务代码里的日志输出这个成本就太大了。2.1 日志分级与格式统一我梳理了代购系统里需要的日志级别参照的是大厂常用的分级规范简单聊聊我的使用习惯。ERROR系统跑不通了、外部接口返回明确失败、数据一致性出问题。这种日志必须打而且要带完整的上下文比如订单号、用户ID、报错堆栈。WARN不该发生但没影响核心流程的事。比如某个商品库存查询超时走了降级逻辑、某个渠道回调重复通知了三次。这类日志的价值在于发现隐患。INFO关键业务节点。用户下单成功、支付回调接收到、采购单创建、物流状态更新。这类日志不要打太多细节否则量太大而且没意义。DEBUG开发排查用生产环境一般不开启。有了分级还不够格式也必须统一。我的做法是定义了一个日志输出的标准模板所有服务的日志都按这个模板打时间戳 | 日志级别 | 服务名 | 追踪ID | 业务类型 | 业务ID | 用户ID | 具体信息举例说明2024-11-20 14:23:45.678 | INFO | order-service | 9f8e7d6c5b4a | order | 20241120142345001 | 10086 | order created, skuSKU12345, qty2, amount188.00这个格式看起来简单实际操作时想让每个开发都严格照做其实不容易。我的经验是没靠自觉而是统一封装了一个日志工具包。团队里所有人打日志都用这个工具包提供的方法比如LogUtil.info(业务类型, 业务ID, 用户ID, 描述信息)底层统一拼格式。这样就算有人偷懒不传用户ID模板也不会乱。2.2 全链路追踪ID的传递日志分析里最深的一个坑就是没有链路追踪ID。单看一条日志觉得没问题但想把一个请求经过的所有服务日志串起来就发现根本串不动。代购系统的调用链相当复杂用户下单这个动作前端会调网关网关调订单服务订单服务要调库存服务还要发消息给采购系统采购系统又要回调。链路长节点多没有统一的追踪ID排查一次问题等于大海捞针。我采用的方案是自己封装了一个轻量级的链路追踪组件基于SLF4J的MDC机制来实现。核心逻辑其实不难请求进入网关时生成一个全局唯一的traceId用 UUID 就行。通过 HTTP 头向下游传递约定好的 Header 名是X-Trace-Id。服务收到请求后从 Header 里取traceId放到日志框架的 MDC 里。日志输出模板里自动带上 MDC 中的traceId。如果是走消息队列的场景比如订单服务发消息给采购服务那traceId就塞进消息头里消费方拿到消息后先从消息头取traceId再设置到 MDC 里。这样一来不管是同步调用还是异步消息整条链路的所有日志都带着同一个traceId。在 Kibana 里按traceId一搜这个订单从创建到状态流转再到异常堆栈全部日志按时间线排得整整齐齐排查效率直接翻倍。这里有个小细节值得提醒HTTP 头里的traceId一定要过滤掉用户传入的值不能在入口处直接信任客户端传上来的 Header 直接拿来用而是生成新的或者当不存在时再生成。不然有人恶意传一个超长的字符串会影响 ES 索引效率也不安全。2.3 关键业务埋点日志不只是给排障用的日志如果只用来排障那就浪费了一大半价值。我还在关键业务节点上做了埋点把日志直接变成数据源。举几个实际例子下单接口耗时在所有 Controller 入口和出口打 INFO 日志记录耗时拿来做接口性能分析。外部渠道回调监控代购系统对接了不少海外支付渠道每次回调都记录渠道名称、回调内容、处理结果、耗时。哪个渠道最近回调成功率下降了一查日志就明白。采购员抢单行为记录采购员ID、抢单时间、订单金额这个数据在分析采购员活跃度和接单策略时非常有用。物流状态推送清关、起飞、落地、派送、签收这些节点都记录后面做时效分析全靠它。这些设计在做的时候多花不了多少时间但后面受益很大。不过提醒一句埋点要克制一条日志不是打得越多越好每一条都要想清楚“将来谁会用它解决什么问题”。只为了自己调试方便打的日志该删就得删留着只会增加存储成本。3. 基于Filebeat Logstash Elasticsearch Kibana的落地实践架构定好了日志规范也统一了接下来就是最硬核的部署和实施阶段。我用的这套组合是非常经典的 ELK 技术栈网上资料虽然多但真正能拿来就用、少走弯路的细节还是得自己踩过坑才知道。3.1 Docker Compose快速搭建ELK环境我们大部分业务服务已经容器化部署了所以 ELK 这套也直接用 Docker Compose 跑维护起来省心很多。我把 compose 文件放出来基本就是可用的版本。version: 3 services: elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:7.17.9 container_name: es-node environment: - cluster.namees-docker-cluster - node.namees-node1 - discovery.typesingle-node - bootstrap.memory_locktrue - ES_JAVA_OPTS-Xms4g -Xmx4g - TZAsia/Shanghai ulimits: memlock: soft: -1 hard: -1 volumes: - /data/es-data:/usr/share/elasticsearch/data ports: - 9200:9200 networks: - elk-net - app-net restart: always logstash: image: docker.elastic.co/logstash/logstash:7.17.9 container_name: logstash environment: - TZAsia/Shanghai - LS_JAVA_OPTS-Xms2g -Xmx2g volumes: - /data/logstash/pipeline/:/usr/share/logstash/pipeline/ - /data/logstash/patterns/:/usr/share/logstash/patterns/ ports: - 5044:5044 depends_on: - elasticsearch networks: - elk-net - app-net restart: always kibana: image: docker.elastic.co/kibana/kibana:7.17.9 container_name: kibana environment: - ELASTICSEARCH_HOSTShttp://elasticsearch:9200 - TZAsia/Shanghai - I18N_LOCALEzh-CN ports: - 5601:5601 depends_on: - elasticsearch networks: - elk-net restart: always networks: elk-net: driver: bridge app-net: external: true部署的时候有两个细节值得展开说说。第一个是内存设置。ES的ES_JAVA_OPTS给的4g不是随便写的。ES 官方建议是把堆内存设置为物理内存的一半但是不能超过 31GB超过了会有压缩指针失效的问题。如果服务器总共 16G 内存分配 4G 给 ES、2G 给 Logstash 是合理的剩下的要给 Filebeat、Kibana 和操作系统缓存留余地。ES 的bootstrap.memory_locktrue是为了锁定内存防止发生 swap 导致性能剧烈抖动这一步强烈建议开启。第二个是网络规划。我把 ELK 组件放一个独立网段elk-net业务服务在app-net网段两边通过external: true挂载同一个业务网络。这样 Filebeat 在业务容器里可以直接用logstash:5044这个服务名连上 Logstash不需要暴露公网端口安全很多。3.2 模板化Logstash解析配置多服务日志一招通吃Logstash 的 pipeline 配置是整个链路里最值得花心思的地方。如果每个服务的日志格式不一样就要写一堆不同的解析规则维护成本会爆炸。我前面提到“日志格式统一”的价值就在这里体现出来了。我的 Logstash pipeline 是按服务名做分发每个服务一套 grok 正则但配置结构高度模板化。看一眼其中一个配置就明白套路了input { beats { port 5044 } } filter { if [service] order-service { grok { match { message %{TIMESTAMP_ISO8601:log_time}\|%{LOGLEVEL:level}\|order-service\|%{UUID:trace_id}\|order\|%{DATA:business_id}\|%{NUMBER:user_id}\|%{GREEDYDATA:log_content} } } date { match [log_time, yyyy-MM-dd HH:mm:ss.SSS] target timestamp } } else if [service] purchase-service { // 类似的正则规则 } mutate { remove_field [message, path, host, beat] } } output { elasticsearch { hosts [elasticsearch:9200] index app-logs-%{service}-%{YYYY.MM.dd} template /usr/share/logstash/templates/logstash.json template_name app-logs template_overwrite true } }这套配置里有三个关键设计想跟大家分享。第一是字段精简。我在mutate里把message、path、host这些原始字段全部删掉了。减少存储压力是次要的更主要的原因是 ES 索引字段越简洁聚合查询的时候越不容易踩字段映射冲突的坑。第二是索引按天滚动。索引名带上了日期配合 ES 的索引生命周期管理策略30 天前的索引可以自动关闭甚至删除这样就能控制好磁盘占用。第三是自定义模板。日志里如果带纯数字的 JSON 字段ES 有可能发生类型映射冲突。比如某个字段这次是数字下次是字符串就会导致索引 mapping 报错。提前在模板里把字段类型固定下来就从根上避免了这个痛苦。3.3 服务端Filebeat配置与常见翻车点业务服务器上跑 Filebeat我一开始踩了不少坑。直接把我调好的配置放出来filebeat.inputs: - type: container enabled: true paths: - /var/lib/docker/containers/*/*.log json.keys_under_root: true json.add_error_key: true filebeat.config.modules: path: ${path.config}/modules.d/*.yml reload.enabled: true processors: - add_docker_metadata: host: unix:///var/run/docker.sock - decode_json_fields: fields: [message] target: json - drop_fields: fields: [container.image.name, stream] output.logstash: hosts: [logstash:5044] loadbalance: true logging.level: warning使用 Docker 容器日志有个特别关键的问题容器输出的 JSON 日志和代码里设置的多行堆栈是对不上的。比如 Java 应用打一个异常堆栈原本是一条日志里有很多行但 Docker 默认会把每一行都当成一个独立的日志消息存下来。Filebeat 采集的时候如果不知道要合并一条完整堆栈就会被拆成五六条在 Kibana 里看到的报错就是支离破碎的没法完整分析异常原因。解决办法是使用multiline多行配置。Filebeat 里提供了multiline.type和multiline.pattern配置项来合并多行日志filebeat.inputs: - type: container enabled: true paths: - /var/lib/docker/containers/*/*.log json.keys_under_root: true multiline.type: pattern multiline.pattern: ^\d{4}-\d{2}-\d{2} multiline.negate: true multiline.match: after这个配置的意图是如果一行的开头不是以2024-11-20这种日期格式开头就说明它是上一条日志的延续应该合并到上一条里去。multiline.negate: true表示“不匹配这个规则的都视为延续行”multiline.match: after表示“把延续行拼接到前一条后面”。使用 Java 的 logback 日志框架时如果配置了pattern输出时间戳格式不一致需要你把正则改成和实际格式匹配的。我见过有些同事卡在这个环节一晚上就是因为正则和日志开头的时间格式对不上合并始终不生效白白浪费好几个小时。另外再分享一个 Filebeat 的细节。add_docker_metadata这个 processor 会从 Docker 读取容器信息把服务的容器名、镜像名都加到日志字段里。这个很有用因为不同的环境可能跑同一个服务名区分环境和版本都得靠容器的元数据。但要注意给 Filebeat 挂载/var/run/docker.sock不然它取不到 Docker 的信息这个 processor 就静默失效了。4. Elasticsearch索引生命周期与性能调优实践ELK 部署完成之后日志不断往 ES 里灌入很快就会遇到存储和性能的问题。代购系统到了大促节点采购单和订单量能翻几倍日志写入量更是水涨船高。如果不对 ES 做生命周期管理和调优策略集群很容易变成定时炸弹。4.1 索引生命周期管理磁盘不是无限大的日志这种数据有个特点越新的越值钱越老的价值越低。一周前的日志偶尔查查还能接受一个多月前的日志基本就没什么人会去碰了。既然这样没必要让所有索引都保持同样的副本数和存储状态。我配置的是经典的 30 天生命周期策略阶段触发条件动作Hot写入中默认配置索引持续写入Warm7天合并分段下调副本数为0Delete30天删除索引释放磁盘空间配置这个策略用 ES 的 Index Lifecycle Management 来做一段简单配置是这样的PUT _ilm/policy/log-policy { policy: { phases: { hot: { min_age: 0ms, actions: { rollover: { max_size: 30gb, max_age: 1d } } }, warm: { min_age: 7d, actions: { forcemerge: { max_num_segments: 1 } } }, delete: { min_age: 30d, actions: { delete: {} } } } } }这份策略里我用了rollover配置。意思是当索引超过 30GB 或者超过 1 天还没滚动就会自动创建新索引。好处有两个单个索引的碎片数量不会失控被删掉的历史索引数据量也适中。每天大概产生几 GB 日志的时候磁盘规划很简单500G 基本可以稳定跑两个月。但如果是日志量特别大的业务建议升级到冷热架构或者对象存储归档成本会更优。4.2 索引mapping优化预防字段映射冲突日志场景里最常见的 mapping 坑就是 Es 动态映射把字段猜错了类型。我之前踩过一个特别典型的坑订单号的 JSON 里有个字段叫status有时候是字符串SUCCESS有时候是数字1ES 动态映射先见到字符串就把它设为text之后来了数字字段就拒绝写入整个 logstash 管道报错后面日志全都堵住了。这个问题的标准解决方案是在索引模板里把字段类型全部锁死。对于不确定的数据直接放弃自动映射全部设置为keyword类型最保险PUT _index_template/app-logs-template { index_patterns: [app-logs-*], template: { settings: { number_of_shards: 3, number_of_replicas: 1, index.lifecycle.name: log-policy }, mappings: { dynamic: strict, properties: { timestamp: { type: date }, service: { type: keyword }, level: { type: keyword }, trace_id: { type: keyword }, business_id: { type: keyword }, user_id: { type: keyword }, log_content: { type: text, analyzer: ik_max_word } } } } }这种设置下如果来了一个模板里没定义的新字段写入会直接报错而不是自动创建。有些人会觉得太死板了不灵活但我觉得日志场景里灵活反而是灾难。新增字段时模板加一条配置就行了几分钟的事总比线上写入被中断要好得多。需要特别说明一下ik_max_word这个分词器是为中文内容准备的需要你自己给 ES 装 IK 插件。日志里的中文内容很多时候是提示信息比如“订单创建失败库存不足”我们想按“库存不足”搜到它就必须有中文分词能力。如果不做这一步中文搜索体验会非常差搜一个完整句子可能匹配不到搜单个字又可能匹配出一堆无关结果。4.3 Filebeat到Kafka的缓冲架构升级可选如果日志量只有每天几十 GBLogstash 直接消费 Filebeat 的数据顶多偶尔有点延迟完全够用了。但如果到了大促节点日志量瞬间飙升到每秒几千条Logstash 稍有不慎就会成为瓶颈然后 Filebeat 的积压队列开始涨最后丢日志。这时候就要在 Filebeat 和 Logstash 之间加一个 Kafka 做消息缓冲。日志进 KafkaLogstash 以自己吃掉的速度去消费谁慢谁调整谁挂了也不影响上游。我实测下来的体感是Kafka 的引入让日志链路的稳定性上升了一个大台阶。代价是运维复杂度提高了Kafka 本身也需要部署和监控。所以这个方案适合日志量确实大、或者对日志不丢失有强要求的场景如果量不大完全没必要增加维护负担。5. 日志驱动的业务价值挖掘从排障到监控预警日志系统真正跑起来之后价值很快就不只停留在“出问题能查到日志”这个层面了。基于 ES 聚合出来的数据做业务分析和监控才是这个系统最香的部分。5.1 基于Kibana做实时业务监控面板Kibana 的 Dashboard 功能非常实用。我建了几个监控面板跟大家分享下思路。第一个是支付网关异常监控。这张面板按照支付渠道分组展示回调失败数量、平均回调延迟、最近 30 分钟失败趋势。每天只要扫一眼面板就能知道早上那批“渠道回调 Timeout”是不是上升了。构建方法是找到servicegateway AND levelERROR的索引做terms聚合按channel分组。把结果可视化成一个柱状图右上角再叠一个折线图看时间趋势。第二个是订单链路耗时分析。这里用关键的埋点数据找出每笔订单从创建到支付成功再到采购接单每个环节消耗了多久。在 RabbitMQ 消费线程池拥堵的时候这个图看得特别明显从“支付成功”到“采购接单”之间的时间差突然拉大一查就能定位到是 MQ 消费出了问题还是采购端应用崩了。第三个是接口 TOP 慢请求列表。用percentiles聚合查出耗时超过 95 分位的接口请求每天列出 Top 20。经常能看到一些平时不太注意的接口因为数据库 SQL 没加索引单次耗时从 50ms 涨到 2 秒这种问题如果没有日志分析靠用户投诉才能发现那就晚了。5.2 MySQL日志分析与慢SQL发现代购系统后端重度依赖 MySQL慢查询基本属于家常便饭。ELK 里我只收集了应用日志MySQL 的慢日志和错误日志也是分析的重点。我的做法是在装了 MySQL 的服务器上通过 Filebeat 采集 MySQL 慢查询日志经过 Logstash 解析后写入独立的索引。MySQL 慢查询日志每行格式长这样就够 Logstash 解析了# Time: 2024-11-20T14:23:45.678901Z # UserHost: order_rw[order_rw] [10.0.0.12] Id: 882313 # Query_time: 3.210000 Lock_time: 0.000213 Rows_sent: 1 Rows_examined: 89032 SET timestamp1732098225; SELECT * FROM order_item WHERE user_id 10086 AND order_id 20241120142345001 AND status 1 ORDER BY created_at DESC;Logstash 里用 grok 正则把Query_time、Rows_examined、SQL 文本拆出来然后写入 ES 专门的mysql-slowlog-*索引。之后我在 Kibana 上做了一张“慢 SQL 排行榜”按Query_time降序排列一眼就能看出哪些 SQL 需要优化。这套机制上线后的第一个星期就抓到了一个非常典型的低级错误。采购员批量创建采购单时执行的一个 UPDATE 语句因为联合索引的字段顺序建反了导致全表扫描单次执行耗时高达 800 毫秒。在慢日志里它的出现频率极高占掉了前十名里的五个位置。后来调整了索引字段顺序耗时直接降到了 30 毫秒以下采购员那边反馈操作明显跟手了很多。MySQL 错误日志也值得收一份。主从同步断掉、连接数打满、死锁这类严重问题都会先出现在错误日志里如果被动等监控报警往往已经影响用户了主动盯着错误日志的变化趋势能提早发现苗头。5.3 从“玄机”到确定性玄学问题这样变透明我琢磨着热搜词里“mysql日志分析 玄机”这个表述挺有意思。确实很多时候日志分析做得不到位系统问题就变成了玄学某个订单数据丢失了谁都不知道怎么回事某个接口偶尔超时重启就好过了三天又犯。有一个最典型的例子让我印象很深。上线了日志系统之后有个售后客服反复反馈“偶尔有订单显示已签收但用户实际没收到货”。因为物流状态回调是外部合作的物流公司推送的没日志的时候我们只能反馈“查一下物流官网”完全无从下手。后来在日志里加了物流签收回调的完整记录问题很快就水落石出。有一条签收记录是在凌晨 2 点 47 分推送的而实际上快递员扫描签收的时间也是凌晨 2 点 47 分。但通过分析同一批签收记录发现了一个规律部分异常单都是相同网点同一批次推过来的而且推出时间与真正签收时间相差接近 20 个小时。最后的结论是物流公司的某个网点扫描枪的时间设置错了导致签收时间严重超前。虽然根本原因在外部但我们的日志分析为这个判断提供了确凿的证据链如果没有完整日志这就是一个让人抓狂的“灵异事件”。日志的价值就在这里把玄学问题变成确定性结论把“我觉得好像是”变成“日志里明确记录了”。6. 实战中的血泪总结与操作技巧这套系统从搭建到现在稳定运行中间踩了不少坑积累了不少心得。挑几个最值得说的放到这里希望兄弟们少走点弯路。6.1 排查链路故障的黄金指令与高频问题速查日志系统也会出故障关键是出了故障怎么快速定位。我整理了一些高频问题按“症状-原因-解法”列个表方便自己人快速排查症状常见原因排查命令/思路Kibana 搜不到新日志Filebeat 没起来或连不上 Logstash先看 Filebeat 日志journalctl -u filebeat -fLogstash 日志大量报错grok 正则没匹配上打开 Logstash 的--debug看是否是_grokparsefailure标签ES 写入拒绝磁盘水位线满了检查GET _cluster/allocation/explain再清理旧索引时区差了 8 小时默认用了 UTC 时区ES 容器环境变量增加TZAsia/ShanghaiLogstash date 插件匹配后也要转本地时区索引字段变成 float 导致精度丢失ES 动态映射猜测错误修改索引 template 的 mapping 字段为long/keyword并重建索引6.2 磁盘写满的未雨绸缪日志服务本身比业务还吃磁盘这是很多人低估的坑。ELK 组件全家桶跑起来ES 数据、Logstash 队列、Kibana 缓存一天下来几个 GB 非常正常。如果忘了做索引清理策略磁盘写满是迟早的事而磁盘写满后 ES 会变成只读所有业务日志都写不进去整个监控体系直接瘫痪。除了前边说的 ILM 策略之外我还会定时用 curl 写上一条 cron 清理任务双保险# 每天凌晨2点执行删除7天前的旧索引 0 2 * * * curl -X DELETE http://localhost:9200/app-logs-$(date -d 7 days ago %Y.%m.%d) /dev/null 21同时要监控 ES 和 Logstash 所在节点的磁盘使用率建议超过 75% 就告警85% 就要强制清理了。我在 Prometheus 里配过这类节点的磁盘监控这块我建议你也有意识地给日志服务器做一个单独的磁盘告警而不是和普通业务机混在一起设 90% 告警。6.3 Filebeat加载均衡与并发上的一些配置细节Filebeat 连接多个 Logstash 节点默认会轮询负载均衡。但有个细节loadbalance: true打开时Filebeat 会把不同的事件发给不同的 Logstash 实例。这要求所有 Logstash 的配置保持一致否则会出现同一个服务的日志有的被解析了有的没被解析混乱无比。另外一个我踩过比较惨的坑是 Filebeat 的harvester_buffer_size。默认值是 16384 字节如果某条日志非常大比如一个异常堆栈带了很长的 SQL 或者 HTTP body超过了缓冲大小就会被截断。这一类问题不好查因为日志看起来格式都对只有最后的内容少了半截。有需要的话把它调到 1MBfilebeat.inputs: - type: container enabled: true harvester_buffer_size: 10485766.4 日志采集对业务性能的影响到底多大聊一下大家最关心的性能影响问题。在 Filebeat 刚上线时我也担心过它对业务服务器的资源占用实际情况反而很让人放心。Filebeat 在日志量不大时CPU 占用基本可以忽略内存稳定保持在 30MB 上下。Logstash 解析是唯一比较吃资源的组件因为 grok 正则的解析是 CPU 密集操作。但我们在 pipeline 里已经按服务做了 if 分支每次只跑一条匹配规则而不是把正则全部试一遍实际压测时单台 8 核机器跑 Logstash 每秒处理 2 万条日志问题不大。对于容器日志如果 Filebeat 直接把整个容器的 stdout 日志采集走业务容器完全不需要额外做任何事这对性能影响为零。真正要注意的是日志在容器内的落盘方式建议让日志直接打到 stdout 由 Docker 接管还是直接重定向到文件再收集这两种方式在 Docker 环境下性能差异很大我一贯沿用 stdout 方案即可。7. 日志系统的安全与权限控制不可忽视日志里有很多敏感数据可能有用户手机号、订单金额、收货地址、支付流水单号。整个系统使用越深入越意识到权限控制是绝对不能跳过的环节。7.1 日志脱敏处理我这边在日志输出层面就做了脱敏。工具包里定义专门的日志输出方法在拼字符串之前先对手机号、身份证号、真实姓名做脱敏处理。手机号输出138****8000姓名输出张**。虽然在 Logstash 阶段也可以用正则再脱敏一次但源头不输出更安全双保险更安心。7.2 Kibana 多租户与权限隔离不同角色的人应该只能看到自己需要的数据。我给运营看订单业务面板给开发看应用错误日志给财务看对账报表。Kibana 基于 ES 的 RBAC 来做创建几个角色然后绑定索引级权限实测相当方便PUT _security/role/order_log_viewer { cluster: [], indices: [ { names: [app-logs-order-*], privileges: [read, view_index_metadata] } ] }再创建响应用户并绑定角色PUT _security/user/order_ops { password : some-strong-password, roles : [ order_log_viewer ], full_name : Order Ops }这样运营同事登录 Kibana 后只能看到订单服务的索引连其他服务日志的存在都感知不到。这个权限隔离的效果很直接之前有业务方会去日志里扒用户的完整收货信息一旦收紧了权限事故概率基本降为零。8. 几个独家的排查脚本与实用技巧直接能用最后分享几个我在实际运维中天天用的小脚本。ELK 的运维不太适合天天在页面上点来点去很多操作命令行更快更直观。查看各索引大小排行最实用的磁盘管理命令curl -s -X GET http://localhost:9200/_cat/indices?vsstore.size:desc | head -20查看字段映射冲突很多写入报错都能从这里找出原因curl -s -X GET http://localhost:9200/app-logs-*/_mapping/field/status?pretty清理持有大量删除标记的分段磁盘空间明明删了很多文档但没释放时的首选操作curl -s -X POST http://localhost:9200/app-logs-2024.11.01/_forcemerge?max_num_segments1Kibana 里排查慢加载时ES 慢日志的查看命令也很重要。curl -s -X GET http://localhost:9200/app-logs-*/_settings?pretty | grep -A3 indexing如果以前开启了 ES 的 slowlog 但没有正常输出需要在 ES 的 log4j2.properties 里检查一下相关配置这个问题当时也折腾过我不少时间。9. 写在最后的实操建议日志系统从零搭到现在给我最深的体验是它不是一个“一次性搭建完就结束”的项目它是会持续演进的基础设施。从最初每天几个 G 日志到后面大促单日接近 100G架构从简单 Filebeat Logstash 到中间加 Kafka再到 ILM 策略、索引模板的多次调整一直是边跑边优化的过程。如果你是刚开始搞这套我的建议是从最简单的架构起步不要一上来就上 Kafka 加一堆组件。先统一日志格式把链路追踪 ID 带上用 Filebeat Logstash ES Kibana 跑起来感受一下日志分析和排查问题的工作方式变化等你真正体验到了每天点几个按钮就能完成以前两小时排查工作的感觉自然会理解接下来该优化什么、扩展什么。最后分享一个我一直保留的排查习惯遇到棘手的问题先不加猜测先去 Kibana 把日志拉出来看完整看一遍时间线再下结论。日志不会骗人就看你想不想得到所有应该被记录下来的东西。日志系统不只是排查工具更是让业务变得透明、让问题不再玄学的底气。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻