Colibrì 分层推理里磁盘只当第二层 / 读写次数比容量更值得先盯

文章导读
把磁盘放在推理分层的第二层,容量只回答“内容能不能放下”,读写次数回答“每个请求要为它多等多久”。用便宜介质承接不常访问的内容,收益来自热层挡住大部分请求;一旦热层开始频繁把请求打到第二层,磁盘的寻道和随机读延迟就会叠加到首字延迟上。先做一件事:把每个统计窗口里热层命中多少次、冷层被读取多少次、这些读取摊在多少个请求上记成数字,再看首字延迟跟着哪个数字波动。容量扩不扩,等次数和延迟的对照关系出来再
📋 目录
  1. 壹 把每层被读取的次数记成一张表
  2. 贰 对照读写次数与首字延迟找相关性
  3. 叁 把冷层换到更快的介质再测同一批请求
  4. 肆 读写次数降不下来时该动哪里
A A

把磁盘放在推理分层的第二层,容量只回答“内容能不能放下”,读写次数回答“每个请求要为它多等多久”。用便宜介质承接不常访问的内容,收益来自热层挡住大部分请求;一旦热层开始频繁把请求打到第二层,磁盘的寻道和随机读延迟就会叠加到首字延迟上。先做一件事:把每个统计窗口里热层命中多少次、冷层被读取多少次、这些读取摊在多少个请求上记成数字,再看首字延迟跟着哪个数字波动。容量扩不扩,等次数和延迟的对照关系出来再定。

在 Colibrì 这类分层推理里,磁盘只当第二层,容量通常够用就行,先别把精力放在扩容上。固定统计窗口和请求样本,把热层命中与冷层回读分开计数,再和首字延迟并排看:次数涨而延迟平稳就先继续观察,次数涨且首字延迟同步抬高,再把冷层换到更快的介质、用同一批请求复测。每次只改一个变量,换介质和调参数不要同时做,否则对照结果没有意义。

把每层被读取的次数记成一张表

要让读写次数可比,先固定采集口径:统计窗口用“连续 N 个请求”或“固定时间片”二选一,之后所有对照都沿用同一种;请求数量必须一起记,它是分母,没有分母的次数放在不同批次之间比没有意义。并发、上下文长度、批次标记也一并写进记录,否则两次采样差异说不清是参数变了还是负载变了。

记录表建议至少包含下面这些字段,每行一次采样:

字段含义采集方式
window_id统计窗口编号手动或脚本生成,连续递增
req_count窗口内请求数(分母)入口日志计数
hot_hit热层命中次数热层读取日志或计数器
cold_read冷层读取次数冷层目录的读取事件或设备统计
cold_write冷层写入次数(首次落盘)同上,与读取分开记
read_per_req每请求冷层回读次数cold_read / req_count
ttft_p50 / ttft_p95首字延迟分位请求侧计时日志
media / batch冷层介质类型、批次标记挂载信息与人工标注

冷层回读和正常加载要分开。正常加载指某份内容第一次进入第二层后被读上来,属于一次性成本,通常在窗口内只出现一次;回读指同一份内容在同一窗口里被反复读出,往往发生在热层淘汰之后或缓存未命中同一标识时。判断方法有两个:一是按内容标识统计窗口内出现次数,大于 1 的计入回读;二是看事件顺序,写入事件之后紧跟着的第一次读取算加载,之后的重复读取算回读。日志里没有内容标识时,退一步用文件路径或分片名做近似键。

对照读写次数与首字延迟找相关性

把两张数据并排放,最省事的做法是同一张表里左半部分是次数、右半部分是延迟,行按 window_id 对齐,一行一个窗口。这样扫一眼就能看出 read_per_req 抬高的窗口里 ttft_p95 是否同向抬高,还是两条线各自摆动。

  • 次数涨、首字延迟也涨,且延迟抬高的量级和回读次数成比例:瓶颈在回读路径,进入下一节的介质对照。
  • 次数涨、首字延迟平稳:说明介质带宽和读取路径还有余量,回读被流水线摊掉了。这种时候不建议立刻调参,先把窗口拉长再采几批,确认不是样本太少的假象。
  • 次数平稳、首字延迟抖动:问题多半不在分层,去查热层是否有大块换入换出、并发是否突增、单请求上下文是否变长。

判断时注意样本量:一个窗口只有十几个请求时,单次慢请求就能把 p95 拉上去,这种数字不要当成结论。建议连续采若干窗口、覆盖至少一次负载高峰再下判断。

把冷层换到更快的介质再测同一批请求

这一步回答的是“慢在次数还是慢在介质”。如果同一批请求、同样窗口下回读次数没有变化,只把冷层换到更快的盘之后首字延迟明显下来了,那是介质速度问题;如果换了盘延迟几乎不动,说明成本主要是访问次数本身,要回头去降次数。

操作顺序可以按下面走,字段名按你环境里的实际键名替换:

  1. 把当前配置里的冷层目录指向新介质的挂载点,改完先做配置回显或语法检查再重启。
  2. 确认目录权限和属主与运行用户一致,挂载点是本地盘而不是网络盘。
  3. 启动后验证是否生效:查看运行日志里打印的实际冷层路径,用 mount | grep <冷层挂载点> 确认设备,再发一个请求,看新目录下是否出现对应文件。
  4. 从系统侧确认读确实落在新设备上:iostat -x 1 观察对应设备在请求期间的读速率与等待时间。
# 冷层目录配置示例,键名以实际版本为准
storage:
  hot_tier:
    path: /dev/shm/colibri_hot
    max_bytes: 0        # 热层上限,按内存余量设定
  cold_tier:
    path: /mnt/nvme0/colibri_cold   # 换介质只改这一行
    read_only: true
    verify_on_start: true

对照结果按同输入记录:同一批请求、同样并发、同样窗口长度、同样上下文长度,只变介质这一项,其余字段照抄上一节的表。两批结果放同一张表里对比,不要跨天比。

读写次数降不下来时该动哪里

次数压不下来,通常是热层装不下工作集,或者同一批内容被拆得太碎反复进出。三个可调项各自的方向不同,建议一次只动一个:

  • 热层上限:调大能减少淘汰,回读次数通常下降,代价是常驻内存变高,可能挤压推理本身。验证时看 hot_hit 与 read_per_req 是否同向变化,同时盯进程内存峰值。
  • 请求批量:把小请求合并或让相邻请求共享同一段内容,回读次数会被摊薄,但单请求的首字延迟可能变大,内存占用峰值也会抬高。验证时同时看 read_per_req 和 ttft_p50,不能只看其中一个。
  • 上下文长度:缩短输入能直接减少需要加载的分片数量,回读次数下降最直接。验证时按同一批请求跑长短两个版本,比较 cold_read 的绝对值而不是比值。

每次改动保留改动前后的 window_id 和批次标记,用同一张记录表累计。若三项都动过、次数仍然随请求量线性上涨,说明工作集本身就超过热层容量,这时候再考虑扩容或换介质才有依据;在没有次数数据支撑前扩容,往往只是把问题往后推。