pgbouncer連線池
背景
在做一站式專案的過程中發現當大量的服務連線到同一個庫,以及大量的開發人員連線到同一個庫的時候,資料庫的2000
連線不夠。當然和使用c3p0
連線池有關係,以前預設都是將最大最小連線數設定為一樣,但現在都是用druid
連線池,所以最大和最小連線數不必設定為一樣。這樣可以減少連線數,當然這只是一方面,今天我們要說的是當有大量連線的時候pgbouncer
連線池的使用
如果沒有資料庫連線池
資料庫在沒有任何連線池的情況下,應用程式必須直接訪問資料庫來建立連線。開啟的一個連線的消耗,關閉一個連線的消耗,而這樣的消耗,伴隨著你開啟的連線越多,則消耗的就越多。還有短連線,可能同時併發的連線多,但佔用這個連線的時間很短。這就會引起另一個問題,你設定的連線數和突入起來的連線數不匹配的情況,最後就會造成拒絕連線的問題。
所以這就對資料庫的連線提出一個問題,複用,連線的複用對資料庫非常重要,這可以降低某些快速連線,快速斷開的連線的資料庫訪問對資料庫效能的消耗和產生的一些不必要的麻煩。
版本
PgBouncer 1.11.x
已經可以支援PostgreSQL 12
PostgreSQL 13
新功能匹配
pgbouncer的作用
既然應用已經使用了durid
連線池了,那麼pgbouncer
還有什麼用呢?
雖然我們每個服務都使用了連線池,但是各個服務之間是相互獨立的,當有許多的服務去連一個數據庫的時候,對資料庫來說這麼多連線還是不受保護的。(如果資料庫僅有少數的應用連線,那麼可以只使用程式自帶的連線池就夠了,但如果有大量的服務在連線資料庫,資料庫其實還是沒有收到連線池的保護
)
另外,PG是多程序結構,每個程序大概耗費10MB左右記憶體,所以連線越多,耗費的記憶體也就越多。
使用軟體架構池對資料庫進行連線
使用durid
連線池如下面所示,當有大量的應用連線資料庫的時候其實對資料庫來說這些連線還是沒有受到控制
使用pgbouncer連線池的方式對資料庫進行連線
pgbouncer
是在資料庫端加了一個池子,也就是所有的連線經過資料庫都需要進入這個池子
採用pgbouncer
來管理連線池的話,相當於在眾多的軟體druid連線池下面加了一個大的池子,來管理連線。這樣來保證資料庫的穩性。
當然,pg
的連線池不僅僅pgbouncer
、還有pgpool
,pgbouncer
功能更加精簡,配置簡單。
安裝配置:
安裝參考安裝文件
資料庫裡面對應的資料庫資訊需要在pgbouncer.ini
配置裡面配置,listen_port
是連線池對外的埠,應用配置時需要配置listen_port
,如果直接配置資料庫的埠,那麼就沒有通過連線池
vi pgbouncer.ini
[databases]
pgbenchdb = host=localhost port=6543 user=sa dbname=pgbenchdb password=xxxx connect_query='SELECT 1' pool_size=100
[pgbouncer]
logfile = /etc/pgbouncer/pgbouncer.log
pidfile = /etc/pgbouncer/pgbouncer.pid
auth_type = hba
auth_file = /etc/pgbouncer/userlist.txt
auth_hba_file =/etc/pgbouncer/pg_hba.conf
admin_users = sa
stats_users = sa
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 228
;min_pool_size = 0
reserve_pool_size = 10
listen_addr = 0.0.0.0
listen_port = 5432
--登入到pgbouncer,可以看到對應的版本為1.12.0
[thunisoft@sqlfx ~]$ psql -Usa -d pgbouncer -p 5432
psql (11.1, server 1.12.0/bouncer)
Type "help" for help.
--show help
pgbouncer=# show help;
NOTICE: Console usage
DETAIL:
SHOW HELP|CONFIG|DATABASES|POOLS|CLIENTS|SERVERS|USERS|VERSION
SHOW FDS|SOCKETS|ACTIVE_SOCKETS|LISTS|MEM
SHOW DNS_HOSTS|DNS_ZONES
SHOW STATS|STATS_TOTALS|STATS_AVERAGES|TOTALS
SET key = arg
RELOAD
PAUSE [<db>]
RESUME [<db>]
DISABLE <db>
ENABLE <db>
RECONNECT [<db>]
KILL <db>
SUSPEND
SHUTDOWN
SHOW
pgbouncer=# show databas;
ERROR: invalid command 'show databas;', use SHOW HELP;
pgbouncer=# show databases;
name | host | port | database | force_user | pool_size | reserve_pool | pool_mode | max_connections | current_connections | paused | disabled
-----------+---------------+------+-----------+------------+-----------+--------------+-----------+-----------------+---------------------+--------+----------
pgbenchdb | xxxxxx | 6543 | pgbenchdb | sa | 100 | 10 | | 0 | 0 | 0 | 0
pgbouncer | | 5432 | pgbouncer | pgbouncer | 2 | 0 | statement | 0 | 0 | 0 | 0
(2 rows)
效能測試
短連結
使用連線池:5985tps
[thunisoft@sqlfx ~]$ pgbench -M extended -v -r -P 1 -S -C -c 100 -j 100 -T 60 -p 5432 -Usa pgbenchdb
starting vacuum...end.
starting vacuum pgbench_accounts...end.
progress: 1.0 s, 6175.1 tps, lat 6.959 ms stddev 2.293
、、、
progress: 60.0 s, 6607.6 tps, lat 6.676 ms stddev 1.708
transaction type: <builtin: select only>
scaling factor: 100
query mode: extended
number of clients: 100
number of threads: 100
duration: 60 s
number of transactions actually processed: 359203
latency average = 7.426 ms
latency stddev = 5.283 ms
tps = 5985.437222 (including connections establishing)
tps = 13415.041978 (excluding connections establishing)
statement latencies in milliseconds:
0.003 \set aid random(1, 100000 * :scale)
7.425 SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
不使用連線池:752tps
[thunisoft@sqlfx ~]$ pgbench -M extended -v -r -P 1 -S -C -c 100 -j 100 -T 60 -p 6543 -Usa pgbenchdb
starting vacuum...end.
starting vacuum pgbench_accounts...end.
progress: 1.1 s, 656.3 tps, lat 8.981 ms stddev 7.668
、、、
progress: 60.0 s, 713.3 tps, lat 8.220 ms stddev 5.773
transaction type: <builtin: select only>
scaling factor: 100
query mode: extended
number of clients: 100
number of threads: 100
duration: 60 s
number of transactions actually processed: 45235
latency average = 7.972 ms
latency stddev = 6.182 ms
tps = 752.359996 (including connections establishing)
tps = 12079.524918 (excluding connections establishing)
statement latencies in milliseconds:
0.005 \set aid random(1, 100000 * :scale)
7.966 SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
短連結情況下使用連線池和不使用連線池,差別非常大。原因是建立大量的連線需要耗費大量的時間
高併發
使用連線池:565tps
--使用連線池,資料庫連線數為100
--這個地方的100是和pgbouncer.ini裡面的pool_size一致
pgbenchdb=# select count(*) from pg_stat_activity where state !='idle' and application_name = 'pgbench';
count
-------
100
(1 row)
--初始化資料
pgbench -i -s 20 pgbenchdb
dropping old tables...
creating tables...
generating data...
、、、
2000000 of 2000000 tuples (100%) done (elapsed 13.11 s, remaining 0.00 s)
vacuuming...
creating primary keys...
done.
--測試
[thunisoft@sqlfx ~]$ pgbench -M extended -r -P 1 -c 1000 -j 1000 -T 60 -p 5432 -Usa pgbenchdb
starting vacuum...end.
、、、
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 20
query mode: extended
number of clients: 1000
number of threads: 1000
duration: 60 s
number of transactions actually processed: 34907
latency average = 1734.514 ms
latency stddev = 406.066 ms
tps = 565.477219 (including connections establishing)
tps = 565.611196 (excluding connections establishing)
statement latencies in milliseconds:
0.006 \set aid random(1, 100000 * :scale)
0.001 \set bid random(1, 1 * :scale)
0.001 \set tid random(1, 10 * :scale)
0.001 \set delta random(-5000, 5000)
1471.673 BEGIN;
2.593 UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
1.302 SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
105.564 UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;
122.611 UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;
2.311 INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
29.079 END;
不使用連線池:406tps
--不使用用連線池,資料庫連線數為1000
pgbenchdb=# select count(*) from pg_stat_activity where state !='idle' and application_name = 'pgbench';
count
-------
1000
(1 row)
--初始化資料
[thunisoft@sqlfx ~]$ pgbench -i -s 20 pgbenchdb
dropping old tables...
creating tables...
generating data...
、、、
2000000 of 2000000 tuples (100%) done (elapsed 13.46 s, remaining 0.00 s)
vacuuming...
creating primary keys...
done.
--測試
[thunisoft@sqlfx ~]$ pgbench -M extended -r -P 1 -c 1000 -j 1000 -T 60 -p 6543 -Usa pgbenchdb
starting vacuum...end.
progress: 2.5 s, 443.8 tps, lat 362.341 ms stddev 407.794
、、、
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 20
query mode: extended
number of clients: 1000
number of threads: 1000
duration: 60 s
number of transactions actually processed: 24946
latency average = 2375.957 ms
latency stddev = 3390.823 ms
tps = 406.784046 (including connections establishing)
tps = 409.912851 (excluding connections establishing)
statement latencies in milliseconds:
0.016 \set aid random(1, 100000 * :scale)
0.001 \set bid random(1, 1 * :scale)
0.001 \set tid random(1, 10 * :scale)
0.003 \set delta random(-5000, 5000)
4.545 BEGIN;
4.436 UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
2.508 SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
1950.669 UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;
369.524 UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;
3.705 INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
40.694 END;
可以看到使用pgbouncer
連線池的tps
要比不使用pgbouncer
要稍高。使用了pgbouncer
後,連線到資料庫的連線數為100
,而不使用pgbouncer
的連線數為1000
總結
1、在使用durid
連線池的時候,最大最小連線池不必設定成一樣,這樣可以減小連線池開銷
2、durid
連線池是應用端的池子,當連線資料庫的應用變多了以後,資料庫任然不受保護,並且連線越多耗費的記憶體越多
3、pgbouncer
相當於在資料庫端加了一個池子,所有的連線過來都需要經過這個池子,負責連線的開啟和關閉
4、當有大量的服務連線到資料庫時,雖然有durid
應用端連線池,但是對於資料庫來說,仍然像沒有使用連線池一樣,pgbouncer
是資料庫端的連線池,用來控制應用端的連線
參考資料: