日志链路是一条数据管道:应用产生事件,采集端读取,传输层削峰,存储层建立索引,查询端再按条件检索。任何一段都可能限流或中断。设计重点不是“能看到日志”,而是在业务高峰与局部故障下,日志不反向阻塞业务,并能说明丢失、重复与延迟的边界。
两种 Agent 采集模式
读文件 tail 模式由节点 Agent 监听日志文件,记录文件标识和读取偏移。它适合传统进程、需要本地落盘审计的场景,也便于应用与采集器解耦。难点在于轮转、截断、符号链接、容器短生命周期和磁盘占满。仅按文件名保存偏移会在轮转后读错对象,应同时识别文件系统标识,并处理“旧文件已重命名但仍有未读内容”。
应用写 stdout/stderr 是容器环境的常用方式。应用无需知道后端地址,容器运行时把输出写入节点日志,Agent 再统一采集并补充 Pod、命名空间和容器标签。这里的“直推 stdout”并不代表同步发送到远端;stdout 仍需经过运行时与节点采集链路。若日志产生速度长期超过节点写盘和采集能力,容器日志同样可能占满磁盘。
缓冲、背压与投递语义
采集端到传输层之间需要内存队列吸收短暂抖动,磁盘队列覆盖较长中断。内存缓冲快但进程退出即丢失,磁盘缓冲更耐故障,却要设置容量、刷盘与淘汰策略。队列达到上限时必须明确选择:丢弃低等级日志、采样、暂停读取文件,或把事件转移到隔离区,不能让行为取决于内存耗尽。
业务写日志不应同步阻塞远端传输。若后端变慢,背压应停留在采集链路,不能一路传回业务请求。对本地文件 tail,Agent 可以暂停读取,待后端恢复后按偏移补采;前提是文件在等待期间没有被轮转删除,且磁盘保留足够空间。
常见实现提供至少一次投递:发送后若确认响应丢失,Agent 会重发,于是存储端可能出现重复。可以为事件生成稳定 ID 去重,但全局去重会增加写入成本。多数运行日志接受少量重复,并通过时间、实例、偏移或事件 ID 辅助判断;要求严格一次的场景需要端到端事务语义,成本与复杂度都更高。
buffer:
type: disk
max_size: 8GiB
flush_interval: 1s
on_full: drop_debug_then_oldest
retry:
max_backoff: 30s
jitter: true
配置值只是结构示例,容量应根据峰值写入量、可容忍中断时长和节点磁盘预算计算。
多行日志必须在采集端合并
Java 堆栈、解释器异常和某些数据库错误会跨多行输出。若每行作为独立事件,异常类型、调用栈与请求上下文会分散,查询也难以还原。合并规则通常把“符合时间戳开头的行”识别为新事件,其余缩进行追加到当前事件:
新事件开头:^d{4}-d{2}-d{2}Td{2}:d{2}:d{2}
续行示例:^s+ats|^Caused by:|^s*... d+ more
规则应在靠近源头的 Agent 执行,因为传输后各行可能分区、乱序。必须设置最大行数、最大字节和等待超时;异常输出未结束时,不能无限占用内存。若应用能直接输出单行结构化 JSON,堆栈可作为转义后的字段,能减少多行解析歧义。
多种应用共享一个采集器时,不要用一条宽泛正则覆盖全部格式。可按容器标签、文件路径或日志类型选择解析器,并把解析失败计入指标和隔离样本,避免静默丢字段。
结构化字段与基数控制
推荐保留稳定字段:时间、级别、服务、实例、环境、追踪 ID、错误类型和消息。字段名与类型应有约束,同一字段在部分日志中为数字、部分为字符串,会造成映射冲突。原始消息可保留以便回溯,但不要对每个字段都建立全文索引。
索引高基数字段会显著增加词典与内存开销。用户 ID、请求 ID、订单号虽然值很多,但有精确检索需求时可使用不分词的精确字段,并控制保留期;完整堆栈、请求体和动态标签不适合作为聚合维度。数组、任意 JSON 对象与用户自定义键可能引发字段爆炸,应在采集端白名单化或放入不索引的原始字段。
敏感数据应在应用输出前避免记录,采集端脱敏只能作为补充。密码、令牌和完整身份信息一旦进入本地文件、缓冲和备份,就会在多个副本中扩散。脱敏规则还需测试嵌套 JSON、URL 参数和多行内容,并监控匹配失败。
写入吞吐与查询性能的取舍
更多索引字段、更细分片和即时刷新能改善部分查询,却会增加写放大、段合并和内存消耗。日志写多读少时,可适当延长刷新间隔、批量写入,并围绕时间与稳定业务维度组织索引。分片过小会产生大量元数据,分片过大又增加恢复和迁移时间,需要依据每日数据量和节点容量调整,而不是固定“每天一个索引”。
查询侧应优先用时间范围、环境、服务等低成本条件缩小集合,再做全文或高基数过滤。无限时间范围加模糊匹配容易扫描大量数据,应在界面和接口设置最大窗口、超时与结果上限。用于告警的查询要比人工排障查询更稳定,最好来自结构化字段和预聚合指标。
热、温、冷的保留分层
热层承载近期高频写入与交互查询,使用较快存储;温层保存较少查询的数据,可降低副本或迁移到成本较低的节点;冷层面向审计和偶发回溯,可采用对象存储快照或延迟加载。不同日志类型不应使用统一保留期:调试日志可能只需短期,安全审计与交易相关日志则按内部规则保留。
限制 Agent 的资源影响
节点 Agent 通常能读取大量容器日志,若没有 CPU、内存和磁盘限额,解析风暴可能与业务争抢资源。应设置请求与限制、磁盘缓冲上限、单文件读取速率、批大小和并发连接数。复杂正则可能造成高 CPU,应使用有界规则并用极长输入测试。
Agent 自身也要暴露队列深度、发送失败、丢弃数量、读取延迟、解析失败和偏移落后量。只监控“进程存活”无法发现日志已经积压数小时。资源限制过紧同样会导致持续追不上写入,应根据每节点峰值压测并留出突发余量。
中断后的补采
采集位置应持久化到本地状态文件或可靠存储,更新位置的时机与发送确认相关。先提交偏移再发送,崩溃时会丢日志;发送成功后再提交,崩溃恢复可能重发。多数链路选择后者,以重复换取不轻易丢失。
轮转场景要保留旧文件直到 Agent 读完,使用“复制后截断”时还要识别文件长度突然变小。容器删除、节点重建会让本地日志与位置一同消失,关键事件需要更短的采集延迟、节点磁盘持久化或独立事件通道。
演练可以暂时阻断传输端,观察业务是否受影响、缓冲增长是否符合预期、告警是否触发;恢复后核对积压下降、时间顺序和重复比例。再模拟 Agent 重启与日志轮转,验证位置恢复。能说明链路在中断时如何退化、恢复后如何补采,比单纯看到查询页面有数据更接近可运行的日志系统。
Comments (4)
收藏了,明天组会拿去当反例。
这波属于是知识密度拉满了。
这段我读了三遍,终于明白之前为什么总出问题了。
这波属于是把我心里话说出来了。
Please Sign in to join the discussion.