diff --git a/docs/enterprise_edition/control_plane/ha.md b/docs/enterprise_edition/control_plane/ha.md new file mode 100644 index 00000000..5cd36d1d --- /dev/null +++ b/docs/enterprise_edition/control_plane/ha.md @@ -0,0 +1,88 @@ +--- +icon: material/server-network +--- + +# High availability + +!!! note "New feature" + + This feature is new and experimental. Make sure to test it before deploying to production. + +The [control plane](index.md) supports deploying multiple instances on different machines. In case of hardware failure, its responsibilities can be taken over by a standby instance with almost no downtime. + +## How it works + +The leader instance, elected using Raft, performs all actions and monitors PgDog instances connected to it. Standby instances are also reachable via HTTP and will forward all API requests to the leader automatically. + +If a leader fails, Raft will quickly promote one of the standby instances and the control plane will continue to operate normally. When the broken leader is replaced, it's added as a follower and the cluster goes back to a healthy state. + +## Configuration + +If you're using our [Helm chart](installation.md) to deploy the control plane, Raft can be easily enabled with the following configuration: + +```yaml +raft: + enabled: true + token: "raft-secret-token" +``` + +Turning Raft on will change the deployment strategy to use a Kubernetes `StatefulSet` and attach a PVC (Persistent Volume Claim) to each pod, so make sure your Kube cluster has a configured default `StorageClass`. + +All required Raft settings, including Raft log storage and the address and ID of each pod in the set, will be automatically configured. + +### Using a Secret + +The Raft token is technically a secret and can be injected via an environment variable into each pod in the set. + +First, create a `Secret` resource in the same namespace as the control plane, for example: + +```yaml title="secret.yaml" +apiVersion: v1 +kind: Secret +metadata: + name: control-secrets +type: Opaque +stringData: + raft-token: "raft-secret-token" +``` + +Once the secret is created, you can reference it in the Helm chart configuration as follows: + +```yaml title="values.yaml" +raft: + enabled: true + secret: + name: control-secrets + tokenKey: raft-token +``` + +### Manual configuration + +If you're deploying the control plane in a non-Kubernetes environment, e.g., EC2, ECS, etc., you can configure high availability manually. + +Each control plane node needs to be aware of all other nodes, so a basic Raft configuration looks as follows: + +```toml title="control.toml" +[raft] +token = "raft-auth-token" +cluster_name = "pgdog" # Immutable. +storage_path = "/path/to/durable/volume/raft.redb" + +[[raft.members]] +id = "1" +address = "10.0.0.0" + +[[raft.members]] +id = "2" +address = "10.0.0.1" + +[[raft.members]] +id = "3" +address = "10.0.0.2" +``` + +!!! note "Number of nodes" + + For Raft to work correctly (and optimally), configure three (3) nodes operating on different + hardware instances. The number of nodes must always be odd (e.g., 3, 5, 7). The more nodes that are part + of the same cluster, the slower a Raft operation will become, since it requires majority consensus. diff --git a/docs/enterprise_edition/globally-sequences.md b/docs/enterprise_edition/globally-sequences.md new file mode 100644 index 00000000..b1453cef --- /dev/null +++ b/docs/enterprise_edition/globally-sequences.md @@ -0,0 +1,81 @@ +--- +icon: material/counter +--- + +# Global sequences + +!!! note "New feature" + + This feature is new and experimental. Make sure to test it before deploying to production. + +The open source edition of PgDog can generate unique, `BIGINT` primary keys in two ways: + +1. [Timestamp-based unique ID](../features/sharding/unique-ids.md) +2. [Sharded sequences](../features/sharding/sequences.md) + +However, both methods produce gaps in the numbers, while the [unique ID](../features/sharding/unique-ids.md) generates very large 64-bit numbers, which may not work with all applications, e.g., JavaScript apps that pass identifiers directly. + +Global sequences are powered by [Raft](control_plane/ha.md) and are guaranteed to produce sequential integers, starting at 1, just like regular PostgreSQL sequences. + +## How it works + +This feature requires PgDog to be connected to the [control plane](control_plane/index.md). Once configured, the following functions will begin to work automatically: + +| Function | Description | +| --------------------- | ---------------------------------------------------------------------- | +| `pgdog.nextval(name)` | Return a monotonically increasing integer for the given sequence name. | + +=== "Example" + + ```postgresql + SELECT pgdog.nextval('public_users_id_seq') AS id; + ``` + +=== "Output" + + ``` + id + ---- + 1 + (1 row) + ``` + +### Usage + +The sequence functions can be called in any query, including INSERT, UPDATE, and DELETE statements. The sequence values can also be automatically injected into INSERT queries targeting [omnisharded](../features/sharding/omnishards.md) tables: + +=== "pgdog.toml" + + ```toml + [rewrite] + primary_key = "rewrite_omni_global" + ``` + +=== "Helm chart" + + ```yaml + rewrite: + primaryKey: rewrite_omni_global + ``` + +The name of the sequence is automatically derived from the table and column names of the table targeted by the INSERT statement. For example, enabling this feature will produce the following rewrite: + +=== "Statement" + + ```postgresql + INSERT INTO tenants (tenant_name) VALUES ($1) + ``` + +=== "Rewrite" + + ```postgresql + INSERT INTO tenants (id, tenant_name) VALUES (pgdog.nextval('tenants_id_seq'), $1) + ``` + +### Under the hood + +All sequence values are stored in the [Raft](control_plane/ha.md) log, which makes them durable, just like PostgreSQL sequences. For this reason, enabling Raft in the control plane is required for this feature to work. + +#### Performance + +Due to their distributed and durable nature, global sequences are slower to generate numbers than [Unique ID](../features/sharding/unique-ids.md) and [sharded sequences](../features/sharding/sequences.md), and should be used for infrequent writes into tables that otherwise would not be able to support `BIGINT` numbers.