Migra de MySQL a Cloud Spanner

En este artículo, se explica cómo migrar la base de datos de procesamiento de transacciones en línea (OLTP) de MySQL a Cloud Spanner.

Restricciones de migración

Cloud Spanner usa ciertos conceptos de manera diferente a otras herramientas de administración de bases de datos empresariales, por lo que es posible que debas ajustar la arquitectura de tu aplicación para aprovechar al máximo sus capacidades. Es posible que también debas complementar Cloud Spanner con otros servicios de Google Cloud para satisfacer tus necesidades.

Procedimientos y activadores almacenados

Cloud Spanner no admite la ejecución de código de usuario a nivel de base de datos, por lo que, como parte de la migración, la lógica empresarial implementada por los procedimientos y activadores almacenados a nivel de la base de datos se debe mover a la aplicación.

Secuencias

Spanner recomienda usar la versión 4 de UUID como método predeterminado para generar valores de clave primaria. La función GENERATE_UUID() (GoogleSQL, PostgreSQL) muestra los valores de UUID de la versión 4 representados como tipo STRING.

Si necesitas generar valores enteros, Cloud Spanner admite secuencias positivas con inversión de bits (GoogleSQL y PostgreSQL), que producen valores que se distribuyen de manera uniforme en el espacio positivo del número de 64 bits. Puedes usar estos números para evitar problemas de generación de hotspots.

Para obtener más información, consulta el artículo sobre las estrategias de valor predeterminado de la clave primaria.

Controles de acceso

Cloud Spanner admite un control de acceso detallado a nivel de tabla y columna. No se admite el control de acceso detallado para las vistas. Para obtener más información, consulta Acerca del control de acceso detallado.

Restricciones de validación de datos

Spanner admite un conjunto limitado de restricciones de validación de datos en la capa de la base de datos. Si necesitas restricciones de datos más complejas, debes implementarlas en la capa de la aplicación.

En la siguiente tabla, se analizan los tipos de restricciones que suelen encontrarse en las bases de datos de MySQL y cómo implementarlas con Spanner.

Restricción Implementación con Spanner
Not null Restricción de columna NOT NULL
Unique Índice secundario con restricción UNIQUE
Foreign key (para tablas normales) Consulta Crea y administra relaciones de claves externas
Acciones ON DELETE/ON UPDATE de clave externa Solo es posible para tablas intercaladas; si quieres usarlas en otro contexto, tendrás que implementarlas en la capa de la aplicación
Verificaciones de valor y validación mediante restricciones CHECK Consulta Crea y administra restricciones de verificación.
Verificaciones de valor y validación mediante activadores Se implementa en la capa de la aplicación

Columnas generadas

Spanner admite las columnas generadas en las que su valor siempre será generado por una función proporcionada como parte de la definición de la tabla. Al igual que en MySQL, las columnas generadas no se pueden establecer expresamente en un valor proporcionado en una declaración DML.

Las columnas generadas se definen como parte de la definición de columnas durante una instrucción CREATE TABLE o ALTER TABLE en el lenguaje de definición de datos (DDL). A la palabra clave AS le sigue una función de SQL válida y la palabra clave de sufijo obligatoria STORED. La palabra clave STORED forma parte de la especificación de ANSI SQL y también indica que los resultados de la función se almacenarán junto con otras columnas de la tabla.

La función de SQL, la expresión de generación, puede incluir cualquier expresión, función y operador deterministas, y puede usarse en índices secundarios o usarse como una clave externa.

Para obtener más información sobre cómo administrar este tipo de columna, consulta Crea y administra columnas generadas.

Tipos de datos admitidos

MySQL y Spanner admiten diferentes conjuntos de tipos de datos. En la siguiente tabla, se enumeran los tipos de datos de MySQL y sus equivalentes en Spanner. Para obtener definiciones detalladas de cada tipo de datos de Spanner, consulta Tipos de datos.

Es posible que debas transformar aún más los datos, como se describe en la columna Notas, para que los datos de MySQL se ajusten a la base de datos de Spanner. Por ejemplo, puedes almacenar un BLOB grande como objeto en un bucket de Cloud Storage en lugar de hacerlo en la base de datos y, luego, almacenar la referencia de URI al objeto de Cloud Storage en la base de datos como una STRING.

