1. 前言
实际上PostgreSQL数据库没有回滚段的设计是比较有创意的地方,但一些人也认为这是有争议的地方,笔者以前是Oracle DBA,也熟悉MySQL数据库,所以试图最佳实践的角度和从原理上把有回滚段和没有回滚的好处和坏处和大家讲清楚。
2. 无回滚段的争议
后,会认为PostgreSQL中无回滚段就是一个缺陷,同时埋怨PG内核社区的人为什么还不赶紧把这个功能加上去,如这篇文章的作说:
很多人在读了这些vacuum的文章,可能都会在潜意识中把vacuum的负作用放大,实际上PG内核开发人员没有把回滚段加上是有原因的,因为回滚段这个事情是有两面性的,目前PG这样没有回滚段时,虽然看起来好象需要vacuum做清理,好象会多产生一些IO,会产生很多负面的影响,实际上这种方式产生的IO与回滚段在理论上是差不多的,同时这种方式也有很多好处。
使用回滚段后,虽然解决了一些问题,但也会带来一些棘手的问题。例如我们知道Oracle中使用了回滚段,如Oracle数据库宕机时如果有很多事务正在运行,这时数据库再启动后,需要把之前的事务做回滚,当没有回滚完成时,数据行上仍然有锁的,这时业务仍然不能正常操作,如果恰好碰到要回滚一些很大的事务,情况会更坏。而PG因为没有回滚段,异常宕机后,启动后可以很快进入正常工作的状态。明显在出现数据库宕机这种出故障之后,每个人都希望数据库能尽快恢复正常,但这种回滚段的机制导致数据库宕机后的恢复正常工作的时间变长。同时需要记住回滚操作本身,也会产生大量的redo log,对IO也会产生冲击。所以在oracle数据库中这种使用了固定空间的回滚段,如果无经验的DBA导致配置不合理,当有大量的并发事务操作时回滚段中的旧数据来不及回收,导致回滚段满了,就会导致数据库的所有更新操作都被hang住,出现这种情况的概率在Oracle领域其实也并不低。所以PG内核社区对于是否需要加上回滚段的功能,一直是有争议的,原因就是在于使用回滚段,看起来美好,但也存在另外一些麻烦的事情。
所以实际上回滚段是把旧版本集中放到一个地方集中处理,这个集中进行垃圾回收,虽然处理效率高一些,但“集中”就意味竞争更激烈,系统可能更不稳定,而集中处理通常也是会占用IO,只是PG的回收操作发生在数据文件,而其它数据库发生在回滚段。而象PG这样把旧版本放在原先的数据文件中,并没有集中到回滚段中,相对来说,竞争就没有这么激烈。同时因为MVCC的事务机制,回滚段中的数据虽然是旧版本数据,但仍然不能丢失,当回滚段损坏,就会导致数据库起不来,所以从工程实践上来看,回滚段的机制在一定的程度上会降低数据库的可靠性。在Oracle中的一些掉电故障后起不来的情况,多数原因是因为回滚段中有数据丢失或损坏。
有人可能会问,为什么MySQL使用了回滚段,但没有感觉出回滚段的坏处?原因是MySQL不太能支持单实例大数据库,在MySQL单实例上通常没有这么大的事务并发(注意是TPS,还不是QPS),而在PG和Oracle中有很多5T以上的大数据库存在,也有很多大事务并发的数据库。而MySQL通常都是分库分表,经过分库分表之后单个实例并不大,在生产中MySQL大于1T的数据库比较少。所以,MySQL如果有一些大于5T的数据库,同时事务并发又高,那么回滚段的问题也会出现。
其实对于回滚段的机制,只是第一眼看上去好象比PG目前这种没有回滚段的设计好一些,但真的这么做了,是否好就不一定了。因为你放到回滚段中,实际上旧版本的数据也是要清理的,只是在回滚段中需要集中清理,而在pg中,是分散到各个数据文件中去清理。而在PG中每次做vacuum中,并不需要把数据文件全部扫描,一些没有发生变化的数据块,并不需要去扫描。所以很多时候,第一次做vacuum时会慢很多,原因是需要清理的垃圾数据很多,但第二次和第三次会快很多,就是这个原因。
3. vacuum的一些最佳实践
当然如果你的数据库vacuum也没有导致出问题,autovacuum_freeze_max_age的就保持默认值2亿,这在多数的数据库也不存在问题。

文章转载自中启乘数,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




