Skip to content

Commit 2ae4b43

Browse files
authored
Add support for multi-database / multi-user pools (#96)
* Add support for multi-database / multi-user pools * Nothing * cargo fmt * CI * remove test users * rename pool * Update tests to use admin user/pass * more fixes * Revert bad change * Use PGDATABASE env var * send server info in case of admin
1 parent c5be556 commit 2ae4b43

File tree

14 files changed

+710
-513
lines changed

14 files changed

+710
-513
lines changed

.circleci/pgcat.toml

Lines changed: 48 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,12 @@
55
#
66
# General pooler settings
77
[general]
8-
98
# What IP to run on, 0.0.0.0 means accessible from everywhere.
109
host = "0.0.0.0"
1110

1211
# Port to run on, same as PgBouncer used in this example.
1312
port = 6432
1413

15-
# How many connections to allocate per server.
16-
pool_size = 15
17-
18-
# Pool mode (see PgBouncer docs for more).
19-
# session: one server connection per connected client
20-
# transaction: one server connection per client transaction
21-
pool_mode = "transaction"
22-
2314
# How long to wait before aborting a server connection (ms).
2415
connect_timeout = 100
2516

@@ -29,56 +20,27 @@ healthcheck_timeout = 100
2920
# For how long to ban a server if it fails a health check (seconds).
3021
ban_time = 60 # Seconds
3122

32-
#
23+
# Reload config automatically if it changes.
3324
autoreload = true
3425

26+
# TLS
3527
tls_certificate = ".circleci/server.cert"
3628
tls_private_key = ".circleci/server.key"
3729

38-
#
39-
# User to use for authentication against the server.
40-
[user]
41-
name = "sharding_user"
42-
password = "sharding_user"
43-
44-
45-
#
46-
# Shards in the cluster
47-
[shards]
48-
49-
# Shard 0
50-
[shards.0]
51-
52-
# [ host, port, role ]
53-
servers = [
54-
[ "127.0.0.1", 5432, "primary" ],
55-
[ "localhost", 5433, "replica" ],
56-
# [ "127.0.1.1", 5432, "replica" ],
57-
]
58-
# Database name (e.g. "postgres")
59-
database = "shard0"
60-
61-
[shards.1]
62-
# [ host, port, role ]
63-
servers = [
64-
[ "127.0.0.1", 5432, "primary" ],
65-
[ "localhost", 5433, "replica" ],
66-
# [ "127.0.1.1", 5432, "replica" ],
67-
]
68-
database = "shard1"
69-
70-
[shards.2]
71-
# [ host, port, role ]
72-
servers = [
73-
[ "127.0.0.1", 5432, "primary" ],
74-
[ "localhost", 5433, "replica" ],
75-
# [ "127.0.1.1", 5432, "replica" ],
76-
]
77-
database = "shard2"
78-
30+
# Credentials to access the virtual administrative database (pgbouncer or pgcat)
31+
# Connecting to that database allows running commands like `SHOW POOLS`, `SHOW DATABASES`, etc..
32+
admin_username = "admin_user"
33+
admin_password = "admin_pass"
7934

80-
# Settings for our query routing layer.
81-
[query_router]
35+
# pool
36+
# configs are structured as pool.<pool_name>
37+
# the pool_name is what clients use as database name when connecting
38+
# For the example below a client can connect using "postgres://sharding_user:sharding_user@pgcat_host:pgcat_port/sharded"
39+
[pools.sharded_db]
40+
# Pool mode (see PgBouncer docs for more).
41+
# session: one server connection per connected client
42+
# transaction: one server connection per client transaction
43+
pool_mode = "transaction"
8244

8345
# If the client doesn't specify, route traffic to
8446
# this role by default.
@@ -88,7 +50,6 @@ database = "shard2"
8850
# primary: all queries go to the primary unless otherwise specified.
8951
default_role = "any"
9052

91-
9253
# Query parser. If enabled, we'll attempt to parse
9354
# every incoming query to determine if it's a read or a write.
9455
# If it's a read query, we'll direct it to a replica. Otherwise, if it's a write,
@@ -109,3 +70,36 @@ primary_reads_enabled = true
10970
# sha1: A hashing function based on SHA1
11071
#
11172
sharding_function = "pg_bigint_hash"
73+
74+
# Credentials for users that may connect to this cluster
75+
[pools.sharded_db.users.0]
76+
username = "sharding_user"
77+
password = "sharding_user"
78+
# Maximum number of server connections that can be established for this user
79+
# The maximum number of connection from a single Pgcat process to any database in the cluster
80+
# is the sum of pool_size across all users.
81+
pool_size = 9
82+
83+
# Shard 0
84+
[pools.sharded_db.shards.0]
85+
# [ host, port, role ]
86+
servers = [
87+
[ "127.0.0.1", 5432, "primary" ],
88+
[ "localhost", 5432, "replica" ]
89+
]
90+
# Database name (e.g. "postgres")
91+
database = "shard0"
92+
93+
[pools.sharded_db.shards.1]
94+
servers = [
95+
[ "127.0.0.1", 5432, "primary" ],
96+
[ "localhost", 5432, "replica" ],
97+
]
98+
database = "shard1"
99+
100+
[pools.sharded_db.shards.2]
101+
servers = [
102+
[ "127.0.0.1", 5432, "primary" ],
103+
[ "localhost", 5432, "replica" ],
104+
]
105+
database = "shard2"

.circleci/run_tests.sh

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ toxiproxy-cli create -l 127.0.0.1:5433 -u 127.0.0.1:5432 postgres_replica
3232
start_pgcat "info"
3333

3434
export PGPASSWORD=sharding_user
35+
export PGDATABASE=sharded_db
3536

3637
# pgbench test
3738
pgbench -U sharding_user -i -h 127.0.0.1 -p 6432
@@ -47,7 +48,7 @@ sleep 1
4748
killall psql -s SIGINT
4849

4950
# Reload pool (closing unused server connections)
50-
psql -U sharding_user -h 127.0.0.1 -p 6432 -d pgbouncer -c 'RELOAD'
51+
PGPASSWORD=admin_pass psql -U admin_user -h 127.0.0.1 -p 6432 -d pgbouncer -c 'RELOAD'
5152

5253
(psql -U sharding_user -h 127.0.0.1 -p 6432 -c 'SELECT pg_sleep(50)' || true) &
5354
sleep 1
@@ -72,15 +73,17 @@ cd tests/ruby && \
7273
cd ../..
7374

7475
# Admin tests
75-
psql -U sharding_user -e -h 127.0.0.1 -p 6432 -d pgbouncer -c 'SHOW STATS' > /dev/null
76-
psql -U sharding_user -h 127.0.0.1 -p 6432 -d pgbouncer -c 'RELOAD' > /dev/null
77-
psql -U sharding_user -h 127.0.0.1 -p 6432 -d pgbouncer -c 'SHOW CONFIG' > /dev/null
78-
psql -U sharding_user -h 127.0.0.1 -p 6432 -d pgbouncer -c 'SHOW DATABASES' > /dev/null
79-
psql -U sharding_user -h 127.0.0.1 -p 6432 -d pgbouncer -c 'SHOW LISTS' > /dev/null
80-
psql -U sharding_user -h 127.0.0.1 -p 6432 -d pgbouncer -c 'SHOW POOLS' > /dev/null
81-
psql -U sharding_user -h 127.0.0.1 -p 6432 -d pgbouncer -c 'SHOW VERSION' > /dev/null
82-
psql -U sharding_user -h 127.0.0.1 -p 6432 -d pgbouncer -c "SET client_encoding TO 'utf8'" > /dev/null # will ignore
83-
(! psql -U sharding_user -e -h 127.0.0.1 -p 6432 -d random_db -c 'SHOW STATS' > /dev/null)
76+
export PGPASSWORD=admin_pass
77+
psql -U admin_user -e -h 127.0.0.1 -p 6432 -d pgbouncer -c 'SHOW STATS' > /dev/null
78+
psql -U admin_user -h 127.0.0.1 -p 6432 -d pgbouncer -c 'RELOAD' > /dev/null
79+
psql -U admin_user -h 127.0.0.1 -p 6432 -d pgbouncer -c 'SHOW CONFIG' > /dev/null
80+
psql -U admin_user -h 127.0.0.1 -p 6432 -d pgbouncer -c 'SHOW DATABASES' > /dev/null
81+
psql -U admin_user -h 127.0.0.1 -p 6432 -d pgbouncer -c 'SHOW LISTS' > /dev/null
82+
psql -U admin_user -h 127.0.0.1 -p 6432 -d pgbouncer -c 'SHOW POOLS' > /dev/null
83+
psql -U admin_user -h 127.0.0.1 -p 6432 -d pgbouncer -c 'SHOW VERSION' > /dev/null
84+
psql -U admin_user -h 127.0.0.1 -p 6432 -d pgbouncer -c "SET client_encoding TO 'utf8'" > /dev/null # will ignore
85+
(! psql -U admin_user -e -h 127.0.0.1 -p 6432 -d random_db -c 'SHOW STATS' > /dev/null)
86+
export PGPASSWORD=sharding_user
8487

8588
# Start PgCat in debug to demonstrate failover better
8689
start_pgcat "trace"

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pgcat"
3-
version = "0.4.0-beta1"
3+
version = "0.6.0-alpha1"
44
edition = "2021"
55

66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

pgcat.toml

Lines changed: 72 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,20 @@
55
#
66
# General pooler settings
77
[general]
8-
98
# What IP to run on, 0.0.0.0 means accessible from everywhere.
109
host = "0.0.0.0"
1110

1211
# Port to run on, same as PgBouncer used in this example.
1312
port = 6432
1413

15-
# How many connections to allocate per server.
16-
pool_size = 15
17-
18-
# Pool mode (see PgBouncer docs for more).
19-
# session: one server connection per connected client
20-
# transaction: one server connection per client transaction
21-
pool_mode = "transaction"
22-
2314
# How long to wait before aborting a server connection (ms).
2415
connect_timeout = 5000
2516

2617
# How much time to give `SELECT 1` health check query to return with a result (ms).
2718
healthcheck_timeout = 1000
2819

2920
# For how long to ban a server if it fails a health check (seconds).
30-
ban_time = 60 # Seconds
21+
ban_time = 60 # seconds
3122

3223
# Reload config automatically if it changes.
3324
autoreload = false
@@ -36,50 +27,20 @@ autoreload = false
3627
# tls_certificate = "server.cert"
3728
# tls_private_key = "server.key"
3829

39-
#
40-
# User to use for authentication against the server.
41-
[user]
42-
name = "sharding_user"
43-
password = "sharding_user"
44-
45-
46-
#
47-
# Shards in the cluster
48-
[shards]
49-
50-
# Shard 0
51-
[shards.0]
52-
53-
# [ host, port, role ]
54-
servers = [
55-
[ "127.0.0.1", 5432, "primary" ],
56-
[ "localhost", 5432, "replica" ],
57-
# [ "127.0.1.1", 5432, "replica" ],
58-
]
59-
# Database name (e.g. "postgres")
60-
database = "shard0"
61-
62-
[shards.1]
63-
# [ host, port, role ]
64-
servers = [
65-
[ "127.0.0.1", 5432, "primary" ],
66-
[ "localhost", 5432, "replica" ],
67-
# [ "127.0.1.1", 5432, "replica" ],
68-
]
69-
database = "shard1"
30+
# Credentials to access the virtual administrative database (pgbouncer or pgcat)
31+
# Connecting to that database allows running commands like `SHOW POOLS`, `SHOW DATABASES`, etc..
32+
admin_username = "user"
33+
admin_password = "pass"
7034

71-
[shards.2]
72-
# [ host, port, role ]
73-
servers = [
74-
[ "127.0.0.1", 5432, "primary" ],
75-
[ "localhost", 5432, "replica" ],
76-
# [ "127.0.1.1", 5432, "replica" ],
77-
]
78-
database = "shard2"
79-
80-
81-
# Settings for our query routing layer.
82-
[query_router]
35+
# pool
36+
# configs are structured as pool.<pool_name>
37+
# the pool_name is what clients use as database name when connecting
38+
# For the example below a client can connect using "postgres://sharding_user:sharding_user@pgcat_host:pgcat_port/sharded"
39+
[pools.sharded]
40+
# Pool mode (see PgBouncer docs for more).
41+
# session: one server connection per connected client
42+
# transaction: one server connection per client transaction
43+
pool_mode = "transaction"
8344

8445
# If the client doesn't specify, route traffic to
8546
# this role by default.
@@ -89,7 +50,6 @@ database = "shard2"
8950
# primary: all queries go to the primary unless otherwise specified.
9051
default_role = "any"
9152

92-
9353
# Query parser. If enabled, we'll attempt to parse
9454
# every incoming query to determine if it's a read or a write.
9555
# If it's a read query, we'll direct it to a replica. Otherwise, if it's a write,
@@ -110,3 +70,61 @@ primary_reads_enabled = true
11070
# sha1: A hashing function based on SHA1
11171
#
11272
sharding_function = "pg_bigint_hash"
73+
74+
# Credentials for users that may connect to this cluster
75+
[pools.sharded.users.0]
76+
username = "sharding_user"
77+
password = "sharding_user"
78+
# Maximum number of server connections that can be established for this user
79+
# The maximum number of connection from a single Pgcat process to any database in the cluster
80+
# is the sum of pool_size across all users.
81+
pool_size = 9
82+
83+
[pools.sharded.users.1]
84+
username = "other_user"
85+
password = "other_user"
86+
pool_size = 21
87+
88+
# Shard 0
89+
[pools.sharded.shards.0]
90+
# [ host, port, role ]
91+
servers = [
92+
[ "127.0.0.1", 5432, "primary" ],
93+
[ "localhost", 5432, "replica" ]
94+
]
95+
# Database name (e.g. "postgres")
96+
database = "shard0"
97+
98+
[pools.sharded.shards.1]
99+
servers = [
100+
[ "127.0.0.1", 5432, "primary" ],
101+
[ "localhost", 5432, "replica" ],
102+
]
103+
database = "shard1"
104+
105+
[pools.sharded.shards.2]
106+
servers = [
107+
[ "127.0.0.1", 5432, "primary" ],
108+
[ "localhost", 5432, "replica" ],
109+
]
110+
database = "shard2"
111+
112+
113+
[pools.simple_db]
114+
pool_mode = "session"
115+
default_role = "primary"
116+
query_parser_enabled = true
117+
primary_reads_enabled = true
118+
sharding_function = "pg_bigint_hash"
119+
120+
[pools.simple_db.users.0]
121+
username = "simple_user"
122+
password = "simple_user"
123+
pool_size = 5
124+
125+
[pools.simple_db.shards.0]
126+
servers = [
127+
[ "127.0.0.1", 5432, "primary" ],
128+
[ "localhost", 5432, "replica" ]
129+
]
130+
database = "some_db"

0 commit comments

Comments
 (0)