Tipo de datos de MySQL Equivalente en Spanner Notas
INTEGER, INT, BIGINT MEDIUMINT y SMALLINT INT64
TINYINT, BOOL y BOOLEAN BOOL, INT64 Los valores TINYINT(1) se usan para representar valores booleanos de “verdadero” (distinto de cero) o “falso” (0).
FLOAT, DOUBLE FLOAT64
DECIMAL, NUMERIC NUMERIC, STRING En MySQL, los tipos de datos NUMERIC y DECIMAL admiten hasta un total de 65 dígitos de precisión y escalamiento, como se define en la declaración de la columna. El tipo de datos NUMERIC de Spanner admite hasta 38 dígitos de precisión y 9 dígitos decimales de escala.
Si necesitas una precisión mayor, consulta la página Almacena datos numéricos de precisión arbitrarios para ver los mecanismos alternativos.
BIT BYTES
DATE DATE Spanner y MySQL usan el formato “yyyy-mm-dd” para las fechas, por lo que no es necesario realizar ninguna transformación. Se proporcionan funciones de SQL para convertir las fechas en una string con formato.
DATETIME y TIMESTAMP TIMESTAMP Spanner almacena el tiempo independientemente de la zona horaria. Si necesitas almacenar una zona horaria, debes usar una columna STRING independiente. Se proporcionan funciones de SQL para convertir las marcas de tiempo en una string con formato mediante el uso de las zonas horarias.
CHAR y VARCHAR STRING Nota: Spanner usa strings Unicode en todo momento.
VARCHAR admite una longitud máxima de 65,535 bytes, mientras que Spanner admite hasta 2,621,440 caracteres.
BINARY, VARBINARY, BLOB y TINYBLOB BYTES Los objetos pequeños (menos de 10 MiB) se pueden almacenar como BYTES. Para almacenar objetos más grandes, considera usar otras ofertas de Google Cloud, como Cloud Storage.
TEXT, TINYTEXT y ENUM STRING Los valores TEXT pequeños (menos de 10 MiB) se pueden almacenar como STRING. Considera usar ofertas alternativas de Google Cloud, como Cloud Storage, para admitir valores TEXT más grandes.
ENUM STRING La validación de los valores ENUM debe realizarse en la aplicación
SET ARRAY<STRING> La validación de los valores del elemento SET debe realizarse en la aplicación
LONGBLOB, MEDIUMBLOB BYTES o STRING que contienen el URI del objeto. Los objetos pequeños (menos de 10 MiB) se pueden almacenar como BYTES. Para almacenar objetos más grandes, considera usar otras ofertas de Google Cloud, como Cloud Storage.
LONGTEXT, MEDIUMTEXT STRING (que puede contener datos o el URI de un objeto externo) Los objetos pequeños (menos de 2,621,440 caracteres) se pueden almacenar como STRING. Para almacenar objetos más grandes, considera usar otras ofertas de Google Cloud, como Cloud Storage.
JSON JSON Las strings JSON pequeñas (menos de 2,621,440 caracteres) se pueden almacenar como JSON. Para almacenar objetos más grandes, considera usar otras ofertas de Google Cloud, como Cloud Storage.
GEOMETRY, POINT, LINESTRING, POLYGON, MULTIPOINT, MULTIPOLYGON y GEOMETRYCOLLECTION Spanner no admite tipos de datos geoespaciales. Debes almacenar estos datos mediante los tipos de datos estándar e implementar cualquier lógica de búsqueda o filtrado en la capa de la aplicación.

Proceso de migración

Un cronograma general del proceso de migración incluiría los pasos que se indican a continuación:

  1. Convertir tu esquema y modelo de datos
  2. Traducir las consultas de SQL que uses
  3. Migrar la aplicación para usar Spanner además de MySQL
  4. Exportar los datos de MySQL de forma masiva e importarlos a Spanner mediante Dataflow
  5. Mantener la coherencia entre ambas bases de datos durante la migración
  6. Migrar la aplicación fuera de MySQL

Paso 1: Convierte la base de datos y el esquema

Debes convertir el esquema existente en un esquema de Spanner para almacenar los datos. Para simplificar las modificaciones de la aplicación, asegúrate de que el esquema convertido coincida lo más posible con el esquema de MySQL existente. Sin embargo, debido a las diferencias en las funciones, se podrían necesitar algunos cambios.

El uso de las prácticas recomendadas en el diseño de esquemas puede ayudarte a aumentar la capacidad de procesamiento y a reducir los puntos problemáticos en la base de datos de Spanner.

