Supavisor Documentation

repository·main·Indexed 24 days ago

https://github.com/supabase/supavisor

Supavisor is a scalable, cloud-native Postgres connection pooler designed to proxy millions of end-client connections into a stateful pool of native Postgres database connections. It supports TCP and HTTP protocols, multi-tenancy, and serves as a drop-in replacement for PgBouncer. Key features include Transaction, Session, and Native pool modes, Prometheus observability, and a Management API with OpenAPI/SwaggerUI support.

Tokens
12.4K
Snippets
25
Records
82
Agent score
80%

What's inside Supavisor

  1. What is Supavisor?

    main
    Supavisor is a scalable, cloud-native Postgres connection pooler designed to proxy millions of Postgres end-client connections into a stateful pool of native Postgres database connections. It is built to handle modern connection demands, such as those from serverless environments, by supporting both TCP and HTTP protocols. It can be used as a multi-tenant pooler or as a single-tenant drop-in replacement for PgBouncer.
  2. Supavisor Features

    main

    Supavisor provides the following capabilities:

    • Scalability: Supports up to 1 million Postgres connections on a cluster and 250,000 idle connections on a single 16-core node with 64GB RAM.
    • Multi-tenancy: Ability to connect to multiple different Postgres instances or clusters.
    • Pool Modes: Supports Transaction mode per tenant.
    • Cloud-Native Design: Supports rolling and blue/green deployment strategies and is resilient during cluster resizing. It is designed to run in non-serverless environments and is not dependent on Kubernetes.
    • Observability: Provides a Prometheus /metrics endpoint to monitor throughput by tenant, tenant database, or individual connection.
    • Manageability: Includes an OpenAPI spec at /api/openapi and SwaggerUI at /swaggerui.
    • Connection Buffering: Provides brief connection buffering to allow for transparent database restarts or failovers.
  3. Enable named prepared statements for Prisma in transaction mode

    main

    By default, Prisma uses named prepared statements, which can conflict with transaction-mode pooling. To allow Prisma to use named prepared statements in transaction mode without using the pgbouncer=true flag, you must enable the named_prepared_statements feature flag in Supavisor.

    You can enable this in two ways:

    1. Globally: Set the NAMED_PREPARED_STATEMENTS_ENABLED environment variable.
    2. Per Tenant: Use the feature_flags configuration.

    Enabling this feature avoids the performance penalty associated with pgbouncer=true when querying tables with extension types.

  4. Configure prepared statement support

    main

    Supavisor supports prepared statements based on the connection mode:

    1. Session Mode: Prepared statements are supported by default.
    2. Transaction Mode: Named prepared statements are only supported if the named_prepared_statements feature flag is enabled.

    You can enable this feature flag in two ways:

    • Globally: Set the NAMED_PREPARED_STATEMENTS_ENABLED environment variable.
    • Per Tenant: Configure it via the feature_flags setting on the tenant.
  5. How Supavisor verifies client credentials

    main

    When a client connection is established, Supavisor verifies credentials using one of two methods depending on the configuration of the tenant record:

    1. Tenant User Record: If no auth_query is defined on the tenant record, Supavisor looks up credentials from user records associated with that tenant. It verifies these against the credentials provided in the client connection string. For this method to work, there must be one or more user records for the tenant where is_manager is false.

    2. Authentication Query: If the user in the client connection is not found in the tenant's user records, Supavisor falls back to using the user where is_manager is true and executes the auth_query defined on the tenant record. This query is used to fetch matching credentials directly from the tenant's database.

  6. How tenant lookup works in Supavisor

    main
    Supavisor uses a tenant record stored in its metadata database to manage configuration for specific groups of connections. A tenant is identified by an external_id which is discovered during the incoming client connection process. Additionally, the sni_hostname field can be used to match an incoming connection to a specific tenant record.
  7. Understand Supavisor cluster connection routing

    main

    When deployed as a cluster for high availability, Supavisor uses an 'owner node' model for tenant pools:

    • Pool Ownership: The first node to receive a connection from a specific tenant becomes the owner and spins up the connection pool on that node.
    • Routing: Any subsequent connections from the same tenant that hit other nodes in the cluster are routed to the owner node.

    Why this model is used:

    • Guaranteed Connection Counts: It ensures the total connections to the database strictly follow the default_pool_size set on the tenant, avoiding synchronization delays between nodes that could lead to exceeding database limits.
    • Scalability: It prevents every node from redundantly issuing database connections for the same tenant, which would hinder horizontal scaling.
  8. How Supavisor architecture works

    main

    Supavisor operates as a highly available cluster of nodes in a cloud environment.

    Key Architectural Concepts:

    • Tenant Configuration: Stored in a highly available Postgres database. Configuration is loaded when a tenant connection pool is initiated.
    • Dynamic Connection Pools: When a client connects, a tenant pool is started and connections to the tenant database are established. The pool's process ID is distributed across the cluster and stored in an in-memory key-value store.
    • Proxying: Subsequent client connections land on an inbound node, and connection data is proxied from the pool node to the client connection node.
    • High Availability: Pool processes are monitored by each node. If a node fails, the process ID is removed from the cluster, and clients will automatically start a new pool upon reconnection to another node.
    • Single Pool Guarantee: To prevent exhausting Postgres connections, only one tenant connection pool should be alive in a cluster at a time. If multiple nodes attempt to start a pool simultaneously, one is gracefully shut down after the process IDs are distributed.