--- title: "Vitess en Ubuntu 24.04: sharding horizontal de MySQL" description: "Monta un clúster de Vitess en Ubuntu 24.04, mueve tablas entre keyspaces con MoveTables y divide un keyspace en dos shards con Reshard sin parar MySQL." category: "Operaciones de Base de Datos" language: es source: https://cubepath.com/es/docs/operaciones-de-base-de-datos/vitess-escalado-horizontal-de-mysql updated: 2026-09-25 --- # Vitess en Ubuntu 24.04: sharding horizontal de MySQL 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. > Advertencia: la guía desactiva el perfil de AppArmor de `mysqld`, porque Vitess arranca instancias de MySQL con directorios de datos propios que ese perfil bloquea. Hazlo en un servidor dedicado a pruebas, no en uno que ya ejecute MySQL en producción. ## Componentes de Vitess Antes de empezar, conviene conocer las piezas que vas a arrancar: | Componente | Función | |---|---| | `vtgate` | Proxy sin estado al que se conecta la aplicación con el protocolo MySQL. Enruta cada consulta al shard correcto. | | `vttablet` | Proceso que acompaña a cada instancia `mysqld`, gestiona sus conexiones y su replicación. Un shard tiene una tablet primaria y réplicas. | | `vtctld` | Servidor de administración. Se controla con el cliente `vtctldclient`. | | `vtorc` | Detecta fallos y elige automáticamente una nueva primaria. | | etcd | Servicio 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: ```bash 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: ```bash sudo systemctl disable --now mysql etcd ``` Desactiva el perfil de AppArmor de `mysqld`: ```bash 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: ```bash systemctl is-active mysql etcd ``` ```output inactive inactive ``` ## Paso 2: Descargar los binarios de Vitess Vitess publica un archivo `vitess--.tar.gz` en cada release de GitHub. Obtén la URL del de la última versión estable: ```bash 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`: ```bash 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: ```bash echo 'export PATH=/usr/local/vitess/bin:$PATH' >> ~/.bashrc source ~/.bashrc ``` Comprueba la instalación: ```bash vtgate --version ``` ```output 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: ```bash cp -r /usr/local/vitess/examples ~/vitess-examples cd ~/vitess-examples/local ``` Arranca el clúster inicial: ```bash ./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: ```bash 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: ```bash vtctldclient GetTablets ``` ```output 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 [] zone1-0000000102 commerce 0 rdonly 127.0.0.1:15102 127.0.0.1:17102 [] ``` Inserta los datos de ejemplo a través de `vtgate` y consúltalos: ```bash mysql < ../common/insert_commerce_data.sql mysql --table < ../common/select_commerce_data.sql ``` ```output Using commerce Customer +-------------+--------------------+ | customer_id | email | +-------------+--------------------+ | 1 | alice@domain.com | | 2 | bob@domain.com | ... ``` 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): ```bash ./201_customer_tablets.sh ``` Crea el flujo de `MoveTables`, que copia los datos existentes y después replica los cambios en tiempo real: ```bash vtctldclient MoveTables --workflow commerce2customer --target-keyspace customer create \ --source-keyspace commerce --tables 'customer,corder' ``` Consulta el estado de la copia: ```bash 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: ```bash 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: ```bash 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: ```bash vtctldclient MoveTables --workflow commerce2customer --target-keyspace customer complete ``` Comprueba que la consulta sigue funcionando igual: ```bash 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: ```bash ./301_customer_sharded.sh ``` Revisa el VSchema resultante del keyspace `customer`: ```bash vtctldclient GetVSchema customer ``` ```output { "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): ```bash ./302_new_shards.sh ``` Comprueba que cada shard nuevo tiene una primaria: ```bash vtctldclient GetTablets --keyspace customer | grep primary ``` ```output 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: ```bash 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: ```bash 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: ```bash 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: ```bash vtctldclient Reshard --workflow cust2cust --target-keyspace customer complete ``` ## Paso 7: Verificar el reparto de datos Consulta los shards que atienden tráfico: ```bash mysql -e "SHOW VITESS_SHARDS;" ``` ```output +----------------+ | 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: ```bash 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: ```bash mysql --table -e "SELECT COUNT(*) FROM customer.customer;" ``` Para ver cómo enruta `vtgate` una consulta, usa `VEXPLAIN`: ```bash 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: ```bash 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: ```bash ./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`.