VTGate’s connection pools are actually two distinct pools, one for talking to clients (your application) and another for talking to VTTablet.

# Example: VTGate client connection pool configuration (in vtgateservice.json)
{
  "bind_address": ":15991",
  "grpc_port": 15991,
  "tablet_manager_grpc_port": 15992,
  "mysql_server_port": 15990,
  "cell": "zone1",
  "tablet_manager_protocol": "grpc",
  "grpc_max_message_size": 16777216,
  "service_map": {
    "vtgate": "/debug/vt/vtgate",
    "vtctld": "/debug/vt/vtctld",
    "vt tablet": "/debug/vt/tablet",
    "throttler": "/debug/vt/throttler"
  },
  "access_control": {
    "allow_all": true
  },
  "authentication": {
    "builtin": {
      "users": {
        "user1": "password"
      }
    }
  },
  "gateway_implementation": "grpc",
  "log_dir": "/vt/logs",
  "metrics_dir": "/vt/metrics",
  "tracing": {
    "jaeger": {
      "agent_host": "jaeger-agent",
      "agent_port": 6831
    }
  },
  "cluster_name": "mycluster",
  "vtctld_grpc_addr": "localhost:15999",
  "num_worker_threads": 16,
  "buffer_pool_size": 4194304,
  "session_payload_size": 1024,
  "tx_coordinator_address": "",
  "tx_mode": "multi",
  "tx_timeout": 30,
  "query_timeout": 120,
  "max_workflow_duration": 3600,
  "max_replication_lag": 600,
  "tablet_watch_poll_interval": "1s",
  "resource_manager_address": "",
  "cell_alias": "zone1-alias",
  "enable_active_reparents": true,
  "enable_table_acl_policy": false,
  "enable_query_plan_cache": true,
  "query_plan_cache_size": 10000,
  "schema_reload_interval": "10m",
  "schema_change_listener": [],
  "vtgate_conn_pool": {
    "size": 50,
    "idle_timeout": "5m",
    "max_lifetime": "30m"
  },
  "vtgate_grpc_pool": {
    "size": 50,
    "idle_timeout": "5m",
    "max_lifetime": "30m"
  }
}

VTGate manages two primary connection pools:

  1. Client Connection Pool (VTGate’s internal pool for incoming client connections): This pool is not directly configured by vtgateservice.json. Instead, it’s managed by the underlying gRPC server. The grpc_max_message_size in vtgateservice.json influences the maximum size of individual RPC messages, indirectly affecting how much data can be sent in a single client request. The number of concurrent client connections is largely determined by the OS’s file descriptor limits and the gRPC server’s internal handling of goroutines.

  2. VTTablet Connection Pool (VTGate’s pool for outgoing connections to VTTablet): This is the pool you configure with vtgate_conn_pool and vtgate_grpc_pool (for gRPC connections to VTTablet’s vtctlservice).

    • vtgate_conn_pool: This refers to the pool of MySQL connections VTGate maintains to each VTTablet. When VTGate needs to execute a query against a specific tablet, it will grab a connection from this pool for that tablet.

      • size: The maximum number of idle connections to maintain per tablet. A value of 50 means VTGate will try to keep up to 50 idle MySQL connections open to each VTTablet it interacts with.
      • idle_timeout: Connections idle for longer than 5m (5 minutes) will be closed. This prevents resources from being held indefinitely by unused connections.
      • max_lifetime: Connections will be closed and re-established after 30m (30 minutes), even if they are active. This helps to mitigate issues like memory leaks or stale network states that can accumulate over time.
    • vtgate_grpc_pool: This refers to the pool of gRPC connections VTGate maintains to the vtctlservice endpoint on each VTTablet. These connections are used for administrative tasks and metadata retrieval, not for query execution.

      • size: The maximum number of idle gRPC connections to maintain to each VTTablet’s vtctlservice.
      • idle_timeout: gRPC connections idle for longer than 5m will be closed.
      • max_lifetime: gRPC connections will be closed and re-established after 30m.

The most surprising thing about VTGate’s connection pooling is that the pool for your application’s direct connections isn’t explicitly tunable in vtgateservice.json; it’s implicitly handled by the gRPC framework itself.

Let’s see VTGate in action. Imagine your application makes a SELECT * FROM users WHERE id = 1 query.

  1. The query arrives at VTGate’s gRPC server (listening on bind_address and grpc_port).
  2. VTGate’s query planner determines which tablet(s) users belongs to. Let’s say it’s zone1-0000000001.
  3. VTGate needs to send this query to the VTTablet process running on zone1-0000000001.
  4. VTGate looks in its vtgate_conn_pool for an available MySQL connection to zone1-0000000001.
  5. If a connection is available and healthy, it’s used. If not, VTGate establishes a new MySQL connection (up to the size limit per tablet).
  6. VTGate sends the SELECT query over this MySQL connection to the VTTablet.
  7. VTTablet executes the query against its local MySQL instance, retrieves the data, and sends it back to VTGate.
  8. VTGate formats the result and sends it back to your application over the original incoming gRPC connection.

The vtgate_conn_pool is crucial because establishing new MySQL connections is relatively expensive. By keeping a pool of connections open to each tablet, VTGate can serve incoming queries much faster, avoiding the overhead of connection setup for every single query. The idle_timeout and max_lifetime settings help manage resource utilization and prevent stale connections from causing problems.

A key detail often missed is that the vtgate_conn_pool settings (size, timeouts) are applied per-tablet. If VTGate is routing queries to 100 different tablets, it can potentially maintain up to 100 * vtgate_conn_pool.size MySQL connections concurrently across the system, plus connections for its gRPC communication. This scale is essential for handling distributed workloads.

The next concept to explore is how VTGate handles transactions and their associated connection management, especially in distributed scenarios.

Want structured learning?

Take the full Vitess course →