线上出了个PGVector的Bug,我排查了一夜。
本文是我的排查记录,包括问题现象、排查过程、根本原因、解决方法,以及经验教训。
一、问题出现
1. 线上报警
那天晚上,线上报警了。
- 向量搜索服务异常
- 查询超时
- 错误率飙升
- 用户投诉
- 我被电话叫醒了
线上问题,总是在半夜来。
2. 初步判断
初步判断:
- 是PGVector的问题
- 不是应用层的问题
- 不是网络的问题
- 是数据库层面的问题
- 需要尽快排查
PGVector,是核心。
3. 开始排查
我开始排查。
- 登录数据库
- 看日志
- 看监控
- 看慢查询
- 一步步来
排查,需要冷静。
二、排查过程
1. 第一步:看慢查询
第一步:看慢查询。
-- 查看慢查询
SELECT * FROM pg_stat_statements ORDER BY mean_exec_time DESC LIMIT 10;- 发现向量查询很慢
- 平时几十毫秒
- 现在几秒
- 找到了线索
慢查询,是第一线索。
2. 第二步:看索引
第二步:看索引。
-- 查看索引
SELECT * FROM pg_indexes WHERE tablename = 'documents';- 索引存在
- 但没生效
- 为什么?
- 继续排查
索引,是关键。
3. 第三步:看执行计划
第三步:看执行计划。
-- 查看执行计划
EXPLAIN ANALYZE
SELECT * FROM documents
ORDER BY embedding <=> '[1,2,3]'
LIMIT 10;- 发现没有用索引
- 全表扫描
- 为什么索引失效?
- 继续排查
执行计划,是真相。
4. 第四步:看数据量
第四步:看数据量。
- 数据量增长很快
- 从几十万到几百万
- 索引可能有问题
- 或者参数不对
- 继续排查
数据量,是诱因。
5. 第五步:复现问题
第五步:复现问题。
- 测试环境复现
- 大数据量下
- 确实查询慢
- 索引失效
- 确认了问题
复现,是修复的前提。
三、根本原因
1. 原因一:索引参数不对
第一个原因:索引参数不对。
- ivfflat索引
- lists参数设置不合理
- 数据量增长后
- 索引效率下降
- 查询变慢
索引参数,是核心问题。
2. 原因二:没有重建索引
第二个原因:没有重建索引。
- 数据量增长后
- 索引需要重建
- 但没有重建
- 索引效率下降
- 查询变慢
重建索引,是必要的。
3. 原因三:work_mem太小
第三个原因:work_mem太小。
- 向量查询需要内存
- work_mem设置太小
- 导致排序慢
- 查询超时
- 是参数问题
work_mem,是参数问题。
4. 原因四:没有分区
第四个原因:没有分区。
- 单表数据量太大
- 没有分区
- 查询慢
- 维护难
- 是架构问题
分区,是架构问题。
5. 原因五:监控不完善
第五个原因:监控不完善。
- 没有向量查询监控
- 没有索引监控
- 没有数据量监控
- 问题发现晚
- 被动应对
监控,是眼睛。
四、解决方法
1. 临时方案:优化参数
临时方案:优化参数。
-- 调整work_mem
SET work_mem = '256MB';
-- 调整维护内存
SET maintenance_work_mem = '1GB';- 先调参数
- 缓解问题
- 恢复服务
- 再慢慢优化
- 先止血
止血,是第一步。
2. 重建索引
重建索引:
-- 重建索引
REINDEX INDEX documents_embedding_idx;
-- 或者重建ivfflat索引
DROP INDEX documents_embedding_idx;
CREATE INDEX documents_embedding_idx ON documents USING ivfflat (embedding vector_l2_ops) WITH (lists = 1000);- 重建索引
- 调整lists参数
- 根据数据量调整
- 提升查询效率
重建索引,是核心修复。
3. 优化查询
优化查询:
-- 用索引扫描
SET enable_seqscan = off;
-- 调整probes
SET ivfflat.probes = 10;- 优化查询参数
- 强制用索引
- 调整probes
- 平衡精度和速度
查询优化,是辅助。
4. 分区表
分区表:
-- 创建分区表
CREATE TABLE documents (
id bigserial,
embedding vector(1536)
) PARTITION BY RANGE (id);
-- 创建分区
CREATE TABLE documents_0 PARTITION OF documents FOR VALUES FROM (0) TO (1000000);
CREATE TABLE documents_1 PARTITION OF documents FOR VALUES FROM (1000000) TO (2000000);- 大表分区
- 提升查询性能
- 便于维护
- 是长期方案
分区,是长期方案。
5. 完善监控
完善监控:
- 向量查询耗时监控
- 索引使用率监控
- 数据量监控
- 慢查询告警
- 及时发现问题
监控,是保障。
五、验证效果
1. 测试
测试:
- 测试环境测试
- 大数据量下
- 查询从几秒降到几十毫秒
- 索引用上了
- 性能提升明显
测试,验证修复。
2. 上线
上线:
- 灰度发布
- 观察监控
- 没有问题
- 全量发布
- 服务恢复
上线,完成修复。
3. 观察
观察:
- 观察几天
- 查询稳定
- 没有超时
- 错误率正常
- 问题解决
观察,确保稳定。
六、经验教训
1. 教训一:向量数据库要调优
第一个教训:向量数据库要调优。
- PGVector不是装了就好
- 需要调优
- 需要根据数据量调整参数
- 需要重建索引
- 不能忽视
调优,是必要的。
2. 教训二:索引参数很重要
第二个教训:索引参数很重要。
- ivfflat的lists参数
- 要根据数据量调整
- 不是一成不变
- 数据量增长后要调整
- 很关键
索引参数,是关键。
3. 教训三:大数据量要分区
第三个教训:大数据量要分区。
- 单表不要太大
- 要分区
- 提升性能
- 便于维护
- 是架构设计
分区,是架构。
4. 教训四:监控要完善
第四个教训:监控要完善。
- 向量查询要监控
- 索引要监控
- 数据量要监控
- 早发现早处理
- 不要等用户投诉
监控,是眼睛。
5. 教训五:要有应急预案
第五个教训:要有应急预案。
- 出问题知道怎么办
- 先止血再修复
- 快速恢复
- 减少影响
- 是保障
预案,是保障。
七、PGVector最佳实践
1. 索引选择
最佳实践一:索引选择。
- ivfflat:适合大数据量,查询快
- hnsw:适合高精度,更新快
- 根据场景选择
- 没有最好只有最合适
索引选择,是基础。
2. 参数调优
最佳实践二:参数调优。
- lists:根据数据量,一般数据量/1000
- probes:查询时设置,平衡精度和速度
- work_mem:足够大,避免磁盘排序
- 定期调整
参数调优,是核心。
3. 数据维护
最佳实践三:数据维护。
- 定期重建索引
- 定期VACUUM
- 监控数据量
- 及时分区
- 保持健康
数据维护,是长期工作。
4. 查询优化
最佳实践四:查询优化。
- 用LIMIT
- 用索引
- 调整probes
- 避免全表扫描
- 持续优化
查询优化,是持续的。
5. 监控告警
最佳实践五:监控告警。
- 查询耗时监控
- 索引使用率监控
- 数据量监控
- 慢查询告警
- 及时处理
监控告警,是保障。
八、写在最后
线上出了个PGVector的Bug,我排查了一夜。
问题是索引参数不对、没有重建索引、work_mem太小、没有分区、监控不完善。排查过程:看慢查询、看索引、看执行计划、看数据量、复现问题。解决方法:优化参数、重建索引、优化查询、分区表、完善监控。
2023年了,向量数据库越来越流行,PGVector是其中的代表。但不是装了就好,需要调优,需要维护,需要监控。出问题不可怕,可怕的是不从问题中学习。
最后,用一句话总结:"PGVector,不是装了就好,需要调优,需要维护,需要监控。出问题不可怕,可怕的是不总结。每次排查都是一次成长。"
愿你的线上服务,永远稳定,永远不半夜报警。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录