Usa Cloud SQL para MySQL de segunda generación como base de datos de backend en juegos para dispositivos móviles

Last reviewed 2022-10-28 UTC

Un patrón verificado para compilar un backend de juego en línea usa una base de datos relacional, como MySQL. Esta base de datos almacena el estado del mundo del juego y los datos de persistencia esenciales. Para juegos básicos basados en sesiones, la base de datos no contiene nada más complicado que los resultados finales de los partidos. En caso de los juegos multijugador masivos en línea (MMO) grandes, de mundo persistente, podría ser un conjunto complicado de tablas interrelacionadas que contienen la progresión de los jugadores y el inventario. La velocidad de las consultas en la capa de la base de datos de tu backend afecta directamente la experiencia del usuario en cuanto a la respuesta en el cliente del juego.

Si bien el patrón resulta familiar, la mayoría de los equipos de desarrollo de juegos no tienen un administrador de base de datos dedicado y, a medida que la base de datos crece en tamaño y las relaciones que modela se vuelven más complejas, la administración puede convertirse en una tarea que muchos equipos preferirían delegar. En los juegos para dispositivos móviles de tamaño pequeño a mediano, asíncronos y por turnos, una base de datos como Google Cloud SQL puede ser una excelente opción. Cloud SQL para MySQL de segunda generación ofrece una instancia completamente alojada y administrada de MySQL con un rendimiento sólido, operaciones mínimas y copias de seguridad automatizadas.

Diseño del patrón de base de datos basado en servicios

Descripción general de la arquitectura de la base de datos

El paradigma de los microservicios resulta útil en el caso los backend de las bases de datos de los juegos para dispositivos móviles. Un diseño común es que la base de datos esté encabezada por un servicio de base de datos, que está formado por un grupo de procesos de trabajo que acepta resultados de consultas desde el frontend del juego, ejecuta esas consultas en la base de datos y muestra los resultados.

Ventajas del patrón de base de datos basado en servicios

Hacer que un servicio intermediario consulte la base de datos en nombre de los servidores del juego presenta diferentes ventajas:

  • Mayor disponibilidad: Las bases de datos generalmente limitan la cantidad de conexiones simultáneas. Un servicio desvincula la cantidad de servidores de juego que pueden realizar solicitudes a la base de datos de la cantidad máxima de conexiones permitidas.
  • Tolerancia de errores: Los servicios de la base de datos se pueden compilar para que procesen solicitudes de manera temporal si la base de datos experimenta algún problema.
  • Solicitudes optimizadas: Un servicio de base de datos puede optimizar las solicitudes de base de datos y proporcionar la siguiente información:
    • Validación de consultas
    • Priorización de consultas
    • Control del flujo de tasa de consultas
    • Almacenamiento en caché de lectura en la memoria
  • Abstracción de la base de datos: Siempre que el contrato de servicio se cumpla, el servicio de base de datos y la base de datos que lo respalda pueden reemplazarse sin modificaciones en los servidores de juegos del frontend. Este diseño posibilita el uso de diferentes bases de datos en entornos de desarrollo o QA, como la migración a una tecnología de base de datos diferente en producción.

Un patrón de base de datos basado en servicios para juegos

En el siguiente diagrama, se ilustra cómo compilar un patrón de base de datos sólido basado en servicios mediante los servicios de Google Cloud Platform.

Patrón de base de datos mediante Google Cloud Platform

