mirror of
https://github.com/postgresml/pgcat.git
synced 2026-03-23 01:16:30 +00:00
@@ -152,7 +152,7 @@ default: <UNSET>
|
|||||||
example: "server.cert"
|
example: "server.cert"
|
||||||
```
|
```
|
||||||
|
|
||||||
Path to TLS Certficate file to use for TLS connections
|
Path to TLS Certificate file to use for TLS connections
|
||||||
|
|
||||||
### tls_private_key
|
### tls_private_key
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ You can open a Docker development environment where you can debug tests easier.
|
|||||||
./dev/script/console
|
./dev/script/console
|
||||||
```
|
```
|
||||||
|
|
||||||
This will open a terminal in an environment similar to that used in tests. In there, you can compile the pooler, run tests, do some debugging with the test environment, etc. Objects compiled inside the contaner (and bundled gems) will be placed in `dev/cache` so they don't interfere with what you have on your machine.
|
This will open a terminal in an environment similar to that used in tests. In there, you can compile the pooler, run tests, do some debugging with the test environment, etc. Objects compiled inside the container (and bundled gems) will be placed in `dev/cache` so they don't interfere with what you have on your machine.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ query_parser_enabled = true
|
|||||||
|
|
||||||
# If the query parser is enabled and this setting is enabled, the primary will be part of the pool of databases used for
|
# If the query parser is enabled and this setting is enabled, the primary will be part of the pool of databases used for
|
||||||
# load balancing of read queries. Otherwise, the primary will only be used for write
|
# load balancing of read queries. Otherwise, the primary will only be used for write
|
||||||
# queries. The primary can always be explicitely selected with our custom protocol.
|
# queries. The primary can always be explicitly selected with our custom protocol.
|
||||||
primary_reads_enabled = true
|
primary_reads_enabled = true
|
||||||
|
|
||||||
# So what if you wanted to implement a different hashing function,
|
# So what if you wanted to implement a different hashing function,
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ tcp_keepalives_count = 5
|
|||||||
# Number of seconds between keepalive packets.
|
# Number of seconds between keepalive packets.
|
||||||
tcp_keepalives_interval = 5
|
tcp_keepalives_interval = 5
|
||||||
|
|
||||||
# Path to TLS Certficate file to use for TLS connections
|
# Path to TLS Certificate file to use for TLS connections
|
||||||
# tls_certificate = "server.cert"
|
# tls_certificate = "server.cert"
|
||||||
# Path to TLS private key file to use for TLS connections
|
# Path to TLS private key file to use for TLS connections
|
||||||
# tls_private_key = "server.key"
|
# tls_private_key = "server.key"
|
||||||
@@ -123,7 +123,7 @@ idle_timeout = 40000
|
|||||||
connect_timeout = 3000
|
connect_timeout = 3000
|
||||||
|
|
||||||
# User configs are structured as pool.<pool_name>.users.<user_index>
|
# User configs are structured as pool.<pool_name>.users.<user_index>
|
||||||
# This secion holds the credentials for users that may connect to this cluster
|
# This section holds the credentials for users that may connect to this cluster
|
||||||
[pools.sharded_db.users.0]
|
[pools.sharded_db.users.0]
|
||||||
# Postgresql username
|
# Postgresql username
|
||||||
username = "sharding_user"
|
username = "sharding_user"
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ impl General {
|
|||||||
|
|
||||||
// These keepalive defaults should detect a dead connection within 30 seconds.
|
// These keepalive defaults should detect a dead connection within 30 seconds.
|
||||||
// Tokio defaults to disabling keepalives which keeps dead connections around indefinitely.
|
// Tokio defaults to disabling keepalives which keeps dead connections around indefinitely.
|
||||||
// This can lead to permenant server pool exhaustion
|
// This can lead to permanent server pool exhaustion
|
||||||
pub fn default_tcp_keepalives_idle() -> u64 {
|
pub fn default_tcp_keepalives_idle() -> u64 {
|
||||||
5 // 5 seconds
|
5 // 5 seconds
|
||||||
}
|
}
|
||||||
@@ -422,7 +422,7 @@ pub struct Pool {
|
|||||||
|
|
||||||
pub shards: BTreeMap<String, Shard>,
|
pub shards: BTreeMap<String, Shard>,
|
||||||
pub users: BTreeMap<String, User>,
|
pub users: BTreeMap<String, User>,
|
||||||
// Note, don't put simple fields below these configs. There's a compatability issue with TOML that makes it
|
// Note, don't put simple fields below these configs. There's a compatibility issue with TOML that makes it
|
||||||
// incompatible to have simple fields in TOML after complex objects. See
|
// incompatible to have simple fields in TOML after complex objects. See
|
||||||
// https://users.rust-lang.org/t/why-toml-to-string-get-error-valueaftertable/85903
|
// https://users.rust-lang.org/t/why-toml-to-string-get-error-valueaftertable/85903
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -404,7 +404,7 @@ pub fn row_description(columns: &Vec<(&str, DataType)>) -> BytesMut {
|
|||||||
let mut res = BytesMut::new();
|
let mut res = BytesMut::new();
|
||||||
let mut row_desc = BytesMut::new();
|
let mut row_desc = BytesMut::new();
|
||||||
|
|
||||||
// how many colums we are storing
|
// how many columns we are storing
|
||||||
row_desc.put_i16(columns.len() as i16);
|
row_desc.put_i16(columns.len() as i16);
|
||||||
|
|
||||||
for (name, data_type) in columns {
|
for (name, data_type) in columns {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ use log::{Level, Log, Metadata, Record, SetLoggerError};
|
|||||||
//
|
//
|
||||||
// So to summarize, if no `STDOUT_LOG` env var is present, the logger is the default logger. If `STDOUT_LOG` is set, everything
|
// So to summarize, if no `STDOUT_LOG` env var is present, the logger is the default logger. If `STDOUT_LOG` is set, everything
|
||||||
// but errors, that matches the log level set in the `STDOUT_LOG` env var is sent to stdout. You can have also some esoteric configuration
|
// but errors, that matches the log level set in the `STDOUT_LOG` env var is sent to stdout. You can have also some esoteric configuration
|
||||||
// where you set `RUST_LOG=debug` and `STDOUT_LOG=info`, in here, erros will go to stderr, warns and infos to stdout and debugs to stderr.
|
// where you set `RUST_LOG=debug` and `STDOUT_LOG=info`, in here, errors will go to stderr, warns and infos to stdout and debugs to stderr.
|
||||||
//
|
//
|
||||||
pub struct MultiLogger {
|
pub struct MultiLogger {
|
||||||
stderr_logger: env_logger::Logger,
|
stderr_logger: env_logger::Logger,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/// Route queries automatically based on explicitely requested
|
/// Route queries automatically based on explicitly requested
|
||||||
/// or implied query characteristics.
|
/// or implied query characteristics.
|
||||||
use bytes::{Buf, BytesMut};
|
use bytes::{Buf, BytesMut};
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ impl Reporter {
|
|||||||
CLIENT_STATS.write().insert(client_id, stats);
|
CLIENT_STATS.write().insert(client_id, stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reports a client is disconecting from the pooler.
|
/// Reports a client is disconnecting from the pooler.
|
||||||
fn client_disconnecting(&self, client_id: i32) {
|
fn client_disconnecting(&self, client_id: i32) {
|
||||||
CLIENT_STATS.write().remove(&client_id);
|
CLIENT_STATS.write().remove(&client_id);
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ impl Reporter {
|
|||||||
fn server_register(&self, server_id: i32, stats: Arc<ServerStats>) {
|
fn server_register(&self, server_id: i32, stats: Arc<ServerStats>) {
|
||||||
SERVER_STATS.write().insert(server_id, stats);
|
SERVER_STATS.write().insert(server_id, stats);
|
||||||
}
|
}
|
||||||
/// Reports a server connection is disconecting from the pooler.
|
/// Reports a server connection is disconnecting from the pooler.
|
||||||
fn server_disconnecting(&self, server_id: i32) {
|
fn server_disconnecting(&self, server_id: i32) {
|
||||||
SERVER_STATS.write().remove(&server_id);
|
SERVER_STATS.write().remove(&server_id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ impl ClientStats {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reports a client is disconecting from the pooler and
|
/// Reports a client is disconnecting from the pooler and
|
||||||
/// update metrics on the corresponding pool.
|
/// update metrics on the corresponding pool.
|
||||||
pub fn disconnect(&self) {
|
pub fn disconnect(&self) {
|
||||||
self.reporter.client_disconnecting(self.client_id);
|
self.reporter.client_disconnecting(self.client_id);
|
||||||
@@ -140,7 +140,7 @@ impl ClientStats {
|
|||||||
self.error_count.fetch_add(1, Ordering::Relaxed);
|
self.error_count.fetch_add(1, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reportes the time spent by a client waiting to get a healthy connection from the pool
|
/// Reporters the time spent by a client waiting to get a healthy connection from the pool
|
||||||
pub fn checkout_time(&self, microseconds: u64) {
|
pub fn checkout_time(&self, microseconds: u64) {
|
||||||
self.total_wait_time
|
self.total_wait_time
|
||||||
.fetch_add(microseconds, Ordering::Relaxed);
|
.fetch_add(microseconds, Ordering::Relaxed);
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ impl ServerStats {
|
|||||||
self.state.store(ServerState::Idle, Ordering::Relaxed);
|
self.state.store(ServerState::Idle, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reports a server connection is disconecting from the pooler.
|
/// Reports a server connection is disconnecting from the pooler.
|
||||||
/// Also updates metrics on the pool regarding server usage.
|
/// Also updates metrics on the pool regarding server usage.
|
||||||
pub fn disconnect(&self) {
|
pub fn disconnect(&self) {
|
||||||
self.reporter.server_disconnecting(self.server_id);
|
self.reporter.server_disconnecting(self.server_id);
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ describe "Admin" do
|
|||||||
describe "SHOW POOLS" do
|
describe "SHOW POOLS" do
|
||||||
context "bad credentials" do
|
context "bad credentials" do
|
||||||
it "does not change any stats" do
|
it "does not change any stats" do
|
||||||
bad_passsword_url = URI(pgcat_conn_str)
|
bad_password_url = URI(pgcat_conn_str)
|
||||||
bad_passsword_url.password = "wrong"
|
bad_password_url.password = "wrong"
|
||||||
expect { PG::connect("#{bad_passsword_url.to_s}?application_name=bad_password") }.to raise_error(PG::ConnectionBad)
|
expect { PG::connect("#{bad_password_url.to_s}?application_name=bad_password") }.to raise_error(PG::ConnectionBad)
|
||||||
|
|
||||||
sleep(1)
|
sleep(1)
|
||||||
admin_conn = PG::connect(processes.pgcat.admin_connection_string)
|
admin_conn = PG::connect(processes.pgcat.admin_connection_string)
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ describe "Least Outstanding Queries Load Balancing" do
|
|||||||
processes.pgcat.shutdown
|
processes.pgcat.shutdown
|
||||||
end
|
end
|
||||||
|
|
||||||
context "under homogenous load" do
|
context "under homogeneous load" do
|
||||||
it "balances query volume between all instances" do
|
it "balances query volume between all instances" do
|
||||||
conn = PG.connect(processes.pgcat.connection_string("sharded_db", "sharding_user"))
|
conn = PG.connect(processes.pgcat.connection_string("sharded_db", "sharding_user"))
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ describe "Sharding" do
|
|||||||
processes.pgcat.shutdown
|
processes.pgcat.shutdown
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "automatic routing of extended procotol" do
|
describe "automatic routing of extended protocol" do
|
||||||
it "can do it" do
|
it "can do it" do
|
||||||
conn = PG.connect(processes.pgcat.connection_string("sharded_db", "sharding_user"))
|
conn = PG.connect(processes.pgcat.connection_string("sharded_db", "sharding_user"))
|
||||||
conn.exec("SET SERVER ROLE TO 'auto'")
|
conn.exec("SET SERVER ROLE TO 'auto'")
|
||||||
|
|||||||
Reference in New Issue
Block a user