资讯动态

  • 首页Our Projects十个客户端把轮询换成一条阻塞调用,备库CPU从57%降到38%

十个客户端把轮询换成一条阻塞调用,备库CPU从57%降到38%

2026-09-30 7232

十个客户端,同一个查询,反复问备库同一句话:我上次写的东西到了吗?两轮跑下来,备库CPU均值 57% 。把循环换成一条阻塞调用,还是十个客户端、同样的负载,CPU掉到 38% ,吞吐反而涨了。 这条阻塞调用叫 WAIT FOR LSN ,是 PostgreSQL 19 的新东西,该版本于 2026 年 9 月 24 日发布第四个 beta。它让应用可以直接问数据库:把这个连接挂住,直到某个特定的预写日志位置在这台服务器上到达指定状态,再返回。对着异步副本做读己之写一致性,以前一直能手工实现——写入后记下 WAL 位置,再去副本上轮询它。WAIT FOR 把这件事变成了一条语句。 搭建环境 用 postgres:19beta4 搭了一主一从的流复制环境。两个 Docker 容器,同一镜像,同一网络: docker network create pgwaitnetdocker run -d --name pg-primary --network pgwaitnet -p 15432:5432 \-e POSTGRES_PASSWORD=postgres -e POSTGRES_HOST_AUTH_METHOD=trust \postgres:19beta4 \postgres -c wal_level=replica -c max_wal_senders=10 -c hot_standby=on 在主库上创建复制角色和槽,为来自容器网络的复制连接和普通连接打开 pg_hba.conf,然后用 pg_basebackup -R 直接把基础备份做到备库的数据目录里,它会替我写好 standby.signal 和 primary_conninfo: docker exec pg-primary psql -U postgres -c \"CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'replpass';"docker exec pg-primary psql -U postgres -c \"SELECT pg_create_physical_replication_slot('standby_slot');"docker exec -u postgres pg-standby bash -c \"PGPASSWORD=replpass pg_basebackup -h pg-primary -U replicator \-D /var/lib/postgresql/19/docker -Fp -Xs -P -R -S standby_slot" 主库上的 pg_stat_replication 显示备库在几秒内就开始流复制,在这台机器上重放延迟大约 0.1ms。下面所有测试都跑在这对主从之上,从宿主机通过 TCP 连接,而不是走 docker exec。 那个头条数字,以及我为什么不完全信它 每个试验里,先在主库插一行、拿到对应的 LSN,再计时备库满足这个 LSN 需要多久,三种方式对比:带 1 毫秒睡眠的轮询、完全不休眠的忙轮询、以及一次 WAIT FOR LSN ... WITH (MODE 'standby_replay') 调用。每个方式跑 20 次试验,带睡眠的轮询重复三轮,另外两种重复两轮,取范围。 对着带睡眠的轮询,WAIT FOR 看起来是干净的 3 到 5 倍 胜出。但对着忙轮询,差距几乎消失——WAIT FOR 每一轮都还是略微领先,但领先的是零点几毫秒,不是倍数。一个从不睡眠的忙循环,在单连接、空闲备库上,发现 LSN 被重放的速度,和一个专门造出来的等待原语差不多。那个 3 到 5 倍,量的是那个随手定的 1 毫秒睡眠,不是这个特性。 十个客户端连续跑,才是它真正赢的地方 十个工作线程,每个循环做「主库插入、备库等待」,连续跑五秒,期间用 docker stats 采样备库 CPU。两轮平均下来:完成的工作更多,平均 CPU 大约是原来的三分之二。 这才是值得拿来规划的数字。忙轮询对一个客户端查一次写入来说没问题,但它不会闲着——每一个等待中的连接都是一个后端在紧循环里空转查询,十个这样的连接,会在那台承担副本读的机器上叠加起来。WAIT FOR 是把后端挂起,而不是让它空转。 需要说明的是,每轮五秒只采到两三个 CPU 样本,因为启动 docker stats --no-stream 本身有开销,所以 CPU 数字当作方向性参考,别抠到百分点;每秒完成数那个数字是直接计数而非采样得来的,更可信。 喂错输入,它全拒了 把能想到的错误输入都试了一遍: 垃圾 LSN:报错 invalid input syntax for type pg_lsn:

about image

订阅我们的时事通讯

获取更多更新