Vitess keyspace routing rules let you precisely control which underlying MySQL shard a specific query will hit, even within a single keyspace.
Let’s see it in action. Imagine we have a customers keyspace with two shards, 0 and 1. Normally, Vitess uses a sharding key (e.g., customer_id) to decide where a query goes. But what if we have a special, high-priority customer, say customer_id = 12345, and we want all their queries to go directly to shard 0, bypassing the normal sharding logic? This is where routing rules shine.
Here’s a simplified vtgate configuration showing a basic keyspace definition:
{
"keyspaces": {
"customers": {
"sharded": true,
"vnodes": 16,
"replicas": 3,
"partition_key_type": "INT64",
"partition_name": "customer_id",
"durability_policy": "none"
}
}
}
Without routing rules, a query like SELECT * FROM orders WHERE customer_id = 12345 would be routed to shard 0 or 1 based on the customer_id modulo 2 (assuming a simple sharding scheme).
Now, let’s add a routing rule to always send queries for customer_id = 12345 to shard 0. This is done via the vtctld command-line tool or the Vitess API. Using vtctld:
vtctldclient ApplyRoutingRules \
--keyspace=customers \
--json='{
"rules": [
{
"description": "Route specific customer to shard 0",
"match_table_name": "orders",
"conditions": [
{
"field": "customer_id",
"op": "=",
"value": "12345"
}
],
"destination_shard": "0"
}
]
}'
What this rule tells Vitess is: "If a query targets the orders table and has a customer_id that exactly equals 12345, then send that query to the shard named 0 within the customers keyspace." The destination_shard field refers to the shard name as defined in your topology.
The mental model here is a cascaded decision process within vtgate. First, vtgate checks if any routing rules apply to the incoming query based on the table name and any specified conditions (like customer_id = 12345). If a rule matches, vtgate uses the specified destination_shard and bypasses the usual sharding logic. If no routing rule matches, vtgate falls back to its standard sharding mechanism, which uses the sharding key to pick a shard.
This allows for fine-grained control. You could route all queries for a specific tenant (if tenant_id were the sharding key) to a dedicated shard, or, as in our example, isolate a single, critical customer. This is invaluable for performance tuning, isolating specific workloads, or implementing phased rollouts where certain data subsets need special handling. The match_table_name is important because routing rules are table-specific; you can have different rules for different tables within the same keyspace. The conditions can be more complex, allowing for IN clauses and other operators, though equality is the most common for direct routing.
The true power comes when you realize that these rules are dynamic. You can apply, modify, or remove them at runtime without restarting vtgate instances, allowing for immediate adjustments to traffic flow based on real-time conditions or operational needs. This makes Vitess incredibly flexible for managing complex, high-throughput database environments.
The next step is understanding how to combine multiple routing rules and the precedence they have when multiple rules might potentially match a single query.