我已经设置了类似于默认设置的 doobie + hikaricp。通过调试日志,我可以看到有多少连接处于活动/空闲状态,这也反映了 pg_stat_activity 使用此查询返回的内容
SELECT
pid,
query,
query_start,
state
FROM pg_stat_activity;
HikariPool-1 - Pool stats (total=10, active=4, idle=6, waiting=0)
我的应用程序主要通过在提交前通过由 3 个插入和 2 个选择组成的事务将它们存储在数据库中来处理来自流的消息。
以下是使用 hikariCP 创建交易者的方式:
val hikariConfig = new HikariConfig()
hikariConfig.setJdbcUrl(dbUrl)
hikariConfig.setDriverClassName("org.postgresql.Driver")
hikariConfig.setUsername(dbUser)
hikariConfig.setPassword(dbPassword)
hikariConfig.setMaximumPoolSize(10)
hikariConfig.setAutoCommit(false)
hikariConfig.addDataSourceProperty("socketTimeout", "30")
val dataSource: HikariDataSource = new HikariDataSource(hikariConfig)
val transactor: HikariTransactor[IO] = HikariTransactor[IO](dataSource)
然后将此事务传递到任何地方以处理数据库事务:
import doobie._
import doobie.implicits._
import doobie.postgres.implicits._
val query = for {
_ <- sql"insert into foo (id, value) values (fooId, 'b')".update.run
_ <- sql"insert into bar (id, value) values (barId, 'b')".update.run
_ <- sql"select * from bar where id = $barId".query[Bar].unique
_ <- sql"insert into bazz (id, value1, value2) values (bazzId, fooId, barId)".update.run
_ <- sql"select * from bazz where id = $barId".query[Bazz].unique
} yield ()
query.transact(transactor).unsafeToFuture()
我看到的问题是查询似乎很快,但插入吞吐量很慢。
我注意到的几点:
检查 pg_stat_activity,我看到许多 COMMIT 查询(多于插入),每个查询都需要约 90 毫秒 - 200 毫秒。
SELECT pid, now() - pg_stat_activity.query_start AS 持续时间,查询,query_start,state FROM pg_stat_activity where state <> 'idle' order by duration desc;
上面的 pg_stat_activity 查询一次只返回 4-8 行,大部分结果是 query = 'COMMIT'。
从一个空流开始,吞吐量可以高达每分钟 30k 条消息。但是,在 15-20 分钟后,吞吐量下降到每分钟 3k 条消息,并且不会重置恢复,直到流为空数小时后重新启动应用程序或扩展应用程序的更多实例并不能提高吞吐量。
数据库和应用程序的 CPU (10%) / Mem 使用率 (16%) 都很低,所以理论上吞吐量应该可以更高,哪些方面值得研究?
目前使用 doobie 0.5.4,hikariCP 0.5.4
更新:根据 Laurenz 的建议,在 rds 数据库上提出commit_delay
和commit_siblings
设置,将高吞吐量的时间从 30 分钟延长到 60 分钟,然后再像以前一样长时间降低吞吐量。我开始测试提升max_wal_size
,但这似乎导致峰值吞吐量(有时非常低)不接近原始启动率。