Skip to content

[WIP] Connection pooler #799

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 67 commits into from
Mar 25, 2020
Merged

[WIP] Connection pooler #799

merged 67 commits into from
Mar 25, 2020

Conversation

erthalion
Copy link
Contributor

The idea is to support connection pooler creation via operator. There is no strict dependencies, one can specify which type of pooler is required, but at the beginning probably only pgbouncer would be implemented.

Suggested changes to the manifest assume a new section:

connectionPool:
  type: pgbouncer
  instancesNumber: 1
  schema: pgbouncer
  user: pgbouncer
  mode: session
  resources:
  ...

Schema & user describe into which schema a lookup function will be installed for all available databases, and which user pooler will use for connection. A set of reasonable default values must be provided with the possibility to simply specify a full pod template for deployment.


// Options for connection pooler
type ConnectionPool struct {
NumberOfInstances *int32 `json:"instancesNumber,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My opinion is this is too many options.

pooling:
  [numberOfPods: 2 #default to op config]
  enabled: true #default to false from opconfig

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's why most of them are optional.
I wanted originally call it "pooling", but it's too broad and not clear, what kind of "pool" are we talking about. NumberOfPods is good.

@Jan-M
Copy link
Member

Jan-M commented Jan 22, 2020

I would slim down some Postgres manifest options in favor of a slim user configuration.

If one is not happy with the number of fields we offer, it is easy to deploy pgbouncer similar to our config manually.

I also think the type can probably be hidden behind the supplied Docker image given we have good env vars specced.

@FxKu FxKu added this to the 1.4 milestone Jan 24, 2020
@Jan-M Jan-M added the zalando label Jan 27, 2020
Add an initial support for a connection pooler. The idea is to make it
generic enough to be able to switch a corresponding docker image to
change from pgbouncer to e.g. odyssey. Operator needs to create a
deployment with pooler and a service for it to access.
Set up a proper owner reference to StatefulSet, and delete with
foreground policy to not leave orphans.
With convertion for config, and start tests.
@erthalion erthalion force-pushed the feature/connection-pooler branch from d1a756a to 6c37520 Compare February 12, 2020 16:35
erthalion and others added 8 commits February 12, 2020 17:35
Add synchronization logic. For now get rid of podTemplate, type fields.
Add crd validation & configuration part, put retry on top of lookup
function installation.
Add pool configuration into CRD & charts. Add preliminary documentation.
Rename NumberOfInstances to Replicas like in Deployment. Mention couple
of potential improvement points for connection pool specification.
Add an initial support for a connection pooler. The idea is to make it
generic enough to be able to switch a corresponding docker image to
change from pgbouncer to e.g. odyssey. Operator needs to create a
deployment with pooler and a service for it to access.
Set up a proper owner reference to StatefulSet, and delete with
foreground policy to not leave orphans.
With convertion for config, and start tests.
@erthalion erthalion force-pushed the feature/connection-pooler branch from 6dad833 to 2384e1e Compare February 13, 2020 12:46
Add synchronization logic. For now get rid of podTemplate, type fields.
Add crd validation & configuration part, put retry on top of lookup
function installation.
It requires more accurate lookup function synchronization and couple
fixes on the way (e.g. few get rid of using schema from a user secret).
For lookup function, since it's idempotend, sync it when we're not sure
if it was installed (e.g. when the operator was shutdown and start sync
everything at the start) and then remember that it was installed.
Small typo-like fixes and proper installing of a lookup function in all
the databases.
Rename application for connection pool (ideally in the future make it
configurable). Take into accounts nils for MaxInt32
if env.Name == "PGUSER" {
ref := env.ValueFrom.SecretKeyRef.LocalObjectReference

if ref.Name != c.credentialSecretName(config.User) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, one check is missing here. Only apply the change if the user in the spec is empty. Same for schema.


// Check if we need to synchronize connection pool deployment due to new
// defaults, that are different from what we see in the DeploymentSpec
func (c *Cluster) needSyncConnPoolDefaults(
Copy link
Member

@FxKu FxKu Mar 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maxDBConnections syncing is missing here (?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's mostly on purpose. Options mentioned there are reasonable to change and relatively easy to track. Not sure if there would be ever need to change maxDBConnections (e.g. pgbouncer in all my tests was always keeping it substantially lower than this limit).

* Set minimum number of pool instances to 2
* Improve logging of sync reasons
* Improve logging of a new pool role
Verify the defaul values only if the schema doesn't override them.
Since connection poolers are usually cpu bounded.
$$ LANGUAGE plpgsql SECURITY DEFINER;

REVOKE ALL ON FUNCTION {{.pool_schema}}.user_lookup(text)
FROM public, {{.pool_schema}};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
FROM public, {{.pool_schema}};
FROM public, {{.pool_user}};

If you don't choose pooler as your user, it will not get created which leads to an role does not exist error here


// in this case also do not forget to install lookup function as for
// creating cluster
if !oldNeedConnPool || !c.ConnectionPool.LookupFunction {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this need to be &&? On each sync I see the LookupFunction logs ("Installing..."). oldNeedConnPool should be false on sync but ConnectionPool.LookupFunction is set to true within the lookup function. Or is it intended?


if *numberOfInstances < constants.ConnPoolMinInstances {
msg := "Adjusted number of connection pool instances from %d to %d"
c.logger.Warningf(msg, numberOfInstances, constants.ConnPoolMinInstances)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

something like coalesce(numberOfInstances, c.OpConfig.ConnectionPool.NumberOfInstances) would prevent logs to look like: Adjusted number of connection pool instances from 824638671720 to 2

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, it's just a pointer needs to be dereferenced.

}
defer func() {
// in case if everything went fine this can generate a warning about
// trying to close an empty connection.
Copy link
Member

@FxKu FxKu Mar 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seen this, too. Can't you simply remove the closeDBConn block at the end of this function?

EDIT: Ah, you're connection to mutliple DBs. Okay. And c.pgDb != nil cannot be used here, too?


if newConnPool != nil {
specSchema = newConnPool.Schema
specUser = newConnPool.Schema
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
specUser = newConnPool.Schema
specUser = newConnPool.User

}

if spec.NumberOfInstances == nil &&
*deployment.Spec.Replicas != *config.NumberOfInstances {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should also check if deployment.Spec.Replicas is smaller than ConnPoolMinInstances. Otherwise, it could be set to 1 here and then raised to 2 again.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, it needs to be done on the config level (e.g. when it's created).

ConnPoolContainer = 0
ConnPoolMaxDBConnections = 60
ConnPoolMaxClientConnections = 10000
ConnPoolMinInstances = 2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Number for min instances should be the same as the internal default for Connection Pool's numberOfInstances. So raise it to two everywhere?

ObjectMeta: metav1.ObjectMeta{
Name: c.connPoolName(),
Namespace: c.Namespace,
Labels: c.labelsSet(true),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be connPoolLabelsSelector().MatchLabels instead, like in the pod template of this deployment?

ObjectMeta: metav1.ObjectMeta{
Name: c.connPoolName(),
Namespace: c.Namespace,
Labels: c.labelsSet(true),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same with deployment. Use connPoolLabelsSelector().MatchLabels instead?

@FxKu
Copy link
Member

FxKu commented Mar 25, 2020

👍

1 similar comment
@erthalion
Copy link
Contributor Author

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants