用户注销流程只删了 MySQL 主表,向量库里该用户的 120 条 chunk 还在,payload 里的手机号也能查到,三天后合规抽查时被发现。

一开始怀疑是「embedding 缓存里还留着原文」,查了一圈,方向不对。

排查方向其实有限,先把可能性排一排。删除流程没覆盖向量库这个存储。也可能是软删除标记没有同步到检索侧。

另外,备份与快照按周期保留,没有清理策略。

第一件事是按租户查出残留条数

curl -s -X POST http://qdrant:6333/collections/docs/points/scroll -d '{"filter":{"must":[{"key":"tenant_id","match":{"value":"u_123"}}]},"limit":100}' | jq '.result.points | length'

然后按过滤条件批量删除

curl -s -X POST http://qdrant:6333/collections/docs/points/delete -d '{"filter":{"must":[{"key":"tenant_id","match":{"value":"u_123"}}]}}'

接着清掉缓存里的对应条目

redis-cli --scan --pattern 'emb:u_123:*' | xargs -r redis-cli DEL

剩下的就是核对主表与向量库条数一致

python reconcile.py --user u_123 --mysql-count 0 --vector-count 0

命令输出我都留了记录,免得改完记不清原来的值。

恢复的判定其实很直接。该用户在向量库的条数为零,检索接口不再返回他的内容,对账脚本输出一致。

提醒一点。注销清单要把主库、缓存、向量库、备份分开写,最容易漏的就是向量库和备份快照。报错文案容易误导,真正的原因往往在相邻那一层的日志里。

作者 9823189