PgSQL · 應用案例 · 阿里雲 RDS PostgreSQL 高併發特性 vs 社區版本

摘要: 背景 進程模型數據庫,須要爲每一個會話指派獨立的進程與之服務,在鏈接數很是多,且大都是活躍鏈接時,進程調度浪費或引入的開銷甚至遠遠大於實際任務須要的開銷(例如上下文切換,MEMCPY等),性能降低會較爲嚴重。sql

背景
進程模型數據庫,須要爲每一個會話指派獨立的進程與之服務,在鏈接數很是多,且大都是活躍鏈接時,進程調度浪費或引入的開銷甚至遠遠大於實際任務須要的開銷(例如上下文切換,MEMCPY等),性能降低會較爲嚴重。數據庫

PostgreSQL與Oracle Dedicate Server同樣,屬於進程模型。在很是高併發的狀況下,性能會降低比較厲害,一般社區版本能夠經過加鏈接池來解決,例如pgbouncer,可是加鏈接池也會帶來一些問題:後端

一、綁定變量沒法很好的知足,固然,PostgreSQL 11會增長相似Oracle cursor force的功能,內部將非綁定變量的SQL轉換爲綁定變量。bash

《PostgreSQL 11 preview - 強制auto prepared statment開關(自動化plan cache)(相似Oracle cursor_sharing force)》併發

二、鏈接池會使得跳數增長,增長了延遲。dom

三、數據庫防火牆配置的變化。從直接控制應用端來源,變成了鏈接池端來源。(除非修改鏈接池層的代碼,作到來源IP和端口透傳)socket

Oracle爲了解決性能問題,提出了shared server的概念,相似數據庫端的backend process pool,一個process可能服務於多個client。tcp

PostgreSQL也能夠如法炮製,好比阿里雲RDS PG內核層面增長了內置的POOL。在高併發的狀況下,性能好不少。高併發

測試CASE
一、測試64 ~ 16384個併發post

二、測試TPC-B,包含5億數據量。

三、測試logged table與unlogged table

四、測試對比社區PostgreSQL 10 與 阿里雲PostgreSQL 10

測試環境準備
一、數據庫使用huge page

《PostgreSQL Huge Page 使用建議 - 大內存主機、實例注意》

二、修改pgbench,支持超過1000個鏈接的測試

《PostgreSQL 11 preview - pgbench 支持大於1000連接(ppoll()代替select())》

https://commitfest.postgresql...

《從PostgreSQL支持100萬個鏈接聊起》

若是使用ppoll,則pstack pgbench能夠看到相似以下信息

Thread 1 (Thread 0x7f3f4d89d840 (LWP 116621)):    
#0  0x00007f3f4ca4569d in poll () from /lib64/libc.so.6    
#1  0x00007f3f4d45a9cf in poll (__timeout=-1, __nfds=1, __fds=0x7ffcd6e13c80) at /usr/include/bits/poll2.h:46    
#2  pqSocketPoll (end_time=-1, forWrite=0, forRead=28675152, sock=<optimized out>) at fe-misc.c:1129    
#3  pqSocketCheck (conn=conn@entry=0x1b58c50, forRead=forRead@entry=1, forWrite=forWrite@entry=0, end_time=end_time@entry=-1) at fe-misc.c:1071    
#4  0x00007f3f4d45aa50 in pqWaitTimed (forRead=forRead@entry=1, forWrite=forWrite@entry=0, conn=conn@entry=0x1b58c50, finish_time=finish_time@entry=-1) at fe-misc.c:1003    
#5  0x00007f3f4d454012 in connectDBComplete (conn=0x1b58c50) at fe-connect.c:1902    
#6  PQconnectdbParams (keywords=<optimized out>, values=<optimized out>, expand_dbname=<optimized out>) at fe-connect.c:542    
#7  0x000000000040576a in doConnect ()    
#8  0x0000000000406e29 in threadRun ()    
#9  0x0000000000403a1b in main ()

三、修改系統配置,保證有足夠的fd, proc等

《PostgreSQL 10 + PostGIS + Sharding(pg_pathman) + MySQL(fdw外部表) on ECS 部署指南(適合新用戶) - 珍藏級》

四、postgresql.conf 通用配置

listen_addresses = '0.0.0.0'    
max_connections = 30000    
superuser_reserved_connections = 13    
unix_socket_directories = '/tmp,.'    
tcp_keepalives_idle = 60    
tcp_keepalives_interval = 10    
tcp_keepalives_count = 0    
shared_buffers = 32GB    
huge_pages = on    
maintenance_work_mem = 1GB    
dynamic_shared_memory_type = posix    
vacuum_cost_delay = 0    
bgwriter_delay = 10ms    
bgwriter_lru_maxpages = 500    
effective_io_concurrency = 0    
max_parallel_workers_per_gather = 0    
wal_level = minimal    
fsync = on    
synchronous_commit = on    
full_page_writes = on    
wal_buffers = 32MB    
checkpoint_timeout = 15min    
max_wal_size = 64GB    
min_wal_size = 16GB    
checkpoint_completion_target = 0.1    
max_wal_senders = 0    
random_page_cost = 1.2    
log_destination = 'csvlog'    
logging_collector = on    
log_truncate_on_rotation = on    
log_checkpoints = on    
log_connections = on    
log_disconnections = on    
log_error_verbosity = verbose       
log_timezone = 'PRC'    
autovacuum = on    
log_autovacuum_min_duration = 0    
autovacuum_freeze_max_age = 900000000    
autovacuum_multixact_freeze_max_age = 900000000    
autovacuum_vacuum_cost_delay = 0ms    
vacuum_freeze_min_age = 500000    
vacuum_freeze_table_age = 1500000000    
vacuum_multixact_freeze_min_age = 5000000    
vacuum_multixact_freeze_table_age = 1500000000    
datestyle = 'iso, mdy'    
timezone = 'PRC'    
lc_messages = 'en_US.utf8'    
lc_monetary = 'en_US.utf8'    
lc_numeric = 'en_US.utf8'    
lc_time = 'en_US.utf8'    
default_text_search_config = 'pg_catalog.english'

五、社區版本與阿里雲版本的差別配置
native

port = 1921

aliyun

port = 1999    
shared_preload_libraries = 'pg_concurrency_control.so'    
pg_concurrency_control.query_concurrency=64    
pg_concurrency_control.bigquery_concurrency=64    
pg_concurrency_control.transaction_concurrency=64    
pg_concurrency_control.autocommit_concurrency=64

測試TPC-B
TPC-B測試SQL以下

scale=5000

\set aid random(1, 100000 * :scale)    
\set bid random(1, 1 * :scale)    
\set tid random(1, 10 * :scale)    
\set delta random(-5000, 5000)    
BEGIN;    
UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;    
SELECT abalance FROM pgbench_accounts WHERE aid = :aid;    
UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;    
UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;    
INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);    
END;

logged table
一、初始化

./pgsql11/bin/pgbench -i -s 5000

二、表大小

postgres=# \dt+    
                          List of relations    
 Schema |       Name       | Type  |  Owner   |  Size   | Description     
--------+------------------+-------+----------+---------+-------------    
 public | pgbench_accounts | table | postgres | 63 GB   |     
 public | pgbench_branches | table | postgres | 216 kB  |     
 public | pgbench_history  | table | postgres | 0 bytes |     
 public | pgbench_tellers  | table | postgres | 2200 kB |     
(4 rows)

三、社區版本測試腳本以下

vi test_native.sh    
    
#!/bin/bash    
export PGHOST=/tmp    
export PGPORT=1921    
export PGUSER=postgres    
export PGDATABASE=postgres    
    
Y=32    
for ((i=1;i<=7;i++))    
do    
X=$((Y*2))    
psql -c "vacuum freeze"    
psql -c "checkpoint"    
./pgsql11/bin/pgbench -M prepared -n -r -P 3 -c $X -j 64 -T 300 > ./test_native_$X.log 2>&1    
Y=X    
done    
    
psql -c "vacuum freeze"    
psql -c "checkpoint"    
./pgsql11/bin/pgbench -M prepared -n -r -P 3 -c 8192 -j 128 -T 600 > ./test_native_8192.log 2>&1    
    
