PostgreSQL的M VCC 实现机制是采用数据块中生成多个副本的方式的,这种机制被很多 D BA 和架构师认为是 PostgreSQL数据库在大型高负载系统中的一个巨大的缺陷。实际上不只是PostgreSQL采用了多副本行元来实现M VCC ,目前比较热门的基于 LSM-Tree存储引擎的数据库系统(比如阿里的Oceanbase,PingCAP的TiDB)也采用了这种方式。L SM- Tree需要通过Compare And Merge这种开销更大的方式来进行老元组的合并重组,而PostgreSQL使用Vacuum机制来进行数据整理。 可能很多朋友都认为 Vacuum的开销很大,对数据库表的性能影响也很大,甚至在出现过Vacuum影响业务系统之后,关闭了AutoVacuu m 。在 Postgre SQL 9之前,Vacuum的算法确实对高负载数据库的影响很大,甚至那时候笔者认为PostgreSQL的M VCC 的缺陷会影响 PostgreSQL在企业级应用中的使用。不过随着这些年PostgreSQL数据库的快速发展,每个版本对Vacuum的算法都有了极大的改善,在目前硬件性能极大提升与PostgreSQL Vacuum的算法的优化双重作用下,目前Vacuum对高负载数据库的影响也越来越低了。 可能还有一些朋友可以举出一些反例,说我们的数据库因为 Vacuum而导致数据库性能出现严重问题了。确实可能会出现这样的反例,不过如果仔细分析一下,通过对PostgreSQL数据库的性能优化,这些反例中遇到的问题大多数都是可以解决的。 前阵子我在网上看到过一个某互联网汽车租赁公司的案例,他们的 PostgreSQL数据库的AutoVacuum出现了严重的性能问题,租车订单表每天要消耗几百万个x id ,而每天的 autovacuum 只能回收其中 70%的x id ,这意味着一个十分严重的问题, x id wraps 的问题。当系统运行一段时间之后,就必须进行停库维护,通过 v acuum 来完成 x id 的完全回收,从而防止未回收 x id 达到 20亿这个可能导致数据库停库的问题出现。当时客户已经在讨论是不是要通过更换数据库来彻底解决这个问题了,不过后来的一次数据库优化让这个系统摆脱了x id wraps 困境。 整个优化工作也十分简单。仅仅是一些 Postgresql参数的调整:
|
序号 |
参数 |
调整值 |
|
1 |
autovacuum_work_mem |
2 GB |
|
2 |
autovacuum_vacuum_cost_limit |
2 000/ 最终调整为 3000 (对于使用 S SD 盘的环境,缺省的 200太保守了) |
|
3 |
maintenance_work_mem |
1 GB |
|
4 |
work_mem |
1 6MB |
|
5 |
autovacuum_max_workers |
5 |
通过上面的参数调整后,每天可回收的 xid 超过了 5亿,x id wraps 问题得到了彻底的解决。 实际上我们遇到的很多 PostgreSQL的问题主要是因为我们对PostgreSQL数据库的认知的不足,从而导致我们遇到问题后不知道该如何去解决。不过PostgreSQL的MVCC带来的负面问题也并不是总能够通过调整数据库参数来解决的。事实上,有些应用对数据库的随意使用是导致很多较为难以解决的数据库性能问题的最主要的原因。记得十多年前帮一个运营商解决的b uffer busy waits 导致的性能问题,最终也是把那张 u pdate 十分频繁的花费余额表改造成内存数据库才得以彻底的解决。如果那个场景用 PostgreSQL来实现,哪怕是十多年后的硬件环境下,因为M VCC 实现技术方面的缺陷,恐怕 P G 数据库依然是搞不定的。 所以说虽然我们能够通过数据库优化的手段去解决大部分的 PostgreSQL数据库的问题,我们还需要应用开发者了解数据库存在的一些缺陷,从而在应用架构设计以及应用开发时能够尽可能规避PostgreSQL的一些缺陷,让应用系统运行的更好。