Claves primarias

En Spanner, cada tabla que debe almacenar más de una fila debe tener una clave primaria compuesta por una o más columnas. La clave primaria de la tabla identifica de manera única cada fila de una tabla, y Spanner usa la clave primaria para ordenar las filas de la tabla. Debido a que Spanner tiene mucha distribución, es importante que elijas una técnica de generación de clave primaria que escale bien con el crecimiento de tus datos. Para obtener más información, consulta las estrategias de migración de claves primarias que recomendamos.

Ten en cuenta que, después de designar tu clave primaria, no podrás agregar ni quitar una columna de clave primaria, ni cambiar un valor de clave primaria sin borrar y volver a crear la tabla. Para obtener más información sobre cómo designar tu clave primaria, consulta Esquema y modelo de datos: claves primarias.

Intercala tus tablas

Spanner tiene una función que te permite definir una relación de superior y secundario de tipo uno a varios entre dos tablas. Esta función intercala las filas de datos secundarias con las filas superiores en el almacenamiento, lo que permite una unión previa de la tabla y mejora la eficiencia de la recuperación de datos cuando se consultan datos del nivel superior y del secundario a la vez.

La clave primaria de la tabla secundaria debe comenzar con las columnas de la clave primaria de la tabla superior. Desde la perspectiva de la fila secundaria, la clave primaria de la fila superior se denomina clave externa. Puedes definir hasta 6 niveles de relaciones entre tablas superiores y secundarias.

Puedes definir acciones de eliminación para las tablas secundarias en las que indicas qué sucede cuando se borra la fila superior: se borran todas las filas secundarias o se impide la eliminación de la fila superior mientras existen filas secundarias.

A continuación, te mostramos un ejemplo de cómo crear una tabla de Álbumes intercalada en la tabla superior de Cantantes definida anteriormente:

CREATE TABLE Albums (
  SingerId     INT64 NOT NULL,
  AlbumId      INT64 NOT NULL,
  AlbumTitle   STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId)
INTERLEAVE IN PARENT (Singers)
ON DELETE CASCADE;

Crea índices secundarios

También puedes crear índices secundarios para indexar datos dentro de la tabla aparte de la clave primaria. Spanner implementa índices secundarios de la misma manera que las tablas, por lo que los valores de columnas que se usarán como claves de índice tendrán las mismas restricciones que las claves primarias de las tablas. Esto también significa que los índices tienen las mismas garantías de coherencia que las tablas de Spanner.

Las búsquedas de valores con índices secundarios son, en la práctica, lo mismo que una consulta con una unión de tablas. Para mejorar el rendimiento de las consultas con índices, puedes almacenar copias de los valores de las columnas de la tabla original en el índice secundario mediante la cláusula STORING, lo que la convierte en un índice de cobertura.

El optimizador de consultas de Spanner solo usa un índice secundario de manera automática cuando el índice almacena todas las columnas que se consultan (una consulta cubierta). Para forzar el uso de un índice cuando se consultan columnas de la tabla original, debes usar una directiva FORCE INDEX como la siguiente en la instrucción de SQL:

SELECT *
FROM MyTable@{FORCE_INDEX=MyTableIndex}
WHERE IndexedColumn=@value

Se pueden usar los índices a fin de aplicar valores únicos dentro de una columna de la tabla; para ello, se define un índice UNIQUE en esa columna. Este índice impedirá que se agreguen valores duplicados.

A continuación, se incluye una instrucción de DDL de ejemplo en la que se crea un índice secundario para la tabla de Álbumes:

CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle);

Si creas índices adicionales después de que se cargan los datos, es posible que lleve un poco de tiempo para propagarse. Te recomendamos que limites la frecuencia con la que los agregas a un promedio de tres por día. Para obtener más indicaciones sobre cómo crear índices secundarios, consulta Índices secundarios. Para obtener más información sobre las limitaciones en la creación de índices, consulta Actualizaciones del esquema.

Paso 2: Traduce las consultas de SQL

Spanner usa el dialecto ANSI 2011 de SQL con extensiones y tiene muchas funciones y operadores para ayudarte a traducir y a agregar los datos. Cualquier consulta de SQL que use dialectos, funciones y tipos específicos de MySQL deberá convertirse para ser compatible con Spanner.

Aunque Spanner no admite datos estructurados como definiciones de columnas, puedes usar datos estructurados en consultas de SQL mediante el uso de los tipos ARRAY<> y STRUCT<>. Por ejemplo, puedes escribir una consulta que muestre todos los álbumes de un artista mediante un ARRAY de STRUCT (esto permite aprovechar los datos ya asociados). Para obtener más información, consulta la sección Subconsultas de la documentación.

Las consultas de SQL se pueden perfilar mediante la interfaz de consulta de Spanner en la consola de Google Cloud para ejecutar la consulta. En general, las consultas que realizan análisis de tablas completos en tablas grandes son muy costosas y deben usarse con moderación. Para obtener más información sobre cómo optimizar las consultas de SQL, consulta la documentación de prácticas recomendadas de SQL.

Paso 3: Migra tu aplicación para usar Spanner

Spanner proporciona un conjunto de bibliotecas cliente para varios lenguajes y la capacidad de leer y escribir datos mediante llamadas a la API específicas de Spanner, así como mediante el uso de consultas de SQL y declaraciones de lenguaje de modificación de datos (DML). El uso de llamadas a la API puede ser más rápido para algunas consultas, como las lecturas de filas directas por clave, ya que no es necesario traducir la instrucción de SQL.

También puedes usar el controlador de la conectividad a bases de datos de Java (JDBC) para conectarte a Spanner, lo que te permite aprovechar las herramientas existentes y la infraestructura sin integración nativa.

Como parte del proceso de migración, las funciones que no están disponibles en Spanner, como se mencionó antes, deben implementarse en la aplicación. Por ejemplo, si usas un activador para verificar los valores de datos y actualizar una tabla relacionada, tendrás que implementarlo en la aplicación mediante una transacción de lectura y escritura a fin de leer la fila existente, verificar las restricciones y escribir las filas actualizadas en ambas tablas.

Spanner ofrece transacciones de solo lectura y de lectura y escritura, que garantizan la coherencia externa de los datos. Además, se pueden aplicar límites de marca de tiempo a las transacciones de lectura, en cuyo caso se lee una versión coherente de los datos de las siguientes maneras:

  • En un momento exacto del pasado (hasta hace 1 hora)
  • En el futuro (en cuyo caso la lectura se bloquea hasta que llegue ese momento)
  • Con una cantidad aceptable de obsolescencia limitada; en este caso, se mostrará una vista coherente hasta algún tiempo en el pasado sin necesidad de verificar que los datos posteriores estén disponibles en otra réplica Esto puede ser beneficioso en términos de rendimiento, pero tiene la desventaja de que los datos podrían estar obsoletos.

Paso 4: Transfiere tus datos de MySQL a Spanner

Para transferir los datos de MySQL a Spanner, debes exportar la base de datos de MySQL a un formato de archivo portátil (por ejemplo, XML) y, luego, importar esos datos a Spanner mediante Dataflow.

transfiere datos de MySQL a Spanner

Realiza una exportación masiva desde MySQL

La herramienta mysqldump incluida en MySQL puede exportar toda la base de datos a archivos XML con formato correcto. Como alternativa, puedes usar la instrucción de SQL SELECT ... INTO OUTFILE a fin de crear archivos CSV para cada tabla. Sin embargo, este enfoque tiene la desventaja de que solo se puede exportar una tabla a la vez, lo que significa que debes pausar la aplicación o desactivar la base de datos a fin de que esta permanezca en un estado coherente para la exportación.

Después de exportar estos archivos de datos, te recomendamos subirlos a un bucket de Cloud Storage a fin de que se pueda acceder a ellos para su importación.

Realiza una importación masiva a Spanner

Debido a que es probable que los esquemas de la base de datos difieran entre MySQL y Spanner, es posible que debas hacer que algunas conversiones de datos sean parte del proceso de importación. Usar Dataflow es la forma más sencilla de realizar estas conversiones e importar los datos a Spanner. Dataflow es el servicio distribuido de extracción, transformación y carga (ETL) de Google Cloud. Proporciona una plataforma para ejecutar canalizaciones de datos escritas con el SDK de Apache Beam a fin de leer y procesar grandes cantidades de datos en paralelo en varias máquinas.

El SDK de Apache Beam requiere que escribas un programa de Java sencillo para configurar la lectura, la transformación y la escritura de los datos. Existen conectores de Beam para Cloud Storage y Spanner, por lo que el único código que debes escribir es la transformación de datos.

Para ver un ejemplo de una canalización simple que lee desde archivos CSV y escribe en Spanner, consulta el repositorio de código de muestra.

