memory-safety.md 6.2 KB

在线服务内存保护(F104)

应用接纳保护默认启用,重启API后生效;Linux硬隔离必须在服务器安装并启用生成的systemd unit后才生效。本轮没有安装生产unit,没有进行服务器容量压测或真实OOM验证。

应用接纳

问答、公司分类、DMS后台扫描和后台分析共享一个Admission。锁内读取RSS及系统可用内存;Linux同时取可见cgroup v2各级剩余内存的最小值,Windows读取系统内存和进程工作集。读数失败保守拒绝。Windows没有本轮新增的服务级硬限制。

配置 默认 说明
API_MEMORY_MAX_JOBS 4 共享重任务上限,范围2–32;扫描占1个,每个新分析另占1个
API_MEMORY_BUDGET_MB 4096 RSS加任务预留的接纳预算,正整数,必须大于单任务预留
API_MEMORY_JOB_RESERVE_MB 256 每个活动及待接纳任务的额外增长预留,正整数,不是实测占用或硬限额
API_MEMORY_MIN_AVAILABLE_MB 512 系统/cgroup额外可用内存底线,正整数

同名系统环境变量优先于.env。上表为代码默认值。F106按用户要求将本地.env调整为共享名额8、接纳预算8192MiB、系统余量1024MiB,每任务预留256MiB保持,需重启生效。满8个任务合计额外预留2048MiB,仍须满足RSS与可用内存检查,不能保证始终接满8个。模型/检索并发未扩大,未实测服务器容量。生产unit将应用预算设为硬预算的75%,覆盖.env同名值。

接纳条件:活动数未达上限;RSS + (活动数 + 1) × 预留 ≤ 应用预算;可用内存 ≥ 底线 + (活动数 + 1) × 预留。预留与已增长RSS叠加是有意保守计算。4个名额不等于4个用户;原会话互斥、API接纳、模型/检索限流继续生效。

问答/分类返回429 memory_busy或server_busy;采样失败返回503 memory_status_unavailable,均带Retry-After: 2。前端提示服务繁忙、稍后重试,不能显示为无政策结果,也不要无限立即重试。后台容量不足延后,不扫描、不消耗模型尝试次数;扫描中无分析名额则保留待分析状态。任务完成/失败释放名额,断线/HTTP超时不提前释放仍运行的任务。容量恢复后下次请求/扫描重新判断。

接纳保护不强行取消在途调用、不主动回收本地库内存;未新增知识原文/Redis检查点字节硬上限。启动BGE加载早于请求接纳,须由硬隔离覆盖。4GB应用预算不是实际峰值保证。

附件解析

保留单附件10MiB、每轮下载32MiB及已有解压/文本/页数边界。Linux解析子进程读输入前设置1.5GiB RLIMIT_AS(虚拟地址空间),已有更小硬限制不放宽;不使用多线程API中的preexec_fn。子进程BLAS/OMP线程设1,主API配置不变。复杂文件可能被拒绝;MemoryError返回document_memory_limit,库包装的异常或子进程被杀可能仍为document_parse_failed,不伪装成功。

Linux生产硬隔离

要求标准/sys/fs/cgroup挂载的cgroup v2内存控制器、支持MemoryMax/MemorySwapMax/OOMPolicy的systemd(建议244及以上),及原部署要求。生成器只写工作区文件,不安装或启动服务。v1/非标准挂载须先调整部署,不要关闭检查冒充隔离已生效。

服务器准备好依赖/知识后,由有systemd管理权限的运维执行。4096MiB仅为示例,应按整机内存减去Redis/Milvus等其他服务与系统余量后分配,不能把整机内存全给API。assistant替换为已有非root用户,须能读取项目/模型/配置/环境并写入所需目录。

SERVICE_PYTHON=$(cat output/deploy/python-path)
UNIT_PATH=$("$SERVICE_PYTHON" scripts/memory_service.py --user assistant --memory-max-mb 4096)
UNIT_NAME=$(basename "$UNIT_PATH")
sudo systemd-analyze verify "$UNIT_PATH"
# 首次切换先停旧进程,再安装unit,避免重叠。
sh deploy.sh stop
sudo install -m 0644 "$UNIT_PATH" "/etc/systemd/system/$UNIT_NAME"
sudo systemctl daemon-reload
sudo systemctl enable --now "$UNIT_NAME"
sudo systemctl show "$UNIT_NAME" -p MainPID -p MemoryCurrent -p MemoryHigh -p MemoryMax -p MemorySwapMax -p ControlGroup
sudo systemctl status "$UNIT_NAME"

MemoryHigh=硬预算87.5%、MemoryMax=硬预算、MemorySwapMax=0,预算覆盖API及解析子进程。OOMPolicy=kill、KillMode=control-group使内存故障/停止针对服务组;异常退出10秒后重启,5分钟最多3次启动,避免重启风暴。触及硬限额可能终止正在进行的问答。系统或其他服务内存耗尽仍可能影响本服务。

生产入口要求读到不高于指定硬预算的有限cgroup限制,否则启动失败。API_REQUIRE_MEMORY_CGROUP和API_MEMORY_HARD_LIMIT_MB由生成器设置用于检查,不要删除。生成unit名含项目路径指纹;ExecStart通过deploy.sh serve前台启动,每次读取output/deploy/python-path,因此更新依赖后不绑定旧环境。

安装后原deploy/start/stop/restart入口转由systemctl管理该unit,权限失败不会回退为无限额后台进程,执行者需有相应权限。启动就绪核对systemd MainPID与本项目API身份。不要并行手工启动python -m src.step4_api绕过隔离,不要移动已安装unit对应的项目。systemd日志用journalctl -u查看,原后台模式仍用output/deploy/api.log。

官方依据:资源控制、故障和重启。

验证与边界

合成测试覆盖并发不超售、内存/可用量拒绝、采样失败、恢复、提交/工作失败释放、断线持有、前后台共享、延后不耗尝试次数;模拟cgroup祖先及命名空间、缺失硬限制拒绝启动、检查unit参数与部署无回退。未耗尽真实内存、未真实模型/DMS测试,未在Linux验证unit及解析器硬限制。

Redis、Milvus、知识更新/入库是独立服务或命令,不受API unit覆盖。同机须分别分配资源限额;Redis还应按会话恢复语义选择maxmemory策略,不任意淘汰会话。本轮未修改这些服务。生产容量、持续运行内存趋势、GPU显存、真实Linux附件兼容性待验证,不能宣称整台服务器绝不会OOM。