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

Un patrón bien probado destinado a compilar un backend para juegos en línea utiliza una base de datos relacional, como MySQL. Esta base de datos almacena el estado del mundo de juego y datos persistentes 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 de 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 es útil para 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 temporalmente solicitudes 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 lo siguiente:
    • 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 frontend del juego. 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 la 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 dedicados para juegos: Las aplicaciones de clientes de juegos se conectan directamente con los servidores de juego y los convierten en un servicio frontend. Los servidores de juego dedicados normalmente son ejecutables personalizados, que están compilados con el motor del juego y deben ejecutarse en un hardware virtualizado, como las VM de Google Compute Engine. Si estás escribiendo un juego en el cual las interacciones en línea pueden modelarse con semántica de solicitud/respuesta de estilo HTTP, Google App Engine también es una buena opción.

  • Comunicación del servidor de juegos con servicios de base de datos: Generalmente, esto se modela mediante el estilo de acceso crear, recuperar, 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 idea.

  • Comunicación de 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 middleware de cola autoadministrado de código abierto, como RabbitMQ o ZeroMQ. En Cloud Platform, puedes utilizar Google Cloud Pub/Sub, que es seguro, duradero y altamente disponible. 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 están hechos con la finalidad de ser económicos en la comunicación entre cliente y servidor. Esto hace posible que los usuarios disfruten su juego incluso cuando tengan 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 aplicación de juegos MASS para dispositivos móviles de prueba con un backend del estilo de Puzzle and Dragons™ o Monster Strike™. Se supone que cada jugador puede acceder desde un solo dispositivo a la vez y que debe completar una acción antes de empezar una nueva. 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 Mimus dentro del servidor Mimus

En los juegos MASS, la velocidad a la cual el cliente del juego genera consultas de base de datos puede estar controlada por el desarrollador del juego; 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 que limitan la velocidad 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, manipuladas por el cliente mediante llamadas al servidor de Mimus. El servidor de Mimus realiza estas solicitudes a la base de datos mediante la API de base de datos síncrona (bloqueadora) de Mimus. Esta API es un módulo de Python importado por el servidor de Mimus y se puede configurar para que ponga a prueba diferentes implementaciones de backend de la base 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 del contenedor que se ejecuta sondea el tema Work de Cloud Pub/Sub en un ciclo sin fin en busca de nuevos mensajes. Cuando recibe un mensaje, ejecuta las consultas en él mediante el módulo de 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 configuraciones de máquina de hasta 32 núcleos y 208 GB de RAM, con tamaños de disco de hasta 10 TB. Además de tener asistencia para réplicas, las instancias de Cloud SQL de segunda generación están configuradas para ejecutar copias de seguridad regulares 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?

  • Prueba otras características de Google Cloud Platform tú mismo. Revisa nuestros instructivos.
¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...