Si se usan tablas intercaladas superiores y secundarias en el esquema de Spanner, se debe tener cuidado en el proceso de importación para que la fila superior se cree antes que la secundaria. El código de canalización de importación de Spanner se encarga de esto. Para ello, importa primero todos los datos de las tablas de nivel raíz; luego, todas las tablas secundarias de nivel 1; luego, todas las tablas secundarias de nivel 2 y así sucesivamente.

Puedes usar la canalización de importación de Spanner directamente para importar de forma masiva los datos, pero este enfoque requiere que los datos existan en archivos Avro con el esquema correcto.

Paso 5: Mantén la coherencia entre ambas bases de datos

Muchas aplicaciones tienen requisitos de disponibilidad que hacen imposible mantener la aplicación sin conexión durante el tiempo necesario para exportar y, además, importar los datos. Por lo tanto, mientras transfieres los datos a Spanner, la aplicación continúa modificando la base de datos existente. Por lo tanto, es necesario duplicar las actualizaciones de la base de datos de Spanner mientras se ejecuta la aplicación.

Existen varios métodos para mantener las dos bases de datos sincronizadas, incluida la captura de datos modificados y la implementación de actualizaciones simultáneas en la aplicación.

Captura de datos modificados

MySQL no tiene una utilidad de captura de datos modificados (CDC) nativa. Sin embargo, hay varios proyectos de código abierto que pueden recibir registros binarios de MySQL y convertirlos en una transmisión de CDC. Por ejemplo, el daemon de Maxwell puede proporcionar una transmisión de CDC para la base de datos.

Puedes escribir una aplicación que se suscriba a esta transmisión y aplique las mismas modificaciones (después de la conversión de datos, por supuesto) a la base de datos de Spanner.

Actualizaciones simultáneas en ambas bases de datos desde la aplicación

Un método alternativo es modificar la aplicación para realizar escrituras en ambas bases de datos. Una base de datos (en principio, MySQL) se consideraría la fuente de información, y después de cada escritura de la base de datos, la fila completa se lee, se convierte y se escribe en la base de datos de Spanner. De esta manera, la aplicación reemplaza de forma constante las filas de Spanner por los datos más recientes.

Cuando estés seguro de que todos los datos se transfirieron de forma correcta, puedes cambiar la fuente de información a la base de datos de Spanner. Este mecanismo proporciona una ruta de reversión si se detectan problemas cuando se realiza el cambio a Spanner.

Verifica la coherencia de los datos

A medida que los datos se transmiten a la base de datos de Spanner, puedes ejecutar una comparación de forma periódica entre los datos de Spanner y MySQL para asegurarte de que sean coherentes. Para validar la coherencia, puedes consultar ambas fuentes de datos y comparar los resultados.

Puedes usar Dataflow para realizar una comparación detallada en conjuntos de datos grandes mediante la transformación de unión. Esta transformación toma 2 conjuntos de datos con clave y hace coincidir los valores por clave. Luego, los valores pueden compararse para determinar si son iguales. Puedes ejecutar esta verificación con regularidad hasta que el nivel de coherencia coincida con tus requisitos empresariales.

Paso 6: Cambia a Spanner como fuente de información de la aplicación

Cuando estés seguro de la migración de datos, puedes cambiar la aplicación para usar Spanner como fuente de información. Si continúas reescribiendo los cambios en la base de datos de MySQL, esto la mantiene actualizada, lo que proporciona una ruta de reversión en caso de que surjan problemas.

Por último, puedes inhabilitar y quitar el código de actualización de la base de datos de MySQL y cerrar la base de datos de MySQL que quedó obsoleta.

Importa y exporta bases de datos de Spanner

De manera alternativa, puedes exportar las tablas de Spanner a un bucket de Cloud Storage mediante el uso de una plantilla de Dataflow para realizar la exportación. La carpeta resultante contiene un conjunto de archivos Avro y archivos de manifiesto JSON con las tablas exportadas. Estos archivos pueden servir para diversos propósitos, incluidos los que se indican a continuación:

  • Crear copias de seguridad de la base de datos para usarlas en la recuperación ante desastres o cumplir con una política de retención de datos
  • Importar el archivo Avro a otras ofertas de Google Cloud, como BigQuery

Para obtener más información sobre el proceso de exportación e importación, consulta Importa bases de datos y Exporta bases de datos.

¿Qué sigue?