psql -c "vacuum freeze"    
psql -c "checkpoint"    
./pgsql11/bin/pgbench -M prepared -n -r -P 3 -c 16384 -j 256 -T 600 > ./test_native_16384.log 2>&1

測試方法

chmod 700 ./test_native.sh     
nohup ./test_native.sh >/dev/null 2>&1 &

五、阿里雲版本測試腳本以下

vi test_aliyun.sh    
    
#!/bin/bash    
export PGHOST=/tmp    
export PGPORT=1999    
export PGUSER=postgres    
export PGDATABASE=postgres    
    
Y=32    
for ((i=1;i<=7;i++))    
do    
X=$((Y*2))    
psql -c "vacuum freeze"    
psql -c "checkpoint"    
./pgsql11/bin/pgbench -M prepared -n -r -P 3 -c $X -j 64 -T 300 > ./test_aliyun_$X.log 2>&1    
Y=X    
done    
    
psql -c "vacuum freeze"    
psql -c "checkpoint"    
./pgsql11/bin/pgbench -M prepared -n -r -P 3 -c 8192 -j 128 -T 600 > ./test_aliyun_8192.log 2>&1    
    
psql -c "vacuum freeze"    
psql -c "checkpoint"    
./pgsql11/bin/pgbench -M prepared -n -r -P 3 -c 16384 -j 256 -T 600 > ./test_aliyun_16384.log 2>&1

測試方法

chmod 700 ./test_aliyun.sh     
nohup ./test_aliyun.sh >/dev/null 2>&1 &    
unlogged table

一、初始化

./pgsql11/bin/pgbench -i -s 5000 --unlogged-tables

二、修改數據庫配置

vi $PGDATA/postgresql.conf    
    
synchronous_commit = off    
    
pg_ctl reload

三、測試一樣的腳本

性能對比
1 logged table對比
一、TPS對比
鏈接數 社區版本TPS 阿里雲版本TPS 社區版本TPS
(過濾首尾干擾值) 阿里雲版本TPS
(過濾首尾干擾值)
64 69216 67853 無干擾 無干擾
128 69211 65712 無干擾 無干擾
256 62964 62775 無干擾 無干擾
512 44595 53382 46141 54988
1024 35055 44295 37022 48679
2048 26791 38881 30327 44358
4096 24218 26990 32023 39086
8192 7064 24304 18611 34316
16384 5046 12478 10020 29499
1.6萬併發時,約3倍於社區版本。

二、事務總體RT對比
鏈接數 社區版本RT 阿里雲版本RT
64 0.923 ms 0.941 ms
128 1.839 ms 1.936 ms
256 4.010 ms 4.021 ms
512 11.151 ms 9.269 ms
1024 27.475 ms 21.070 ms
2048 67.295 ms 46.063 ms
4096 127.923 ms 104.689 ms
8192 999.236 ms 239.466 ms
16384 1594.185 ms 577.913 ms
三、實際SQL RT對比
鏈接數 社區版本RT 阿里雲版本RT
64 0.428 ms 0.465 ms
128 0.698 ms 0.734 ms
256 1.784 ms 1.658 ms
512 4.736 ms 4.378 ms
1024 11.082 ms 8.664 ms
2048 37.258 ms 8.007 ms
4096 65.486 ms 7.395 ms
8192 818.411 ms 6.472 ms
16384 1183.571 ms 4.927 ms
1.6萬鏈接時,真實SQL響應速度約240倍於社區版本。

