【DB吐槽大会】第2期 - PG 32位xid

背景


视频回放

1、产品的问题点

  • 事务号xid是uint32类型, 最多只能存储40亿个事务号, 事务号必须循环使用.

2、问题点背后涉及的技术原理

  • 事务号是事务的标记, 在row的头信息中存储着这条记录是由哪个事务写入、更新、删除的. 数据库需要通过事务号来判断事务是过去的还是未来的事务.
  • 大于当前事务号、或者大于当前事务快照最小未分配事务号的都是未来的事务, 对当前query不可见.

由于xid只能存储40亿个事务, 所以很快就会耗尽, PG为了解决耗尽问题, XID就需要重复使用, 怎么重复使用呢?

  • 通过设置一个全局的frozenxid, 将XID的40亿切成2半, 把XID的可用空间想象成一个圆, frozenxid就在这个圆上移动, 处于它顺时针方向的一半属于已消耗的事务号(在过去), 处于它逆时针方向的一半属于可分配的事务号(在未来).
  • 随着数据库事务发起xid不断消耗, 这个 frozenxid 必须在事务号消耗20亿之前发生移动, 否则就变成全部都是已分配事务了.

frozenxid怎么移动呢?

  • 为了让frozenxid移动, 我们必须对全集群的表进行扫描, 把已有的记录头信息中设置对应的bit位, 表示这条记录已经是frozen的, 因此这个集群的frozenxid就在圆上往前移动了. 它可以使用的事务号半圆内又有足够的事务号可以分配.
    • frozenxid在圆上 老的位置 与 新的位置 这段区间内的xid就是被标记了了bit的事务.

什么时候会触发frozen操作呢?

  • autovacuum会定时(参数设定)扫描系统表, 发现达到阈值的表会触发frozen操作.

3、这个问题将影响哪些行业以及业务场景

  • 频繁更新的业务. 和MVCC那一期一样.

4、会导致什么问题?

  • frozen操作需要扫描全表, 会产生较大IO.
  • 如果frozen不及时, 严重的(如剩余可分配事务号低于100万时)要停库进入单用户模式执行frozen.
  • 如果大量的表在一个较小的时间窗口内都触发了frozen, 那么会发生frozen风暴, 主库IO使用量暴增, 导致性能问题, 同时如果产生大量wal日志, 会导致从库复制延迟.

5、业务上应该如何避免这个坑

  • PG 内核的优化: 对于已frozen后没有变化过的PAGE可以跳过以减少扫描. 所以更新不频繁的系统frozen发生时系统的消耗并不高.
  • 海量静态数据写入时即设置为freeze标记位, 避免二次freeze.
  • 使用更好的SSD, 加速frozen, 降低frozen IO影响.
  • 主、从库之间采用更大带宽的网络
  • 设置autovacuum sleep间隙, 降低frozen IO影响.
  • 不同的表, 或者分区, 不同分区设置不同的frozen阈值, 避免同时发生frozen操作产生风暴.

6、业务上避免这个坑牺牲了什么, 会引入什么新的问题

  • 增加了管理成本
  • 增加了硬件成本

7、数据库未来产品迭代如何修复这个坑

  • 64位xid
    • 例如 zedstore, zheap, postgrespro 等引擎.



上一篇:【DB吐槽大会】第3期 - share nothing RO


下一篇:【DB吐槽大会】第1期——PG MVCC