这类问题并不是个例,我们一个共享单车客户的实例和一个考试系统实例, 发现了该问题,用户反馈在业务高峰期,数据库吞吐量比平时还低。同时,我们发现,客户碰到该问题后的解决方案都是,增加连接池大小,但几乎没效果。

通过分析,我们发现,在大并发场景下

  1. 数据库实例的每一个连接执行 SQL 时都会开启一个事务(只读事务和读写事务),同时开启事务较多时,数据的可见性判断复杂程度会急剧增加, 通过 perf top 可以看到,函数 XidInMVCCSnapshot 的占用超过 90%。这是性能问题的主要原因。

另外,之前提到的,这样的场景下,大多数 DBA 会选择增加客户端程序的连接池大小,希望通过加大并发提高系统吞吐量。根据分析,这只会徒劳加大同时开启的事务数,对提高系统吞吐量帮助不大。

当该问题发生时,虽然开启了数千个连接,也是业务的高峰期,但整个实例吞吐量却十分低下,业务很难走出高峰期。

针对该问题,RDS PostgreSQL 在内核层面提出解决方案

  1. 在 PostgreSQL 内部创建4个独立的队列
    • a dml 队列
    • b autocommit 语句队列
    • c 事务块队列
  2. 数据库执行 SQL 时,会先把他们分类,然后按照 SQL 的类型进行排队执行。

  3. 对于交易型业务,控制他们的并发程度,可以让它们很快的执行完成,下一章有性能数据。

  4. 交易型业务的并发程度可以支持设定,建议并发度和实例规格的的 CPU 数相当。

下面,让我们来看看 RDS for PostgreSQL 应用该特性后和社区 PostgreSQL 的性能测试数据

测试场景 pgbench tpc-b

  1. 社区版本的 PostgreSQL 随着连接数增加,TPS 会急剧降低,RT 会显著增加。

本文从原理角度出发,解析了大并发条件下 PostgreSQL 系统吞吐量的原因,也给出了RDS PostgreSQL 解决该问题的思路,欢迎大家使用该特性!