四、RT 標準方差對比
鏈接數 社區版本RT DEV 阿里雲版本RT DEV
64 2.960 ms 2.863 ms
128 7.559 ms 4.914 ms
256 6.595 ms 6.090 ms
512 11.810 ms 8.704 ms
1024 30.656 ms 46.411 ms
2048 88.371 ms 68.239 ms
4096 183.815 ms 140.255 ms
8192 20114.612 ms 345.584 ms
16384 2404.222 ms 1116.238 ms
五、創建完全部鏈接的耗時對比
鏈接數 社區版本 阿里雲版本
64 0 s 0 s
128 0 s 0 s
256 4.8 s 5 s
512 8.9 s 11.3 s
1024 18.5 s 27.4 s
2048 36.3 s 37.8 s
4096 73.5 s 93.6 s
8192 150.9 s 168.6 s
16384 306 s 341.8 s
六、釋放完全部鏈接的耗時對比
鏈接數 社區版本 阿里雲版本
64 0 s 0 s
128 0 s 0 s
256 0 s 0 s
512 0 s 0 s
1024 0 s 0 s
2048 0 s 0 s
4096 0 s 0 s
8192 594 s 9 s
16384 21 s 24 s
2 unlogged table對比
一、TPS對比
鏈接數 社區版本TPS 阿里雲版本TPS 社區版本TPS
(過濾首尾干擾值) 阿里雲版本TPS
(過濾首尾干擾值)
64 99086 95932 無干擾 無干擾
128 86807 86719 無干擾 無干擾
256 69805 74371 70766 75143
512 49147 59423 50369 61153
1024 42295 45883 44798 48910
2048 32147 38698 36729 44552
4096 23556 27604 31504 38334
8192 17037 24524 22937 34553
16384 196 12668 1943 30273
二、事務總體RT對比
鏈接數 社區版本RT 阿里雲版本RT
64 0.644 ms 0.666 ms
128 1.466 ms 1.466 ms
256 3.617 ms 3.391 ms
512 10.115 ms 8.343 ms
1024 22.761 ms 20.864 ms
2048 55.771 ms 45.903 ms
4096 130.195 ms 107.858 ms
8192 356.904 ms 239.312 ms
16384 66640.630 ms 570.207 ms
三、實際SQL RT對比
鏈接數 社區版本RT 阿里雲版本RT
64 0.475 ms 0.501 ms
128 0.934 ms 0.854 ms
256 2.109 ms 1.842 ms
512 4.656 ms 4.587 ms
1024 9.837 ms 8.69 ms
2048 36.882 ms 7.928 ms
4096 67.513 ms 7.522 ms
8192 201.208 ms 6.536 ms
16384 65428.243 ms 4.811 ms
四、RT 標準方差對比
鏈接數 社區版本RT DEV 阿里雲版本RT DEV
64 2.941 ms 1.767 ms
128 4.445 ms 2.763 ms
256 5.515 ms 2.775 ms
512 11.424 ms 4.447 ms
1024 28.950 ms 16.575 ms
2048 87.051 ms 52.400 ms
4096 200.132 ms 149.614 ms
8192 403.771 ms 358.461 ms
16384 462277.689 ms 1161.376 ms
五、創建完全部鏈接的耗時對比
鏈接數 社區版本 阿里雲版本
64 0 s 0 s
128 0 s 0 s
256 4.9 s 5.3 s
512 9.4 s 10.2 s
1024 18.5 s 20.2 s
2048 37.6 s 40 s
4096 75 s 81.3 s
8192 151.6 s 168.4 s
16384 312.1 s 341.5 s
六、釋放完全部鏈接的耗時對比
鏈接數 社區版本 阿里雲版本
64 0 s 0 s
128 0 s 0 s
256 0 s 0 s
512 0 s 0 s
1024 0 s 0 s
2048 0 s 0 s
4096 3 s 3 s
8192 6 s 9 s
16384 3312 s 27 s
小結
進程模型數據庫,須要爲每一個會話指派獨立的進程與之服務,在鏈接數很是多,且大都是活躍鏈接時,進程調度浪費或引入的開銷甚至遠遠大於實際任務須要的開銷(例如上下文切換,MEMCPY等),性能降低會較爲嚴重。

阿里雲RDS PG,採用與Oracle Shared Server模式相似的方案,解決了進程模式在高併發的狀況下性能降低的問題。

在超過1萬個活躍併發的狀況下,阿里雲RDS PG的TPC-B測試指標依舊可以保持15萬左右的QPS (消除干擾項),吞吐能力是社區版本的3倍。同時,在低併發的狀況下,性能不減,與社區版本至關。

具體測試結果分析:

一、阿里雲RDS PG在高併發下,TPS相比社區版本好不少,更加平穩。