Se puede compilar un patrón de base de datos sólido basado en servicios mediante los siguientes componentes:

  • Frontend/servidores de juegos dedicados: Las aplicaciones cliente de juegos se conectan directamente con los servidores de juegos y los convierten en un servicio de frontend. Los servidores de juegos dedicados suelen ser ejecutables personalizados, que se compilan mediante el motor del juego y deben ejecutarse en hardware virtualizado, como las VM de Google Compute Engine. Si escribes un juego en el que la interacción en línea se puede modelar con una semántica de solicitud o respuesta de estilo HTTP, Google App Engine también es una buena opción.

  • Comunicación del servidor de juegos con los servicios de base de datos: Por lo general, esto se modela mediante el estilo de acceso crear, leer, actualizar y borrar (CRUD), por lo que la creación de una API de REST o un extremo de gRPC en Compute Engine es una buena opción.

  • Comunicación del extremo de API/RPC con un grupo de trabajadores de la base de datos: Es un caso típico de puesta en cola. Las opciones populares son softwares middleware en cola autoadministrados y de código abierto, como RabbitMQ o ZeroMQ. En Cloud Platform, puedes usar Google Cloud Pub/Sub, que es seguro y duradero, además de tener alta disponibilidad. Ofrece una solución de colas administrada sin necesidad de administrar servidores.

  • Trabajadores de bases de datos que se conectan con Cloud SQL de segunda generación: Los trabajadores de la base de datos pueden escribirse en cualquier lenguaje que proporcione un método de acceso a MySQL actualizado. Estos trabajadores pueden administrarse de forma manual en Compute Engine, o se los puede empaquetar en contenedores Docker a fin de que sean fáciles de administrar mediante el DSL de Kubernetes en Google Kubernetes Engine.

Debes tener en cuenta algunas limitaciones cuando utilices Cloud SQL de segunda generación:

  • Límite de tamaño de base de datos de 10 TB
  • Límite de conexión de 4,000 conexiones simultáneas
  • Falta de compatibilidad con NDB (fragmentación), aunque se admiten las réplicas

A fin de abordar estas cuestiones, haz lo siguiente:

  • Elige un modelo de datos que optimice la cantidad de datos almacenados.

  • Incorpora procesos que saquen los datos a los que rara vez se accede de la base de datos primaria y que los coloquen en un almacén de datos, como Google BigQuery.

  • Utiliza un patrón según el cual los servidores de juegos accedan a la base de datos a través de un microservicio. Incluso si la cantidad de jugadores es lo suficientemente baja como para que los servidores de juego puedan acceder a la base de datos directamente, existen diferentes ventajas relacionadas con desvincular la capa de base de datos del servidor del juego: puesta en cola, nivelación de la tasa de consultas, tolerancia a errores en la conexión, y más. Además, agregar una capa separada de acceso a la base de datos una vez que el juego se haya vuelto popular puede ocasionar tiempo de inactividad y pérdida de ingresos.

  • Ejecuta las estadísticas del juego y la telemetría del jugador en una réplica de solo lectura de la base de datos. De esta manera, evitas que los análisis tengan un impacto en el tiempo de respuesta de la base de datos. Cloud SQL para MySQL de segunda generación permite la replicación estándar de MySQL. Además, puedes dimensionar tu segunda instancia de manera correcta para que las consultas de estadísticas mantengan los costos de manera marginal.

Diseño de muestra: un juego social masivo para un jugador (MASS)

Un paradigma de juego emergente en la última década consiste en una cantidad masiva de jugadores individuales que juegan sesiones en línea de manera simultánea, con mecanismos sociales, como el préstamo y el comercio de unidades, y la tabla de clasificaciones como el único punto de contacto entre los jugadores. Algunos ejemplos de juegos MASS son Puzzle and Dragons™ y Monster Strike™. Los juegos MASS para dispositivos móviles se compilan con el objetivo de ser económicos en cuanto a la comunicación entre el cliente y el servidor. Esto hace posible que los usuarios disfruten su juego incluso cuando tengan una conectividad limitada o esporádica. El modelo de datos para un juego como este, en el cual casi todo el almacenamiento de estado persistente está relacionado con el metajuego (recolectar unidades y mantener la moneda del jugador), produce dos tipos básicos de objetos que se almacenan en la base de datos. Esos objetos pueden manipularse fácilmente con mecanismos CRUD.

Objetos del jugador, que hacen un seguimiento de lo siguiente:

  • Monedas reales y del juego
  • Cantidad total de ranuras para las unidades
  • Energía
  • Experiencia

Objetos de las unidades, que hacen un seguimiento de lo siguiente:

  • Propietario (ID del jugador)
  • Experiencia
  • Valor de adquisición
  • Inventario de la unidad

Para menos de 100,000 jugadores, este modelo de datos se adapta correctamente a una base de datos relacional, como Cloud SQL de segunda generación.

Mimus

Mimus es una simulación de aplicación de juegos MASS para dispositivos móviles con un backend del estilo de Puzzle and Dragons™ o Monster Strike™. En ella, se supone que cada jugador puede acceder desde un solo dispositivo a la vez y que debe completar cualquier acción antes de comenzar otra. Con Mimus, puedes ejecutar cargas de trabajo simultáneas a fin de evaluar la capacidad óptima de la arquitectura, que normalmente se basa en la cantidad de usuarios simultáneos (CCU).

Puedes encontrar el código fuente de Mimus en https://github.com/GoogleCloudPlatform/mimus-game-simulator.

Descripción general de la arquitectura de Mimus

Simulación de cliente de Mimus dentro del servidor de Mimus

En los juegos MASS, el desarrollador del juego puede controlar la velocidad con la que el cliente del juego genera consultas a la base de datos; para ello, le solicita al jugador que mire animaciones o que interactúe con el cliente del juego a fin de continuar. Mimus simula estas estrategias de límite de frecuencia mediante llamadas sleep(). De esta manera, Mimus simula una aproximación razonable de carga de la base de datos por cliente mediante la ejecución de tantos procesos como jugadores simultáneos. Esto se organiza de manera eficiente mediante un pod de cliente/servidor de Mimus en un contenedor, en un clúster de Kubernetes que genera consultas en la base de datos.

Este cliente de juego Mimus simula comunicaciones con el servidor de backend mediante un circuito continuo que llama directamente a los procedimientos del servidor de Mimus. Para ello, selecciona llamadas funcionales basadas en el estado del jugador y de su inventario.

Entre las acciones del jugador que Mimus simula se incluyen las siguientes:

  • Jugar una ronda del juego
  • Comprar moneda
  • Gastar moneda
  • Subir de nivel o evolucionar unidades

Cada una de estas acciones se implementa como interacciones CRUD múltiples con los objetos del jugador o la unidad, que el cliente manipula mediante llamadas al servidor de Mimus. El servidor de Mimus realiza estas solicitudes de base de datos mediante la API de la base de datos de Mimus síncrona (de bloqueo). Esta API es un módulo de Python importado por el servidor de Mimus y se puede configurar para que pruebe diferentes implementaciones de backend de bases de datos.

Comunicación de la API de la base de datos de Mimus con el grupo de trabajadores de la base de datos de Mimus

En el siguiente diagrama, se ilustra la comunicación entre el servidor de Mimus y el servicio de la base de datos.

Diseño de la comunicación de Mimus

La API de la base de datos de Mimus acepta lotes de consultas de base de datos y muestra los resultados. Publica estos lotes como mensajes de Cloud Pub/Sub y espera a que los resultados se muestren mediante Redis. Antes de enviar un mensaje, la API de la base de datos valida todos los valores que se escribirán en la base de datos y etiqueta el mensaje con un ID de transacción único. Luego, el mensaje se publica en un tema Work en Cloud Pub/Sub. A continuación, la API de la base de datos realiza ciclos y busca la existencia del ID de transacción como una clave de Redis. La API de la base de datos recupera los resultados en el valor de la clave y los devuelve al servidor de Mimus, en el que se ponen a disposición del cliente de Mimus.

Consideraciones sobre la selección de comunicación

Mimus utiliza Cloud Pub/Sub para la comunicación de consultas pendientes, ya que las acciones de los usuarios requieren durabilidad y entrega confiable. Mimus utiliza Redis a fin de comunicar los resultados cuando la durabilidad y confiabilidad son menos importantes. Si los resultados se pierden debido a un error en la aplicación o un error de Redis, el cliente de Mimus consulta nuevamente los resultados finales en la base de datos. Con las transacciones en una base de datos relacional, se garantiza que se realizaron todos los cambios solicitados, o que no se realizó ninguno. Gracias a que es poco frecuente que Mimus necesite realizar una segunda solicitud, se considera una concesión aceptable a cambio de la simplicidad y la velocidad de recuperación que brinda Redis. Para que el uso de Redis sea razonable, se permite que los resultados de la solicitud venzan en Redis luego de 30 segundos.

Grupo de trabajadores de la base de datos de Mimus

El grupo de trabajadores de la base de datos de Mimus contiene múltiples procesos que se ejecutan en Kubernetes Engine. Cada instancia de contenedor en ejecución analiza el tema Work de Cloud Pub/Sub en un bucle infinito en busca de mensajes nuevos. Cuando recibe un mensaje, ejecuta las consultas en el mensaje mediante el módulo Python MySQLdb. Un solo mensaje representa una transacción relacional y puede contener consultas múltiples. Todas las consultas en el mensaje deben completarse antes de que se confirmen en la base de datos. Una vez que se hayan completado las consultas (o que hayan arrojado un error), el trabajador de la base de datos publica los resultados en Redis con el ID de transacción recibido como parte del mensaje original.

Base de datos de Mimus

La base de datos relacional que respalda el servicio de base de datos de Mimus es una instancia de Cloud SQL para MySQL de segunda generación. Cuando creas la instancia, puedes seleccionar opciones de configuración de la máquina de hasta 32 núcleos y 208 GB de RAM, con discos de hasta 10 TB de almacenamiento. Además de admitir réplicas, las instancias de segunda generación de Cloud SQL están configuradas para ejecutar copias de seguridad periódicas de forma predeterminada. Si necesitas un ajuste de MySQL adicional, puedes establecer marcas de MySQL específicas en la instancia de Cloud SQL. Si deseas obtener más información acerca de la configuración, consulta la documentación de Cloud SQL.

Conclusiones obtenidas tras probar Cloud SQL con Mimus

Tipo de máquina SG de Cloud SQL Cantidad recomendada de usuarios simultáneos
n1-standard-4 15,000
n1-standard-8 30,000
n1-standard-16 60,000
n1-standard-32 120,000
n1-highmem-8 50,000
n1-highmem-16 100,000
n1-highmem-32 200,000

Cuando se utilizó el agente de prueba de Mimus a fin de simular 100,000 usuarios simultáneos en la instancia de Cloud SQL para MySQL de segunda generación que se creó en una instancia n1-highmem-16 de Compute Engine, el tiempo de respuesta de la consulta se mantuvo inferior a 2 segundos en toda la prueba.

Si estás compilando un juego MASS para dispositivos móviles y necesitas admitir cientos de miles de jugadores simultáneos, un patrón de base de datos de frontend de servicios basado en Cloud SQL para MySQL de segunda generación puede proporcionar el rendimiento necesario. Cuando tu juego crezca en popularidad, puedes ingresar otras instancias de Cloud SQL, ya sean compartidas o como réplicas, y una estrategia de almacenamiento en caché Redis o Memcached al nivel del servicio de la base de datos a fin de mantener el rendimiento en niveles aceptables.

Para juegos con una proyección menor de usuarios simultáneos, puedes utilizar un tipo de máquina más pequeña a fin de reducir costos.

Para juegos con una proyección de millones de CCU, deberías considerar utilizar una base de datos NoSQL, como Google Cloud Datastore o Google Cloud Bigtable, con escalabilidad y características de rendimiento sólidas.

¿Qué sigue?

  • Explora arquitecturas de referencia, diagramas y prácticas recomendadas sobre Google Cloud. Consulta nuestro Cloud Architecture Center.