Vitess es un sistema de clustering para MySQL, nacido en YouTube y graduado en la CNCF, que reparte los datos entre varias instancias MySQL (shards) y presenta el conjunto a la aplicación como una única base de datos compatible con el protocolo MySQL. En este tutorial montarás un clúster de prueba de Vitess en un solo servidor Ubuntu 24.04 con los binarios oficiales y los scripts de ejemplo del proyecto. Con él harás las dos operaciones clave: mover tablas a un keyspace propio con MoveTables y dividir ese keyspace en dos shards con Reshard, todo sin detener las consultas.

Requisitos previos

  • Un servidor de pruebas con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 4 vCPU y 8 GB de RAM. El clúster de ejemplo levanta hasta 12 instancias de MySQL.
  • Un usuario no root con privilegios sudo.
  • Unos 20 GB libres en disco.
  • Conocimientos básicos de MySQL.

Componentes de Vitess

Antes de empezar, conviene conocer las piezas que vas a arrancar:

ComponenteFunción
vtgateProxy sin estado al que se conecta la aplicación con el protocolo MySQL. Enruta cada consulta al shard correcto.
vttabletProceso que acompaña a cada instancia mysqld, gestiona sus conexiones y su replicación. Un shard tiene una tablet primaria y réplicas.
vtctldServidor de administración. Se controla con el cliente vtctldclient.
vtorcDetecta fallos y elige automáticamente una nueva primaria.
etcdServicio de topología donde Vitess guarda keyspaces, shards y tablets.

Un keyspace es una base de datos lógica. Si no tiene sharding, vive en un solo shard llamado 0. Si tiene sharding, se divide por rangos de keyspace_id (por ejemplo -80 y 80-), y el VSchema indica qué columna de cada tabla decide a qué shard va cada fila.

Paso 1: Instalar MySQL y etcd

Vitess necesita los binarios de MySQL 8.0 y de etcd, pero los arrancan sus propios scripts. Instala los paquetes junto con las herramientas que usan los ejemplos:

sudo apt update
sudo apt install -y mysql-server etcd-server etcd-client curl jq

Detén y desactiva los servicios que arrancan por defecto, para que no ocupen los puertos que usará Vitess:

sudo systemctl disable --now mysql etcd

Desactiva el perfil de AppArmor de mysqld:

sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/
sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld

Comprueba que los dos servicios están parados:

systemctl is-active mysql etcd
inactive
inactive

Paso 2: Descargar los binarios de Vitess

Vitess publica un archivo vitess-<versión>-<commit>.tar.gz en cada release de GitHub. Obtén la URL del de la última versión estable:

URL=$(curl -s https://api.github.com/repos/vitessio/vitess/releases/latest \
  | jq -r '.assets[].browser_download_url | select(test("vitess-[0-9.]+-[0-9a-f]+\\.tar\\.gz$"))')
echo "$URL"

Descárgalo y extráelo en /usr/local/vitess:

curl -fLO "$URL"
sudo mkdir -p /usr/local/vitess
sudo tar -xzf "$(basename "$URL")" -C /usr/local/vitess --strip-components=1

Añade los binarios al PATH de tu usuario:

echo 'export PATH=/usr/local/vitess/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

Comprueba la instalación:

vtgate --version
vtgate version Version: 22.0.1 (Git revision ... branch 'HEAD') built on ... by runner@... using go1.24.x linux/amd64

Paso 3: Arrancar el clúster inicial

El paquete incluye un ejemplo completo en examples/local. Cópialo a tu directorio personal, porque los scripts guardan los datos en un subdirectorio vtdataroot junto a ellos:

cp -r /usr/local/vitess/examples ~/vitess-examples
cd ~/vitess-examples/local

Arranca el clúster inicial:

./101_initial_cluster.sh

El script arranca etcd, vtctld, tres instancias de MySQL con sus vttablet (UID 100, 101 y 102) para un keyspace commerce sin sharding, vtorc para elegir la primaria, y vtgate, que escucha el protocolo MySQL en el puerto 15306. También crea las tablas product, customer y corder. Tarda un par de minutos.

Carga las variables de entorno de los ejemplos y define dos alias para no repetir la dirección del servidor en cada comando:

source ../common/env.sh
alias mysql="command mysql --no-defaults -h 127.0.0.1 -P 15306"
alias vtctldclient="command vtctldclient --server localhost:15999"

Estos alias solo existen en la sesión actual. Si abres otra terminal, vuelve a ejecutar las tres líneas desde ~/vitess-examples/local.

Lista las tablets registradas en la topología:

vtctldclient GetTablets
zone1-0000000100 commerce 0 primary 127.0.0.1:15100 127.0.0.1:17100 [] 2026-09-25T10:12:31Z
zone1-0000000101 commerce 0 replica 127.0.0.1:15101 127.0.0.1:17101 [] <null>
zone1-0000000102 commerce 0 rdonly 127.0.0.1:15102 127.0.0.1:17102 [] <null>

Inserta los datos de ejemplo a través de vtgate y consúltalos:

mysql < ../common/insert_commerce_data.sql
mysql --table < ../common/select_commerce_data.sql
Using commerce
Customer
+-------------+--------------------+
| customer_id | email              |
+-------------+--------------------+
|           1 | [email protected]   |
|           2 | [email protected]     |
...

La aplicación ve una base de datos MySQL normal en el puerto 15306, aunque detrás hay tres instancias.

Paso 4: Mover tablas a otro keyspace con MoveTables

Imagina que las tablas customer y corder crecen mucho más rápido que product. El primer paso es separarlas en un keyspace propio, customer, que luego podrás dividir en shards. Arranca las tablets del nuevo keyspace (UID 200 a 202):

./201_customer_tablets.sh

Crea el flujo de MoveTables, que copia los datos existentes y después replica los cambios en tiempo real:

vtctldclient MoveTables --workflow commerce2customer --target-keyspace customer create \
  --source-keyspace commerce --tables 'customer,corder'

Consulta el estado de la copia:

vtctldclient MoveTables --workflow commerce2customer --target-keyspace customer status

Cuando el estado sea Running y la fase de copia haya terminado, compara origen y destino fila a fila con VDiff:

vtctldclient VDiff --workflow commerce2customer --target-keyspace customer create
vtctldclient VDiff --workflow commerce2customer --target-keyspace customer show last

Espera a que el informe muestre "State": "completed" y "HasMismatch": false. Después, cambia el tráfico de lecturas y escrituras al nuevo keyspace:

vtctldclient MoveTables --workflow commerce2customer --target-keyspace customer switchtraffic

Desde este momento vtgate envía al keyspace customer todas las consultas sobre esas tablas, sin que la aplicación cambie nada. Si algo va mal, reversetraffic devuelve el tráfico al origen. Cuando estés conforme, cierra el flujo, lo que borra las tablas copiadas del keyspace de origen:

vtctldclient MoveTables --workflow commerce2customer --target-keyspace customer complete

Comprueba que la consulta sigue funcionando igual:

mysql --table -e "SELECT * FROM customer.customer;"

Paso 5: Preparar el keyspace para sharding

Para dividir customer en shards necesitas tres cosas:

  • Un vindex por tabla que calcule el keyspace_id de cada fila. Aquí se usa un vindex hash sobre customer_id, de modo que un cliente y todos sus pedidos acaban en el mismo shard.
  • Secuencias para los campos autoincrementales, porque cada shard tiene su propio AUTO_INCREMENT y generarían IDs repetidos. Las tablas de secuencia viven en el keyspace sin sharding commerce.
  • Las tablas sin AUTO_INCREMENT en los shards de destino.

El script de ejemplo aplica los cambios de esquema y los VSchema necesarios:

./301_customer_sharded.sh

Revisa el VSchema resultante del keyspace customer:

vtctldclient GetVSchema customer
{
  "sharded": true,
  "vindexes": {
    "hash": {
      "type": "hash"
    }
  },
  "tables": {
    "corder": {
      "column_vindexes": [
        {
          "column": "customer_id",
          "name": "hash"
        }
      ],
      "auto_increment": {
        "column": "order_id",
        "sequence": "order_seq"
      }
    },
    "customer": {
      "column_vindexes": [
        {
          "column": "customer_id",
          "name": "hash"
        }
      ],
      "auto_increment": {
        "column": "customer_id",
        "sequence": "customer_seq"
      }
    }
  }
}

Elegir la columna del vindex es la decisión más importante del diseño: las consultas que filtran por ella van a un solo shard, y las que no la incluyen se envían a todos los shards (scatter), que es más caro.

Paso 6: Dividir el keyspace con Reshard

Arranca las tablets de los dos shards nuevos: -80 (UID 300 a 302) y 80- (UID 400 a 402):

./302_new_shards.sh

Comprueba que cada shard nuevo tiene una primaria:

vtctldclient GetTablets --keyspace customer | grep primary
zone1-0000000200 customer 0 primary 127.0.0.1:15200 127.0.0.1:17200 [] ...
zone1-0000000300 customer -80 primary 127.0.0.1:15300 127.0.0.1:17300 [] ...
zone1-0000000400 customer 80- primary 127.0.0.1:15400 127.0.0.1:17400 [] ...

Crea el flujo de Reshard del shard 0 a los dos nuevos:

vtctldclient Reshard --workflow cust2cust --target-keyspace customer create \
  --source-shards '0' --target-shards '-80,80-'

Sigue el progreso y valida los datos con VDiff, igual que en el paso 4:

vtctldclient Reshard --workflow cust2cust --target-keyspace customer status
vtctldclient VDiff --workflow cust2cust --target-keyspace customer create
vtctldclient VDiff --workflow cust2cust --target-keyspace customer show last

Cambia primero las lecturas de réplicas y, cuando compruebes que todo va bien, las escrituras:

vtctldclient Reshard --workflow cust2cust --target-keyspace customer switchtraffic --tablet-types "rdonly,replica"
vtctldclient Reshard --workflow cust2cust --target-keyspace customer switchtraffic --tablet-types primary

Cierra el flujo:

vtctldclient Reshard --workflow cust2cust --target-keyspace customer complete

Paso 7: Verificar el reparto de datos

Consulta los shards que atienden tráfico:

mysql -e "SHOW VITESS_SHARDS;"
+----------------+
| Shards         |
+----------------+
| commerce/0     |
| customer/-80   |
| customer/80-   |
+----------------+

Cuenta las filas de customer en la primaria de cada shard. La base de datos real en MySQL se llama vt_ seguido del nombre del keyspace:

vtctldclient ExecuteFetchAsDBA zone1-0000000300 "SELECT customer_id FROM vt_customer.customer"
vtctldclient ExecuteFetchAsDBA zone1-0000000400 "SELECT customer_id FROM vt_customer.customer"

Cada shard devuelve una parte distinta de los clientes, y la suma coincide con el total. Mientras tanto, la aplicación sigue viéndolo todo junto:

mysql --table -e "SELECT COUNT(*) FROM customer.customer;"

Para ver cómo enruta vtgate una consulta, usa VEXPLAIN:

mysql -e "VEXPLAIN PLAN SELECT * FROM customer.customer WHERE customer_id = 1\G"

Una consulta con customer_id en el WHERE aparece como EqualUnique (un solo shard), mientras que un SELECT sin filtro aparece como Scatter.

Las interfaces web de vtctld (puerto 15000) y vtgate (puerto 15001, ruta /debug/status) escuchan en el servidor. No abras esos puertos en el firewall; accede a ellas con un túnel SSH desde tu equipo:

ssh -L 15000:127.0.0.1:15000 -L 15001:127.0.0.1:15001 your_user@your_server_ip

Paso 8: Detener y limpiar el clúster

Cuando termines, detén todos los procesos y borra los datos de prueba:

./401_teardown.sh
rm -rf ~/vitess-examples/local/vtdataroot

Solución de problemas

101_initial_cluster.sh falla al arrancar mysqld. Revisa los logs de MySQL en ~/vitess-examples/local/vtdataroot/vt_0000000100/error.log. Si aparecen errores de permisos, el perfil de AppArmor sigue cargado: comprueba con sudo aa-status | grep mysqld que no aparece.

Puertos ocupados (address already in use). El MySQL o el etcd del sistema siguen activos, o quedan procesos de una ejecución anterior. Ejecuta ./401_teardown.sh, comprueba con ss -ltnp qué proceso ocupa el puerto y vuelve a arrancar.

Un shard no tiene primaria. vtorc elige la primaria unos segundos después de arrancar las tablets. Si no ocurre, revisa los logs de vtorc en vtdataroot/tmp/ y lista las tablets con vtctldclient GetTablets.

VDiff informa de diferencias. No cambies el tráfico. Revisa el informe con show last, corrige la causa (normalmente escrituras directas en MySQL que no pasan por vtgate) y lanza un VDiff nuevo.

Conclusión

Has montado un clúster de Vitess, has separado tablas en su propio keyspace con MoveTables y has dividido ese keyspace en dos shards con Reshard, validando los datos con VDiff y cambiando el tráfico sin parar las consultas. Para llevarlo a producción, el siguiente paso habitual es desplegarlo en Kubernetes con el operador oficial de Vitess (vitess-operator), repartir las tablets de cada shard entre varios servidores y activar la autenticación de usuarios en vtgate.