二、阿里雲RDS PG引入了POOL機制後,響應延遲,抖動相比社區版本低了不少。

三、啓用POOL後,整個事務的RT,相比社區版本下降,使得整個處理吞吐獲得提高。

四、啓用POOL機制,使得一個事務中,真正執行SQL的時間大大縮短。同時還避免了鎖等待的問題。

16384個鏈接,社區版本

1.750  BEGIN;    
 21.531  UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;    
  0.745  SELECT abalance FROM pgbench_accounts WHERE aid = :aid;    
461.077  UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;    
700.583  UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;    
  1.958  INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);    
408.864  END;

16384個鏈接,阿里雲版本

559.291  BEGIN;    
  2.359  UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;    
  1.223  SELECT abalance FROM pgbench_accounts WHERE aid = :aid;    
  1.191  UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;    
  2.310  UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;    
  0.981  INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);    
 13.695  END;

對比以上兩個版本的事務BEGIN的耗費時間、SQL執行時間的分佈:

社區版本的SQL執行時間耗時更高(基本達到了500毫秒左右);

阿里雲的PG版本,SQL執行時間很是短(基本都在1毫秒左右)。

實際的DML SQL執行越久,持鎖就越久,併發1萬多時,社區版本PG出現較多WAITING狀態,就能夠說明問題。

0:00.18 postgres: postgres postgres [local] UPDATE waiting    
0:02.62 postgres: postgres postgres [local] UPDATE waiting    
0:00.15 postgres: postgres postgres [local] UPDATE waiting    
0:00.17 postgres: postgres postgres [local] UPDATE waiting    
0:00.12 postgres: postgres postgres [local] UPDATE waiting    
0:00.11 postgres: postgres postgres [local] UPDATE waiting    
..............................  
0:00.13 postgres: postgres postgres [local] COMMIT            
0:00.13 postgres: postgres postgres [local] UPDATE waiting    
0:00.13 postgres: postgres postgres [local] UPDATE waiting    
0:00.16 postgres: postgres postgres [local] UPDATE waiting    
0:00.14 postgres: postgres postgres [local] UPDATE waiting    
.....................

阿里雲RDS PG內置POOL,不會致使SQL執行時間變長。所以有效的避免了持有資源鎖的問題,是的真實的SQL RT很是的平穩。

鏈接數 社區版本RT 阿里雲版本RT
64 0.475 ms 0.501 ms
128 0.934 ms 0.854 ms
256 2.109 ms 1.842 ms
512 4.656 ms 4.587 ms
1024 9.837 ms 8.69 ms
2048 36.882 ms 7.928 ms
4096 67.513 ms 7.522 ms
8192 201.208 ms 6.536 ms
16384 65428.243 ms 4.811 ms
五、啓用POOL後,16384個鏈接高併發下,收尾時長縮短。從3312秒縮短到了27秒。

六、進程模式,創建鏈接比較耗時,若是業務上須要短期內建立大量鏈接,也是一個瓶頸。好比建立16384個鏈接,串行建立,所有創建完16384個鏈接大概須要花費300秒。這樣的業務,建議採用業務層鏈接池,而且配置較少的後端鏈接。

七、pgbench在統計TPS時,從全部鏈接創建完成,到全部鏈接退出,這之間產生的TPS。當須要創建不少鏈接或釋放不少鏈接時,可能會耗時比較久,致使實際測試的性能不許,特別是在8000個鏈接以上時,斷開鏈接過程當中,TPS降低比較明顯,而且會被統計進去,實測600秒,到1000多秒才完成統計,詳見LOG。

八、阿里雲RDS PG內置POOL,相比外置鏈接池,還有一個好處是「不會影響綁定變量的使用,也不會引入新的跳數,同時不會影響數據庫pg_hba.conf防火牆的配置」。

在超過1萬個活躍併發的狀況下,阿里雲RDS PG的TPC-B測試指標依舊可以保持15萬左右的QPS (消除干擾項),吞吐能力是社區版本的3倍。真實SQL執行響應速度240倍於社區版本。同時低併發的狀況下,性能不減,與社區版本至關。

原文連接

相關文章
相關標籤/搜索