今天在使用Supabase过程中,遇到磁盘空间告警并影响项目正常运行的情况。当时冒了一身冷汗,产品经理就在旁边。幸好supabase上放的主要是异步数据(内部使用和清洗的数据),没有造成线上不可用(对用户无影响),但由于每日依赖这批数据,我需要在24H内修复它。历时一天我终于定位并且修复了问题。
本文结合实际案例,系统梳理了从告警现象、问题排查到修复手段的全过程,重点涵盖了索引清理、触发器优化、空间回收及Postgres版本升级等关键环节,供大家参考(以下内容均已脱敏)
一、告警现象与问题描述
Supabase免费项目默认配备8GB的GP3磁盘空间,超过后会自动扩容1.5倍,但超出免费额度部分会按小时计费。告警通常表现为:
- 控制台提示“Projects exceeding quota”,磁盘使用超过8GB免费额度。
- 项目进入只读模式,写操作受限。
- 计费页面显示持续的磁盘使用量(usage)和费用。
- 无法直接缩减磁盘大小,提示需升级Postgres版本触发“right-size”操作。
二、问题排查与定位
1. 查看磁盘使用情况
通过SQL查询了解数据库及各表大小:
SELECT pg_size_pretty(pg_database_size(current_database())) AS db_size;
SELECT relname AS table_name,
pg_size_pretty(pg_total_relation_size(relid)) AS total_size
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC;
2. 检查索引使用情况,排查冗余索引
查询表的所有索引:
SELECT indexname, indexdef FROM pg_indexes WHERE tablename = 'your_table_name';
查找未使用的索引(idx_scan=0):
SELECT psui.indexrelid::regclass AS index_name,
psui.idx_scan AS index_scans
FROM pg_stat_user_indexes psui
JOIN pg_index pi ON psui.indexrelid = pi.indexrelid
WHERE psui.idx_scan = 0 AND pi.indisunique = false;
确认冗余索引后,删除无用索引:
DROP INDEX IF EXISTS redundant_index_name;
3. 检查触发器,删除无用触发器
查询触发器:
SELECT tgname FROM pg_trigger WHERE tgrelid = 'your_table_name'::regclass;
删除无用触发器:
DROP TRIGGER IF EXISTS trigger_name ON your_table_name;
4. 检查表膨胀及死元组情况
使用pgstattuple扩展查看表膨胀:
CREATE EXTENSION IF NOT EXISTS pgstattuple;
SELECT * FROM pgstattuple('your_table_name');
三、修复手段与具体语句
1. 删除冗余索引和触发器,减少空间和性能消耗
示例:
DROP INDEX IF EXISTS idx_job_positions_url_isclose_id_desc;
DROP TRIGGER IF EXISTS handle_updated_at ON your_table_name;
2. 执行VACUUM FULL彻底回收空间
VACUUM FULL your_table_name;
注意:
VACUUM FULL会锁表,执行时间较长,建议在业务低峰期执行。
3. 重建索引(如索引膨胀严重)
REINDEX TABLE your_table_name;
4. 升级Postgres版本触发磁盘“right-size”
-
删除不兼容扩展(如
pgjwt):sql DROP EXTENSION IF EXISTS pgjwt; -
在Supabase控制台项目设置中找到Postgres版本升级入口,执行升级操作。
-
升级过程中,系统会根据当前数据库大小自动调整磁盘容量,释放WAL碎片,减少磁盘浪费。
5. 设置更长的statement_timeout避免长操作超时
连接数据库后执行(注意在supabase的dashboard后台不生效,需要本地使用python来运行):
SET statement_timeout = '120min';
然后执行VACUUM FULL等长时间操作。
四、WAL日志空间管理
- WAL(预写日志)用于保证数据一致性和崩溃恢复,是数据库核心机制。
- WAL日志写入频繁,可能占用较大磁盘空间。
- 通过合理配置检查点(checkpoint)、归档策略和监控复制延迟,控制WAL空间增长。
- 不要手动删除WAL文件,避免数据库崩溃。
五、总结与建议
| 关键步骤 | 作用与说明 |
|---|---|
| 删除未使用的索引 | 减少磁盘占用和写入开销 |
| 删除无用触发器 | 减少额外的性能和空间消耗 |
执行VACUUM FULL | 彻底回收死元组空间,释放磁盘 |
重建索引(REINDEX) | 清理索引膨胀,提升查询性能 |
| 升级Postgres版本 | 触发磁盘“right-size”,缩减磁盘碎片和WAL空间 |
| 设置长超时参数 | 避免长操作被超时中断 |
| 监控数据库大小和使用情况 | 及时发现和预防磁盘空间问题 |
通过以上步骤,成功解决了Supabase磁盘满告警问题,恢复了项目的正常读写和性能,避免了额外计费和限制。
参考链接
通过这次问题定位与修复,深刻体会到数据库维护的重要性,合理管理索引和空间,结合平台特性,才能保障项目稳定高效运行。
目前看到的情况是,在100万数据量左右情况下supabase会出现蛮奇怪的现象。一开始用supabase用得爽,网络传输成本以及与大数据计算(如火山云的Mapreduce、阿里云ODPS【dataworks】的集成还是有蛮多不方便。
计划后面还是需要排期将系统迁移到阿里云或者火山引擎的postgresql。