这类问题我又碰上了一次。服务里用 functools.lru_cache(maxsize=5000) 缓存文本 embedding,发布重启后第一批请求全部回源,embedding 接口的 QPS 瞬间到 200,直接 429。
第一反应是「缓存键用整段文本,标点改一下就落空」,验证下来不成立。
把日志和配置对完,能解释这个现象的基本就这几处。进程内缓存随重启清空,发布即冷启动;gunicorn 起 4 个 worker,各存一份,命中率只有四分之一;没有预热逻辑,流量一上来全部并发回源。
上来先看当前的命中率
python -c "from functools import lru_cache;f=lru_cache(maxsize=5000)(lambda x:x);[f(i%50) for i in range(100)];print(f.cache_info())"
随后换到 Redis 做共享缓存并加 TTL
redis-cli SET emb:8f3a "[0.01,0.02]" EX 604800
接着把缓存键改成文本的 sha256 前 16 位
python -c "import hashlib;print(hashlib.sha256('合同第一条'.encode()).hexdigest()[:16])"
发布后先跑预热脚本再放流量
python warmup.py --file hot_queries.txt --concurrency 5
怎么算真的好了,看的是同一批现象。重启后 Redis 命中率达到 78%,embedding 接口的峰值 QPS 从 200 降到 45,没有再出现 429,冷启动时间缩短到 20 秒。
进程内缓存适合纯计算,跨进程共享的数据要么放 Redis 要么接受冷启动,发布窗口的流量最好用预热顶住。同一份配置在测试环境跑通,不代表线上没事,两边的默认值经常不一样。
