现场是这样的。提示词存在 MySQL 的 prompt 表,管理后台改完立刻查询能读到新值,线上服务仍用旧文案,重启进程后才生效,用的是 SQLAlchemy 2.0 加 Redis 做二级缓存。

中间走过弯路,把「读写走了不同实例,从库延迟导致读到旧行」当成主因,改完现象没变。

排查方向其实有限,先把可能性排一排。会话级 identity map 缓存了同一个主键对象;二级缓存按查询语句缓存,没有按主键失效;更新语句没提交事务,后台看到的只是本会话快照。

第一件事是确认服务读到的版本号与库里的更新时间

python -c "import pymysql;c=pymysql.connect(host='db',user='u',password='p',database='app');print(c.cursor().execute('select id,version,updated_at from prompt order by id desc limit 3'))"

接着关掉二级缓存后重查同一主键

python -c "from sqlalchemy import create_engine;e=create_engine('mysql+pymysql://u:p@db/app',echo=True);print(e.execute('select version from prompt where id=1').fetchone())"

更新后显式让缓存失效再读

python -c "from sqlalchemy.orm import Session;Session.expire_all();print(s.get(Prompt,1).version)"

末了把读取路径改成短 TTL 加版本号校验

python prompt_loader.py --ttl 5 --check-version

怎么算真的好了,看的是同一批现象。后台改完后线上十秒内切到新文案,日志里读到的 version 与库中一致,不再依赖重启。

补一句。ORM 缓存与业务缓存叠在一起时,改库不生效几乎是必然的,排查要一层层关缓存,先关二级再关会话级,别一上来就重启。这类问题最好一次改到位,反复小改反而容易把原因搅混。

作者 9823189