不打开它,日志就永远留着
一句话总结
Loki 出厂时保留功能是关闭的。不打开,放进去的日志就永远留着;就算打开,删除也是 compactor 按自己的周期执行的异步任务,所以“删了”和“看不见了”之间有时间间隔。
为什么需要它
有个团队的存储账单在三个月里变成了原来的四倍。在仪表板上打开较旧的区间,一年前的日志也出来了。没有人配置过保留,也没有人知道这件事——因为默认值是“不删除”。
也有相反方向的事故。一个团队发现混进了个人信息,提交了删除请求,看到请求刚提交那行日志就从查询里消失了,便报告说“已经删了”。一个月后,存储容量原封不动。默认的删除方式(filter-and-delete)在请求被接收的瞬间就会在查询时过滤掉,但从对象里真正删除,要等取消等待期(默认 24 小时)过后由 compactor 来做。看不见和被删掉是两回事。
工作原理
保留由 compactor 来做。要同时看三件事。
| 设置 | 默认值 | 含义 |
|---|---|---|
compactor.retention_enabled |
false |
关着就什么也不删 |
compactor.compaction_interval |
10m |
运行压缩和保留的周期 |
compactor.retention_delete_delay |
2h |
标记为待删除之后,到真正删除之前等待的时间 |
保留期限本身用 limits_config.retention_period 来定,想按流分别设置的话,就在 retention_stream 列表里写上选择器、优先级和期限。多条规则重叠时,优先级高的获胜。审计日志保留一年、调试日志保留一天——在同一个集群里这样区分,是降低成本最大的旋钮。
删除特定的行与保留是不同的路。给 POST /loki/api/v1/delete 传入选择器和区间,删除请求就会被接收,状态变成 received。在默认的 deletion_mode 即 filter-and-delete 下,从那一刻起查询就会过滤掉这些行,所以查询马上就显示为空。但请求在 delete_request_cancel_period(默认 24 小时)内可以取消,真正从存储的对象中删除,要等过了这段时间之后,由 compactor 来做。
这里常常错位的是期望与保证。“查询里没了”是一个表象,不是“已删除”的证据。如果因合规要求有时限,就要把这个时限与取消等待期、compactor 周期一起算进去,如果是在等容量下降,就更是如此。
容量规划反而很简单。用查询响应附带的 totalBytesProcessed 测出一小时的实际字节数,乘以一天、一个月,再乘以各流的保留期限后相加。压缩率则对照实际存储的数据块文件的大小来校正。从实测而不是估算出发,讨论缩短保留期限时就是在用数字说话。
在现场相遇的样子
最常见的错误是打开了保留却没有启动 compactor。在微服务部署中,compactor 是单独的组件,整个集群里必须恰好只运行一个。设置里写了 retention_enabled: true,却没有 compactor,什么也不会发生,而只看设置文件,会觉得它是开着的。
第二是漏掉流规则的优先级。优先级相同的两条规则作用在同一个流上,哪边获胜就很难预测。每次加规则都明确写上优先级,是更安全的习惯。
第三是“删了,容量却没降”。删除标记与真正删除对象之间有等待时间,对象存储一侧还可能另有一层生命周期策略。
下一项实验要做什么
亲手写出打开保留并按流设置不同期限的设置文件,用 loki -verify-config 确认的不是语法,而是设置本身是否有效。用这份设置在另一个端口上启动第二个 Loki(连 gRPC 端口也要改),用 /config 确认服务器确实带着这些值启动之后,提交删除请求,一并记录它被接收,以及不会马上消失。最后根据实测字节数计算保留预算,做成策略文档。