背压、缓冲区和日志 Sidecar
Source: Dev.to
(未提供要翻译的正文内容。如果您把需要翻译的文本粘贴在这里,我可以为您将其翻译成简体中文。)
9 PM – 一切的起点崩溃
我正随意地在 YouTube 上浏览时,Slack 的一条通知打破了寂静:我们的日志 sidecar 已崩溃 – 退出码 137。
乍一看,这似乎是一个简单的背压问题。 “增大缓冲区,或许调一下限制,然后重新部署。”
事实并非如此。
这次崩溃把我带入了 Fluent Bit 的块生命周期、文件系统缓冲,以及一个认识:即使是看似“简单”的日志 sidecar,也会表现得像一个小型分布式系统——伴随而来的全部权衡。
在本文中,我想分享这段旅程中的经验和教训。
我们的设置
- Fluent Bit 作为 sidecar 与每个应用容器一起运行。
- 它的职责很简单:收集来自应用程序的日志,进行处理,并将其转发到外部日志平台。
为什么 Fluent Bit 会 OOM
大多数 OOM 情况都归结为 管道内部的不平衡:
| 原因 | 影响 |
|---|---|
| 输出慢 – 下游系统滞后,而输入持续摄取日志 | 反压累积 → 内存使用上升 |
| 过滤或处理负载重 – 过滤器暂时增加内存占用 | 同上 |
| 摄取无限制 vs 缓冲区限制 – 日志量超过配置的内存限制 | Sidecar 成为瓶颈 |
可见性问题
关于容器突发崩溃的棘手之处在于缺乏可见性。当 sidecar 被杀死时,我们失去了调试所需的关键信号。我们的容器级内存图表看起来很平稳,这让崩溃更加令人困惑。
后来我们意识到,自己并没有 实时 观察内存。
我们最终看到峰值的方式
- 启用了 Memory Input Plugin。
- 通过 Fluent Bit 日志检查内部指标。
就在这时我们终于发现——出现了外部监控看不到的突发内存峰值。
实验时间线
第一次迭代 – “限制内存能解决吗?”
# Example: cap memory per input
Mem_Buf_Limit 5M
- 我们的预期: 限制内存 → 防止 OOM。
- 实际情况:
- 当达到限制时,输入会被暂停。
- 应用程序没有暂停;它仍然持续输出日志。
- 由于我们使用的是forward 输入插件(没有上游持久化),输入被暂停意味着日志丢失。
结果:内存压力得到控制,但可靠性受到了影响。
第二次迭代 – “磁盘缓冲能拯救我们吗?”
# Enable filesystem buffering
storage.type filesystem
- 目标:将压力从 RAM 转移到磁盘,同时保持持久性。
- 结果:sidecar 仍然因 OOM 错误崩溃。
仅靠磁盘缓冲不足以解决问题。
第三次迭代 – “内存还流向哪里?”
我们意识到 输入并不是唯一的 RAM 消耗者——过滤器和输出同样会占用内存。
| 组件 | 内存影响 |
|---|---|
| 过滤器 / 解析器(例如 JSON、Multiline) | 暂时保存记录;在我们的案例中,JSON 解析器是主要的内存消耗者。 |
| 输出 | 可能进行压缩、重试或从磁盘重新加载块。即使使用文件系统缓冲,块在刷新前也必须重新加载到内存中。 |
我们尝试的措施
- 增加容器的 CPU 与内存——显而易见,但违背了“轻量 sidecar”的目标。
- 将部分解析工作下移至下游——降低了解析器的内存压力。
- 调整输出的 backlog 限制——限制一次性加载到 RAM 的块数量。
系统保持稳定……直到下一次崩溃。
新症状 – 退出码 139(段错误)
[2019/01/09 17:06:01] [error] [plugins/in_forward/forward_fs.c:218 errno=28] No space left on device
[2019/01/09 17:06:01] [error] [in_forward] could not register file into fs_events
容器以 139 退出——出现段错误。
日志显示 errno=28 → “设备上没有剩余空间”。
日志 sidecar 如何耗尽磁盘
- ECS Fargate 为每个任务提供 20 GB 的临时存储——看似足够用于缓冲。
- 将 输入摄取指标 与 输出刷新指标 进行对比,出现了明显的模式:摄取速率 ≫ 刷新速率。
实际发生的情况
- 内存缓冲区被填满。
- 数据块溢写到磁盘。
- 输出从磁盘加载块并尝试刷新。
- 突然出现摄取峰值,而刷新速率保持不变(或受限)。
- 磁盘使用量增长速度超过了排空速度 → 磁盘填满 →
ENOSPC→ 段错误。
只要这种失衡持续足够长的时间,磁盘填满不仅是可能的——而且是必然的。
限流与缓解策略
| 层级 | 操作 |
|---|---|
| Application | - 抽样 - 去重 - 强制执行严格的生产日志级别 |
| Fluent Bit | - 限制每个输出的磁盘使用量 - 达到限制时丢弃最旧的块 - 应用 throttle filter 进行突发控制 |
| Operations | - 当摄取持续超过处理能力时发出警报 - 增加临时存储(短期缓冲,非永久性解决方案) |
要点
- 内存压力并非唯一问题——磁盘耗尽也可能在相同的不平衡下出现。
- 日志 sidecar 实际上是一个 小型分布式系统;必须将其管道(输入 → 过滤 → 输出)整体对待。
- 实时可观测性(内存、磁盘、摄取/刷新速率)对于在失衡导致容器崩溃前捕获问题至关重要。
- 调整 单一参数(例如
Mem_Buf_Limit)而不考虑下游影响可能导致数据丢失或新的故障。
通过对三个实验的迭代、暴露隐藏的指标,最终加入适当的速率限制和磁盘使用保护,我们将一个不稳定、易崩溃的 sidecar 转变为日志管道中可靠的组件。
观察
- 物理学。
- 当你生成数据的速度超过了移动它的速度时,压力会累积。
- 在我们的案例中——它通过磁盘耗尽而泄漏。
- 日志是基础设施。它需要防护措施。
- 如果你不为突发情况设计,突发情况就会决定你的故障。
- 好奇你会如何不同地处理它。