Commit d9a9fda0 by luoqi

merge: 堆上限按生产实测下调到 6144 → main

parents b60a5923 cfb6e16b
Pipeline #3685 failed in 0 seconds
......@@ -117,14 +117,18 @@ services:
# dockerd(闲时 0.4G,08-29 压力下实测 2.7G) ~2.7 GB ← ⚠️ 它在容器外,本行限不住
# pac-web + pac-docs(实测 49+64 MB) ~0.2 GB
# ────────────────────────────────────────────────
# 可给 pac-service ~10 GB → 观测峰值 6.03G,取 8G(留 33% 余量)
# 可给 pac-service ~10 GB → 取 8G,余下留给 OS/dockerd
#
# ⚠️ **与下面 NODE_OPTIONS 的 8192 相等,是刻意的过渡态,不是笔误。**
# RSS 恒大于 V8 堆(堆外还有 Buffer/Prisma engine/源码映射),两者都是 8G 时一定是
# **先撞 cgroup 被 SIGKILL(exit 137,无任何日志)**,而不是 V8 抛 heap limit(有堆栈)。
# 理想是堆上限 < mem_limit,让 V8 先自己抛。但现在**没有生产实测峰值**可依据 ——
# 分批改造(09-05 上线)每 5 批打一行 `heapUsed=`,拿到真实峰值后再压堆上限。
# ⛔ 别凭感觉先把 8192 调小:调过头会把本来能跑完的轮次变成必崩。
# ✅ 8G 已由生产实测证实**很宽**(2026-09-05 10:15 那轮,分批改造上线后第一轮干净数据,
# 550,481 召回池):**峰值 rss=2873MB,只用到 36%,2.8 倍余量,RestartCount=0 全程没被杀。**
# ⚠️ 定这个数时手上只有 6.03G 那个**分批改造之前**的旧峰值(才留 33% 余量),
# 是分批把实际峰值又压掉一半多。⛔ 以后调这个数**必须重新量**,别拿 6.03G 当依据。
# 量法:`docker logs pac-pac-service-1 | grep -o "rss=[0-9]*MB heapUsed=[0-9]*MB"` 取最大。
#
# 【与下面 NODE_OPTIONS 的关系】RSS 恒大于 V8 堆(堆外还有 Buffer/Prisma engine/源码映射,
# 实测约 560MB)。两者若相等,撞顶时**一定是先被 cgroup SIGKILL(零日志零堆栈)**,
# 而不是 V8 抛 heap limit(有 JS 堆栈)。所以堆上限必须**低于** mem_limit ——
# 09-05 拿到实测峰值后已把它从 8192 下调到 6144,理由写在那一行旁边。
#
# ⚠️ **swap 语义**:docker 不显式设 memswap_limit 时,总量 = 2×mem_limit(8G RAM + 8G swap)。
# 生产**没有 swap** → 就是硬 8G,精确。测试机有 16G swapfile → 那边实际是 8G+8G。
......@@ -187,10 +191,31 @@ services:
# ⛔ 但**别手工并发跑** `recompute-plans --host=<全量>`(它也吃 8G)——
# 那条 CLI **不走 sync 锁**,与服务自己那轮全量撞上时才真有可能把宿主吃满。
#
# ⚠️ 这是**止血不是根治**:池子还在涨,8G 迟早也会到顶。
# 根治是「增量之后别跑全量」—— `recompute-plans` 已经有 `--clinics` 收窄能力,
# 同样的思路搬到 SyncIncrementalSchedulerService 那一处即可。
NODE_OPTIONS: --max-old-space-size=8192
# ⚠️ 抬天花板只是**止血**。根治是「增量之后别跑全量」——
# `recompute-plans` 已经有 `--clinics` 收窄能力,同样的思路搬到
# SyncIncrementalSchedulerService 那一处即可。(2026-09-05 的端到端分批
# 把峰值压掉一半多,但"每轮都对全部患者跑一遍召回"这个行为本身没变。)
#
# 🔵 2026-09-05 由 8192 下调到 6144 —— **不是为了省内存,是为了让失败可诊断**。
#
# 加了 mem_limit(8g)之后,堆上限还留在 8192 会形成一个坏顺序:RSS 恒大于堆
# (实测 rss=2873MB 时 heapTotal=2309MB,堆外常驻约 560MB),
# 两者相等时**一定是先撞 cgroup 被 SIGKILL(exit 137,零日志零堆栈)**,
# 而不是 V8 抛 `Reached heap limit`(有 JS 堆栈,能直接定位是哪段吃的)。
# 等于把唯一一次能拿到现场的机会浪费掉 —— 而 09-04 整件事就是败在没有现场。
#
# 6144 的依据(2026-09-05 生产 10:15 那轮实测,分批改造上线后第一轮干净数据):
# 峰值 heapUsed=2437MB(批 15),之后单调降到 402MB;峰值 rss=2873MB。
# 6144 相对实测峰值留 2.5 倍余量;最坏 RSS ≈ 6144 + 600 ≈ 6.7G < 8G ⇒ V8 先抛。
#
# ⚠️ 不影响 CLI:补摄/recompute-plans 走 `node --max-old-space-size=8192 …`,
# 命令行 V8 flag 覆盖 NODE_OPTIONS(Node 把 NODE_OPTIONS 当作排在命令行**之前**),
# 重复 flag 取最后一个。⛔ 但别忘了它们和服务同 cgroup,见上面 mem_limit 那段。
#
# ⚠️ 什么时候该往回调:池子涨到让 heapUsed 峰值逼近 4G(即 6144 的 2/3)时。
# 峰值主要由 selectHits→hitsByPatient 那份双拷贝决定,它随**命中数**涨,
# 不随分批变小 —— 那才是下一个要动的地方,不是这个数。
NODE_OPTIONS: --max-old-space-size=6144
# 覆盖 .env 的 localhost URL → 走 docker 内部网络
DATABASE_URL: postgresql://${POSTGRES_USER:-pac}:${POSTGRES_PASSWORD:-pac}@postgres:5432/${POSTGRES_DB:-pac}?schema=public
REDIS_URL: redis://redis:6379
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment