rag 与 review 是 backend 之外的两个独立小弟:各一个进程、各 2G 限额、各一本借书证(DB / Redis 池)。rag 干重活(LibreOffice 解析大文件)冲高属预期,关键看回不回落;review 池子小(独立池 5+5),慢任务一借就空。覆盖 m128 · m129 · m130 · 后端内存仪表盘「👷 RAG / Review Worker」组(内存盘 3 图)。
backend 之外还有两个「独立小弟」:rag(RAG 检索,要解析用户上传的大文件)和 review(审阅服务)。它们各自是单进程、各顶 2G 内存限额、各有自己的 DB / Redis 借书证。体检单看三样:体温计(RSS:rag 处理 LibreOffice 大文件时冲高属预期——关键看之后回不回落;冲高不回落+逼近 2G 限额 = 下一个 OOM 受害者,rag 有前科)、借书证使用率和借出数绝对值(review 是独立小池 5+5,特别容易被慢任务借空)。
先认清这两个小弟是谁。backend 是四 worker 的大店,rag 和 review 是两间独立小作坊:各只有一个进程、各分到 2G 的「房间面积」(容器限额)。因为单进程,它们的体检单没有 per-worker 多线——一个服务一条线,跟 backend 那种「四条线一起看」的画面完全不同。指标前缀也不同:siliang_worker_*,job 是 siliang-rag / siliang-review,别拿 backend 的面板来找它们。
rag 的体检重点是「冲高看回落」。它的工作就是用 LibreOffice 解析用户上传的大文档——解析期间内存必然冲高,这不是病,是干活的样子。干完活回落 = 健康(锯齿)。要警惕的是另一种形态:冲上去之后横住不回落,并且一步一步逼近 2G 限额线——这不是「正在干活」,这是「干完的活没收拾」。rag 是有前科的:它历史上就因为 LibreOffice 大文件被 OOM 杀过。OOM 不打招呼:working_set 顶到限额,内核直接 SIGKILL,日志空白,现场只剩「重启 + 5xx + 用户掉线」三联。所以「冲高不回落 + 贴限额」必须在被枪毙之前发现——这正是这张体检单存在的意义。
review 的体检重点是「小池借空」。它不像 backend 有 sync 30 / async 80 的大书架,只有一个独立小池 5+5(常备 5 + overflow 5)。小池的脾气是:平时够用,但慢任务一多——几条查询抱着连接不还——很快借空,后面所有请求排队,审阅接口集体变慢。看它就用和 backend 一样的两张卡(使用率 + 绝对值),只是脑子里要换算:这里的天花板是 5,不是 80。
| 类比里的东西 | 系统里对应的东西 |
|---|---|
| 两个独立小作坊 | rag / review:backend 之外的两个单进程服务,各 2G 限额,job=siliang-rag / siliang-review |
| 小弟的体温计 | siliang_worker_process_resident_memory_bytes(RSS,主口径;单进程每服务一条线) |
| 干活的样子 | rag 用 LibreOffice 解析大文件时 RSS 冲高——属预期,关键看之后回不回落 |
| 干完没收拾 | 冲高不回落 + 逼近 2G 限额 = OOM 倒计时(rag 被 LibreOffice 大文件 OOM 杀过,有前科) |
| 小号借书证 | review 独立 DB / Redis 池,天花板 5+5;siliang_worker_db_pool_connections 等 |
| 爬升速度计 | deriv(rss[1h]) > 5MB/h:内存盘核心告警口径,把「在爬」量化成数字 |
# 身份证(主图谱口径) job=~"siliang-rag|siliang-review" # 两个小弟的 job # 限额:rag 2G · review 2G(容器层口径,OOM 判定看 working_set)
# 判定口径(面板原话) # 冲高 → 回落 = 预期,锯齿健康 # 冲高 → 不回落 + 逼近 2G = 下一个 OOM 受害者(rag 有前科)
# 现场三联(OOM 后只剩这些) # 容器重启 + 一波 5xx + 用户掉线;日志空白,别指望遗言
deriv(rss[1h]) 算斜率=每小时涨多少字节。这是内存盘核心告警口径之一。 # 核心告警(口径卡) deriv(siliang_worker_process_resident_memory_bytes{job="siliang-rag"}[1h]) > 5MB/h # → 持续爬升;[1h] 窗口抹掉抓取抖动
# 池天花板对照(别背混) # backend: sync 30 / async 80 / checkpointer 30 # biz: 10 + overflow 20 = 30 # review: 5 + 5 # ← 特别容易被慢任务借空
siliang_db_pool_*、siliang_process_* 是两套。找错前缀=图上永远没数据。 # 前缀对照 siliang_worker_process_resident_memory_bytes # 小弟 RSS siliang_worker_db_pool_connections # 小弟 DB 池 siliang_worker_redis_pool_connections # 小弟 Redis 池
# 互证顺序 # 接口慢 → 池借空(m129/m130)→ RSS 冲高逗留(m128)→ 回源:慢任务是谁
它是什么:rag 与 review 两个单进程服务的 RSS 体温计,每实例一条线。这是两个小弟最重要的体检项——因为它们各自顶 2G 限额,而 rag 干的活(LibreOffice 解析大文件)天生就在限额边上跳舞。
回答什么问题:两个小弟的内存现在什么形态?rag 这次冲高是「正在干活」还是「干完没收拾」?离 OOM 还有几个台阶?
✅ 健康长啥样:rag 处理大文件(LibreOffice 解析)时内存冲高属预期——关键看之后回不回落;回落形成锯齿 = 健康的干活节奏。review 平稳低位。
🚨 危险长啥样:冲高后不回落 + 逼近 2G 限额 = 下一个 OOM 受害者(rag 有前科:历史上被 LibreOffice 大文件 OOM 杀过)。动作:立即配合 deriv(>5MB/h) 量化爬升,定位卡住的大文件任务并处理,不等内核开枪。
# 主图谱口径:两个小弟的 RSS(1 分钟抹抖,job 正则圈住两家) max_over_time(siliang_worker_process_resident_memory_bytes{job=~"siliang-rag|siliang-review"}[1m])
联动:主图谱 · RAG/Review Worker 内存 ↗ · 相关课程:OOM kill:内存超限直接枪毙 · 泄漏判定心法(冲高/回落/平台期)
它是什么:两个小弟自己的 DB / Redis 借书证使用率(借出 ÷ 藏书)。它们和 backend 各用各的池,所以这套面板的前缀是 siliang_worker_*——这本书的「图书馆」是分开管的。
回答什么问题:小弟的池子紧张吗?审阅/检索变慢是不是因为借不到连接(而不是服务本身慢)?
✅ 健康长啥样:使用率在低位从容波动;偶发高峰(一批任务集中处理)后回落。
🚨 危险长啥样:使用率持续贴近 100% = 池借空、请求排队。小池容量小(review 5+5),几条慢任务就能打满;动作:先找占着连接不还的慢任务(对照 m130 看借出绝对值),再考虑池参数。
# 主图谱口径:DB 池 + Redis 池使用率(前缀 siliang_worker_*) siliang_worker_db_pool_connections{state="checked_out"} / siliang_worker_db_pool_capacity + siliang_worker_redis_pool_connections / siliang_worker_redis_pool_capacity
联动:主图谱 · Worker 连接池使用率 ↗ · 相关课程:连接池:图书馆借书 · backend 视角的同款双卡
它是什么:小弟池子的绝对值版:实线=各服务借出几条,水平参考线=上限。review 是独立小池 5+5(常备 5 + overflow 5),天花板画出来就贴着地面——这张图让你直观看到「离借空还差几条」。
回答什么问题:review 现在借出几条、离 5 还差几条?借空是均匀分摊还是被某几条慢任务独占?
✅ 健康长啥样:借出数在 0~3 之间起伏,高峰短促不驻留;overflow 启用后能及时归还。
🚨 危险长啥样:借出数顶平 5 = 小池被借空,后续请求全部排队(review 池特别容易被慢任务借空)。动作:定位那几条慢任务(它们抱着连接不还),先治慢,再谈加池。
# 主图谱口径:借出数 + 上限参考线(含 review 独立池 5+5)
siliang_worker_db_pool_connections / siliang_worker_db_pool_capacity
+ siliang_worker_redis_pool_connections / siliang_worker_redis_pool_capacity
联动:主图谱 · Worker 连接池借出数与上限 ↗ · 相关课程:连接池:图书馆借书 · 锁冲突(慢任务的常见病根)
rag 冲高天天有,全是警报等于没有警报。用形态+斜率把「干活」和「泄漏」分开。
# 第 1 步:看形态——冲高之后回不回落? max_over_time(siliang_worker_process_resident_memory_bytes{job="siliang-rag"}[1m]) # → 回落成锯齿 = 干活;横住不回落 = 嫌疑 # 第 2 步:量化斜率——是真在爬还是在抖? deriv(siliang_worker_process_resident_memory_bytes{job="siliang-rag"}[1h]) # → > 5MB/h 持续 = 真爬升(核心告警口径);正负跳变 = 抖动 # 第 3 步:对照限额——还有几个台阶到 2G? # 贴 2G = OOM 倒计时(rag 有前科),立刻处理卡住的大文件任务
判读:回落 + 斜率归零 = 收工;不回落 + 斜率持续为正 + 贴限额 = 处理事故,别等内核开枪。
OOM 不打招呼,告警必须抢在内核前面。一级抓爬升速度,二级抓绝对水位。
# 一级:爬升速度(核心告警口径 deriv > 5MB/h) - alert: RagMemoryClimbing expr: deriv(siliang_worker_process_resident_memory_bytes{job="siliang-rag"}[1h]) > 5 * 1024 * 1024 labels: {severity: warning} # 在爬:定位卡住的大文件任务 # 二级:绝对水位逼近 2G 限额(示例阈值 85%,按限额换算) - alert: RagMemoryNearLimit expr: max(siliang_worker_process_resident_memory_bytes{job="siliang-rag"}) > 0.85 * 2 * 1024 * 1024 * 1024 labels: {severity: critical} # 贴限额 = OOM 倒计时(rag 有前科)
review 接口集体变慢,别急着 profile 服务——先看那本 5+5 的小借书证还剩几条。
# 借出绝对值:天花板 5,几条慢任务就能顶平 siliang_worker_db_pool_connections{state="checked_out",job="siliang-review"} # 使用率互证:贴 100% = 借空排队 siliang_worker_db_pool_connections{state="checked_out",job="siliang-review"} / siliang_worker_db_pool_capacity{job="siliang-review"} # 找病根:慢任务常见来源是锁窗口(1205=等太久,1213=死锁) sum(rate(siliang_db_lock_errors_total[5m])) by (operation, code)
判读:借出顶平 5 + 使用率 100% = 池借空实锤;顺着慢任务查锁与慢查询,治好慢,池自然松。
rag 冲高不回落时,反问一句「它在给谁干活」:把冲高时间戳与文件/媒体处理字节分布对照,找到那个「搬运工」。
# 冲高时刻的伴读图:文件/媒体处理的典型体重(P95) histogram_quantile(0.95, sum by (le) (rate(siliang_file_batch_archive_bytes_bucket[5m]))) # → 大文件在冲高窗口内被解析:冲高有了出处 # 结局对照:这批活干成了还是反复失败重试(重试=反复占内存) sum by (outcome) (rate(siliang_file_batch_archive_outcome_total[5m])) # → exception 高 = 反复重试反复占内存,RSS 不回落的重要原因
rag / review 各只有一条命(单进程),发布后确认抓取目标都在、指标在更新。
# 每个小弟的抓取目标都应是 1(up 是 Prometheus 通用指标) up{job=~"siliang-rag|siliang-review"} # → 0 = 该服务的 /metrics 没被抓到:进程挂了或抓取配置断了 # 复活后 RSS 应从低位重新开始(重启后内存归零再增长) max_over_time(siliang_worker_process_resident_memory_bytes{job=~"siliang-rag|siliang-review"}[1m])
# 错: rss > 1G 即报 # 大文件一来就误报 # 对: deriv(rss[1h]) > 5MB/h 持续 + 不回落 # 抓真爬升
# 错: siliang_db_pool_connections{job="siliang-rag"} # 前缀就错了 # 对: siliang_worker_db_pool_connections{job=~"siliang-rag|siliang-review"}
# 错: "rag 图只有一条线,是不是少抓了 worker" # 对: 单进程=一条线;数错了去查抓取配置
# 错: review 借出 > 60 才报 # 天花板才 5,永远不报 # 对: review 使用率 = 借出/5,贴 100% 即借空
# 错: RSS 高 → 直接查大对象 # 对: 先看池是否借空排队 → 再查大对象/慢任务
# 错: "到 95% 再处理" # 内核不陪你等 # 对: 逼近 2G 限额 = 立即处置 + 复盘大文件来源
参考答案:rag 的本职工作是用 LibreOffice 解析用户上传的大文档,解析期间把文件内容摊进内存,冲高就是干活的样子——和处理 200MB 视频内存先涨 200MB+ 是同一个道理。危险的形态只有一个:冲高之后不回落,并且一步步逼近 2G 限额——说明活干完了没收拾,而且 rag 有 OOM 前科,内核随时开枪。用 deriv(rss[1h])>5MB/h 把「在爬」量化出来,抢在 OOM 前处理。
参考答案:本质区别是量级:backend 是大书架(sync 30 / async 80 / checkpointer 30),review 是独立小池 5+5(常备 5 + overflow 5)。监控时脑子要换算天花板——review 借出 4 条就已经是 80% 的危险水位,几条慢任务抱着连接不还就能借空整个池子,让审阅接口集体排队。
参考答案:看三个身份标记:指标前缀(小弟是 siliang_worker_*,backend 是 siliang_db_pool_* / siliang_process_*)、job(小弟是 siliang-rag / siliang-review,backend 是 siliang_backend_worker)、线的数量(小弟单进程一条线,backend 四 worker 四条线)。三者对上,图就没找错。