匿名用户当再终端开启2个会话,其中会话1 执行
begin;
update t set ....;
模拟线上有写操作,但是没有完成
会话2 执行
SELECT squeeze.squeeze_table('public', 'test', null, null, null);
发现会话2 ,会因为锁等待而卡住,请问都说线上环境用这个工具不影响业务,请问这个咋理解呢?
在PostgreSQL中,pg_squeeze 是一个用于在线表重组的扩展工具,它可以有效减少表膨胀(bloat),从而提高性能。然而,当表有频繁的更新、删除或插入操作时,pg_squeeze.squeeze_table 可能会被阻塞或卡住,主要原因是它需要获取某些锁(如 ACCESS EXCLUSIVE 锁)来完成表的重组工作。
在实际的生产环境中,为了安全高效地使用 pg_squeeze,需要采取以下策略来避免或最小化对业务的影响:
1. 使用 pg_squeeze 的基础原理
pg_squeeze 的工作机制通常分为以下几个阶段:
- 创建一个新的临时表。
- 将源表的数据逐行复制到临时表中(考虑并发事务)。
- 替换原始表的物理存储。
- 丢弃临时表。
其中,在某些阶段需要短暂获取较高级别的锁(如 ACCESS EXCLUSIVE),这可能导致阻塞或等待。
2. 问题分析
当表有频繁的更新操作时,以下问题可能会导致 pg_squeeze.squeeze_table 被卡住:
- 锁冲突:
pg_squeeze在进行表替换时需要获取ACCESS EXCLUSIVE锁,而此锁会阻塞其他操作(如查询、更新、删除等)。如果表上有活跃事务,这个锁可能会一直等待。 - 长事务影响:如果有长时间运行的事务占用资源,会导致
pg_squeeze无法获取所需锁。 - 表数据量大:对于非常大的表,
pg_squeeze的数据复制阶段可能会耗时较长,从而增加锁定和冲突的可能性。
3. 线上环境的最佳实践
为了在生产环境中安全有效地使用 pg_squeeze,可以采取以下措施:
3.1 降低锁冲突风险
-
使用
squeeze_freeze参数:
设置squeeze_freeze为TRUE时,pg_squeeze会尝试冻结表的元数据以避免长时间占用锁。SELECT squeeze_table('schema_name', 'table_name', squeeze_freeze := TRUE); -
限制锁等待时间:
通过设置lock_timeout参数,限制ACCESS EXCLUSIVE锁的等待时间。如果超时未能获取锁,pg_squeeze将取消操作。SET lock_timeout = '10s'; SELECT squeeze_table('schema_name', 'table_name'); -
使用
pg_try_advisory_lock:
在运行之前检查是否可以安全地获取锁,避免直接将pg_squeeze卡住。
3.2 避免高峰期执行
-
选择业务低峰期:
在业务访问量较低的时间段(如深夜)运行pg_squeeze,以最小化对正常业务的影响。 -
分批处理:
对于数据量较大的表,可以按分区(如果有)或逐步迁移的方式进行重组,而不是一次性处理整个表。
3.3 配置合适的参数
-
调整
pg_squeeze参数:
配置合适的参数以减少对业务的影响。例如:squeeze_triggered_by_table_bloat: 触发表膨胀的阈值。squeeze_max_retry_count: 遇到锁冲突时的最大重试次数。squeeze_vacuum_cost_delay: 控制 VACUUM 操作的延迟,避免过多资源占用。
-
加速复制过程:
使用parallel_workers参数(如果可用)来加快数据复制阶段,减少所需时间。SELECT squeeze_table('schema_name', 'table_name', parallel_workers := 4);
3.4 监控与诊断
-
监控锁信息:
在执行pg_squeeze的过程中,实时监控锁的状态,确保没有长时间的锁等待。SELECT * FROM pg_locks WHERE relation::regclass = 'schema_name.table_name'::regclass; -
查看活动事务:
检查当前的活跃事务,避免长时间事务阻塞pg_squeeze。SELECT * FROM pg_stat_activity WHERE state = 'active'; -
日志分析:
打开pg_squeeze的日志记录功能,分析问题根源。
3.5 自动化调度
-
使用调度器:
配置pg_squeeze与调度器(如cron或pg_cron)结合,定期清理膨胀,但是要确保调度任务的时间避开业务高峰期。示例:
INSERT INTO squeeze.tables (schemaname, tablename, enabled) VALUES ('schema_name', 'table_name', TRUE); -- pg_squeeze 将自动在后台运行
4. 替代方案
如果表的更新频率非常高,或者表特别大,可以考虑以下替代方法:
- 逻辑重建:通过创建新表、复制数据,然后切换到新表的方式手动完成重组。
- 分区表:对大表进行分区,可以减少膨胀,并降低表重组的复杂性。
- VACUUM FULL:虽然会锁表,但对于一些极端膨胀的表,VACUUM FULL 可能是更快的解决方法。
评论
有用 2
墨值悬赏

