jdbc - HikariCP:看到低插入吞吐量,而 DB/App cpu % 仍然很低
jdbc - HikariCP: Seeing low insert thoughput while DB/App cpu % is still low
我设置了 doobie + hikaricp,其设置与默认设置类似。通过调试日志记录,我可以看到有多少连接处于活动/空闲状态,这也反映了此查询 pg_stat_activity returns
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 查询(多于插入),每个查询都在 ~90ms - 200ms 之间。
SELECT pid, now() - pg_stat_activity.query_start AS duration, query, query_start, state FROM pg_stat_activity where state <> 'idle' order by持续时间描述;
上面pg_stat_activity一次只查询returns4-8行,大部分结果都是查询='COMMIT'.
从空流开始,吞吐量可以高达每分钟 30k 条消息。但是,在 15-20 分钟后,吞吐量下降到每分钟 3k 条消息,并且不会重置恢复,直到流为空数小时后重新启动应用程序或扩展应用程序的更多实例不会提高吞吐量。
数据库和应用程序的 CPU (10%) / 内存使用率 (16%) 都很低,因此理论上吞吐量应该可以更高,哪些方面值得研究?
当前使用 doobie 0.5.4、hikariCP 0.5.4
更新:根据 Laurenz 的建议提高了 rds 数据库的 commit_delay
和 commit_siblings
设置,这将高吞吐量的时间从 30 分钟延长至 60 分钟,然后像以前一样在吞吐量长时间下降之前。
我开始测试提高 max_wal_size
但这似乎导致更高的吞吐量(有时非常低)不接近原始启动率。
如果 COMMIT
花费很长时间,则表明您的 I/O 系统已过载。
如果问题不是 I/O 卷,可能是来自许多事务的许多 WAL 同步请求。
部分选项:
用更少、更大的事务执行工作。
如果您可以承受在发生崩溃时丢失半秒的已提交事务,请将 synchronous_commit
设置为 off
。
如果不能选择丢失已提交的事务,请调整 commit_delay
和 commit_siblings
。这会使交易时间稍长,但可以减少 I/O 负载。
我设置了 doobie + hikaricp,其设置与默认设置类似。通过调试日志记录,我可以看到有多少连接处于活动/空闲状态,这也反映了此查询 pg_stat_activity returns
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 查询(多于插入),每个查询都在 ~90ms - 200ms 之间。
SELECT pid, now() - pg_stat_activity.query_start AS duration, query, query_start, state FROM pg_stat_activity where state <> 'idle' order by持续时间描述;
上面pg_stat_activity一次只查询returns4-8行,大部分结果都是查询='COMMIT'.
从空流开始,吞吐量可以高达每分钟 30k 条消息。但是,在 15-20 分钟后,吞吐量下降到每分钟 3k 条消息,并且不会重置恢复,直到流为空数小时后重新启动应用程序或扩展应用程序的更多实例不会提高吞吐量。
数据库和应用程序的 CPU (10%) / 内存使用率 (16%) 都很低,因此理论上吞吐量应该可以更高,哪些方面值得研究?
当前使用 doobie 0.5.4、hikariCP 0.5.4
更新:根据 Laurenz 的建议提高了 rds 数据库的 commit_delay
和 commit_siblings
设置,这将高吞吐量的时间从 30 分钟延长至 60 分钟,然后像以前一样在吞吐量长时间下降之前。
我开始测试提高 max_wal_size
但这似乎导致更高的吞吐量(有时非常低)不接近原始启动率。
如果 COMMIT
花费很长时间,则表明您的 I/O 系统已过载。
如果问题不是 I/O 卷,可能是来自许多事务的许多 WAL 同步请求。
部分选项:
用更少、更大的事务执行工作。
如果您可以承受在发生崩溃时丢失半秒的已提交事务,请将
synchronous_commit
设置为off
。如果不能选择丢失已提交的事务,请调整
commit_delay
和commit_siblings
。这会使交易时间稍长,但可以减少 I/O 负载。