摘要: 背景 進程模型數據庫,須要爲每一個會話指派獨立的進程與之服務,在鏈接數很是多,且大都是活躍鏈接時,進程調度浪費或引入的開銷甚至遠遠大於實際任務須要的開銷(例如上下文切換,MEMCPY等),性能降低會較爲嚴重。git
進程模型數據庫,須要爲每一個會話指派獨立的進程與之服務,在鏈接數很是多,且大都是活躍鏈接時,進程調度浪費或引入的開銷甚至遠遠大於實際任務須要的開銷(例如上下文切換,MEMCPY等),性能降低會較爲嚴重。github
PostgreSQL與Oracle Dedicate Server同樣,屬於進程模型。在很是高併發的狀況下,性能會降低比較厲害,一般社區版本能夠經過加鏈接池來解決,例如pgbouncer,可是加鏈接池也會帶來一些問題:sql
一、綁定變量沒法很好的知足,固然,PostgreSQL 11會增長相似Oracle cursor force的功能,內部將非綁定變量的SQL轉換爲綁定變量。數據庫
《PostgreSQL 11 preview - 強制auto prepared statment開關(自動化plan cache)(相似Oracle cursor_sharing force)》後端
二、鏈接池會使得跳數增長,增長了延遲。bash
三、數據庫防火牆配置的變化。從直接控制應用端來源,變成了鏈接池端來源。(除非修改鏈接池層的代碼,作到來源IP和端口透傳)併發
Oracle爲了解決性能問題,提出了shared server的概念,相似數據庫端的backend process pool,一個process可能服務於多個client。dom
PostgreSQL也能夠如法炮製,好比阿里雲RDS PG內核層面增長了內置的POOL。在高併發的狀況下,性能好不少。socket
一、測試64 ~ 16384個併發tcp
二、測試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.org/18/1388/
若是使用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測試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;
一、初始化
./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 &
一、初始化
./pgsql11/bin/pgbench -i -s 5000 --unlogged-tables
二、修改數據庫配置
vi $PGDATA/postgresql.conf synchronous_commit = off pg_ctl reload
三、測試一樣的腳本
鏈接數 | 社區版本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 |
---|---|---|
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 |
鏈接數 | 社區版本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 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 |
鏈接數 | 社區版本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 |
---|---|---|
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 |
鏈接數 | 社區版本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 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倍於社區版本。同時低併發的狀況下,性能不減,與社區版本至關。
本文爲雲棲社區原創內容,未經容許不得轉載。