Dentro de ArenaNet: Análisis de una desconexión del juego en vivo

por El equipo de Guild Wars 2 el 15 de julio de 2021

¡Hola! Soy Robert Neckorcuk, jefe del equipo de plataformas de ArenaNet. Mi equipo se ocupa de varios servicios de red internos para la franquicia Guild Wars®: servidores de inicio de sesión, servidores de chat, sitios web, y mucho más. Trabajamos muy de cerca con otros dos grupos, el de operaciones de juego y el de gestión de lanzamientos, formando así el grupo de servicios internos. También trabajamos con jugabilidad, analítica, atención al cliente, etc., pero nuestra labor principal es que los juegos y su infraestructura se mantengan en línea. La franquicia de Guild Wars es famosa por su impresionante disponibilidad online. Aunque celebramos el éxito de nuestra infraestructura, tmabién hemos encontrado desafíos. Hoy voy a compartir con vosotros los detalles de lo que pasó en el último gran incidente, así como la lección que aprendimos para seguir mejorando nuestro compromiso con vosotros.

El 11 de mayo de 2020, a las 06:00, hora local, recibí una llamada. Os aseguro que no me ha hecho falta comprobar la fecha: todavía lo recuerdo de manera intensa. Nuestro equipo de operaciones de juego había recibido una alerta de que había un “retroceso” en una de las bases de datos en vivo de Guild Wars 2, lo que hacía que los servidores de juego dieran información incoherente a los jugadores y nuestras herramientas internas mostraban un montón de otras alarmas y errores relacionados.

Ah, porras.

He tenido lunes menos emocionantes. De hecho, prefiero los lunes poco emocionantes. Tras iniciar sesión en mi ordenador de trabajo, me uní a la gente que investigaba qué había pasado y qué podíamos hacer para devolver el juego a la normalidad. Nuestra investigación nos llevó a una conclusión que es la peor pesadilla de todo equipo y compañía que aspiran a estar “siempre online”: tendríamos que desconectar todo el juego para restaurar los datos a un estado aceptable. Dado que esta era la primera vez que presenciaba un problema así, me llevó un tiempo identificar las cosas que necesitaban aprobación. Justo después de las 09:00, hora local, envié los cambios para desactivar los inicios de sesión del juego y apagar los servidores europeos de Guild Wars 2.

Iteración constante

Durante la interrupción del servicio, Guild Wars 2 estuvo desactivado en nuestros centros de datos europeos durante más de 20 horas. Sin tener en cuenta unas cuantas caídas de solo unos poco minutos, la desactivación anterior de Guild Wars 2 tuvo lugar el 23 de agosto de 2016. Aunque nunca es divertido tener que lidiar con problemas que afectan a la conectividad del juego, pudimos aprovechar estos incidentes para aprender a mejorar nuestra infraestructura y procesos. Nuestro proceso para lidiar con incidentes sigue el modelo de muchas compañías con servicios online, tanto dentro como fuera de la industria del videojuego:

  • Identificar el alcance del problema: ¿Está pasando en un servidor, un centro de datos o una versión del programa? Ver si se puede reducir la investigación a un conjunto más pequeño de servicios o regiones.
  • Identificar una manera de hacer que el servicio vuelva a estar disponible cuanto antes: aquí es necesario equilibrar entre exactitud y disponibilidad. Si conseguimos que el servicio vuelva a funcionar modificando algo, ¿provocaremos problemas en otra parte?
  • Una vez el servicio vuelva a estar disponible, escribir un informe sobre el incidente: este informe debe detallar qué ocurrió, qué nos informó del problema, qué pasos tomamos y quién se vio afectado.
  • Más tarde, durante las horas de trabajo regulares, preparamos una reunión con los equipos afectados para revisar el informe del incidente y crear tareas para cualquier acción posterior: las acciones pueden ser para mejorar las alertas o la detección, actualizar la documentación o los procesos automatizados o desarrollar una nueva herramienta.

No solo echamos un vistazo a nuestros procesos y procedimientos para hacer cambios durante incidentes como este. En 2017, ArenaNet tomó la decisión de migrar su centro de datos físico a uno en la nube usando la infraestructura AWS (¡sin tiempo de desconexión!). En 2020, tras ajustarnos al trabajo desde casa, completamos una migración de nuestra estructura de registro de analíticas de un proveedor de hardware a uno en la nube.

La razón por la que hemos realizado tantas migraciones a la nube es porque ofrecen flexibilidad: tenemos la opción de cambiar y modificar nuestra infraestructura rápidamente y sin interrupciones. A principios de 2020 comenzamos una mejora de AWS interna y holística, viendo los costes y opciones para cada servidor que estábamos usando, desde nuestros servidores de desarrollo de comercio hasta los de planificación de PvP en vivo. AWS constantemente ofrece nuevos servicios y tipos de hardware, y no habíamos realizado una auditoría completa desde 2017. Esta planificación nos permitió realizar cambios para mejorar la experiencia de jugador en el juego en vivo, emparejando nuestros entornos de desarrollo con el juego en vivo, y mejorando varias herramientas internas. También actualizamos algunos servidores que no habían cambiado nunca (o que incluso nunca se habían reiniciado) desde nuestra migración de 2017.

Cuando nos enfrentamos a un gran proyecto, una de las estrategias más efectivas es dividirlo en trozos más pequeños y manejables. ¡Como partir una gran pizza! Queríamos ver cada instancia de AWS, y por suerte, ya tenía varios “cubos” de distintos tipos de instancias: servidores de juego, de bases de datos, de comercio, etc. Nuestro plan era revisarlos todos, de uno en uno, realizar cambios y después pasar al siguiente grupo. Por cada conjunto de cambios, empezaríamos migrando nuestros servidores de desarrollo interno. Después, escribiríamos una guía para documentar el proceso y verificar el comportamiento, luego migrar nuestros entornos de preparación y en vivo siguiendo los pasos de dicha guía.

La posibilidad de realizar iteraciones es absolutamente esencial para cualquier producto y compañía. Construir cosas en el patio trasero, romperlo en mil pedazos, romperlo tan a menudo y de la manera más extraña como sea posible. Una vez esté todo arreglado internamente, debería de ser bastante resistente cuando llegue al público. Para los equipos de plataformas y de operaciones de juego, este proceso de “practicar la manera en que jugamos” es otra herramienta a nuestra disposición que beneficia a la calidad de nuestro servicio. Dicho eso, los servidores de desarrollo y los del juego en vivo son muy diferentes en cuanto a coste y tamaño, por lo que, aunque desearíamos que todo se comportara igual, lo cierto es que son bastante únicos.

Una pequeña (simplificando mucho) explicación sobre cómo son nuestras bases de datos: tenemos dos servidores, uno primario y otro secundario. Cuando escribimos en la base de datos, un mensaje de “realiza este cambio” se manda a la instancia primaria. La primaria manda después un mensaje a la secundaria (también llamado “espejo”) diciendo “realiza este cambio”, y después se aplica el cambio a sí misma. Si pasa “algo malo” en la primaria, la instancia secundaria se hará automáticamente con el control e informará como si fuera la primaria. Esto significa que no hay tiempo de desconexión ni pérdida de datos, y la nueva primaria pondrá mensajes en una cola para mandarlos a la “nueva secundaria” una vez se recupere de las “cosas malas”. Para mejorar instancias, desconectamos manualmente las bases de datos primaria y secundaria, mejoramos la secundaria y las reconectamos.

Uno de los puntos de datos más importantes que podemos rastrear es el tiempo que le lleva a la secundaria recibir todos los mensajes de la primaria que hay en cola y volver a la paridad de datos. Al combinar esto con otros datos métricos sobre la carga y la salud, podemos saber si el servidor está sano o no. Y personalmente, estas gráficas me resultan fascinantes. Después intercambiamos la primaria y la secundaria, repetimos el proceso, y entonces obtenemos gráficas incluso más bonitas, además de un entorno totalmente mejorado.
En el entorno de desarrollo, todo fue como la seda. Nuestro entorno de preparación nos ofrecía otra oportunidad de ejecutar el proceso de principio a fin, y eso también fue como la seda. Empezamos nuestra mejora del juego en vivo con los servidores de la región europea el miércoles, 6 de mayo de 2020.

Donde están las cosas malas

La actualización del 6 de mayo salió según lo previsto. Cortamos la conexión, actualizamos la secundaria y restablecimos la conexión. Los mensajes en cola se copiaron, intercambiamos la primaria por la secundaria y repetimos esas acciones una vez más. La copia de mensajes fue un poco más lenta que en las ejecuciones de práctica en el entorno de desarrollador, pero había una cola mucho más larga debido al volumen de tráfico del juego en vivo.

El jueves, 7 de mayo, nos saltó una alarma de “espacio en el disco casi lleno”. Habíamos realizado recientemente una copia de seguridad adicional de los datos, la cual ocupaba cierto espacio, pero la buena metodología dictaba que debíamos expandir el espacio de almacenamiento de todas formas. El almacenamiento no es caro y con AWS se podría duplicar el tamaño de nuestra unidad de registro y de copias de seguridad con solo unos clics del ratón. Un miembro del equipo de operaciones de juego hizo clic con su ratón varias veces, y aun así, el tamaño de almacenamiento ampliado no apareció. El viernes enviamos solicitudes de ayuda a AWS, que nos recomendó reiniciar para arreglar el problema. Dado que este servidor era actualmente el primario, tendríamos que cambiarlo por el secundario antes de poder reiniciar.

Es muy fácil echar la vista atrás y reconocer los errores evidentes, pero en aquel momento, no sabíamos qué cosas eran las que no sabíamos. El viernes a media tarde intentamos intercambiar el primario y el secundario para poder realizar un reinicio rápido. No obstante, en aquel momento la cola de mensajes del primario al secundario no estaba vacía, y seguía copiándose lentamente. Algunos cálculos nos decían que el disco duro no se llenaría totalmente durante el fin de semana, así que podríamos regresar el lunes por la mañana, ver la cola de mensajes, cambiar los servidores y realizar el reinicio.

Lo único que se cumplió de todo eso es que regresamos el lunes…

Aunque reconocimos que los mensajes en cola se enviaban lentamente (a “velocidad de tortuga”), no tuvimos en cuenta la velocidad a la que la cola crecía (a “velocidad de tortuga con un propulsor”). Si os acordáis, dije que si pasa “algo malo” en la base de datos primaria, la secundaria se hace automáticamente con el control como nueva primaria. Y se dio el caso de que una de las “cosas malas” que provocan un fallo general es que la cola de mensajes se está volviendo demasiado grande.

A las 02:41 de la madrugada (hora local) del lunes, 11 de mayo, se cruzó el umbral de las “cosas malas”, y las bases de datos intercambiaron la primaria y el espejo. Dado que los mensajes de actualización de la base de datos estaban todos en cola en el otro servidor, cuando las bases de datos fallaron, los jugadores experimentaron de pronto viajes en el tiempo (y no de los buenos) al ver que todo su progreso desde el viernes por la noche se había borrado. Tres dolorosas horas después, a las 05:40 de la mañana, llamaron a nuestro equipo de operaciones de juego cuando los informes de jugadores aumentaron. A mí me llamaron a las 06:00 de la mañana, y el juego fue desconectado a las 09:00.

En cuanto se desactivó el juego, uno de nuestros primeros pasos fue reiniciar el servidor primario, y tal y como estaba previsto, el disco expandido apareció. Buenas noticias, como poco. Con el disco nuevo expandido, encontramos el archivo de copia de seguridad más reciente y los registros que contenían todos los mensajes en cola, hasta las 02:41.

Guardar copias de seguridad es una práctica excelente. El almacenamiento es barato, tener la opción de recuperar datos te da tranquilidad y es muy fácil programar copias de seguridad automáticas. No obstante, restaurar los datos usando dichas copias… eso es otro tema, sobre todo porque no se hace muy a menudo. Por un lado, no había carga en las bases de datos, por lo que podíamos echarlo todo abajo y empezar desde cero si hacía falta. Por otro lado, el juego estaba caído, y teníamos una presión enorme para restaurar los datos rápidamente y con precisión para que el juego volviera a funcionar.

(Nota: Me voy a centrar en la historia principal, pero incluso en este punto había una serie de investigaciones secundarias sobre el impacto mayor en el bazar, la tienda de gemas, la creación de cuentas nuevas, etc. Pasaron muchas cosas durante este incidente, con contribuciones de muchos equipos distintos. Creo que podría escribir un libro entero con minihistorias sobre este evento).

La verdad es que el proceso de restauración fue bastante aburrido, ya que solo seguimos una guía de prácticas recomendadas. Unos cuantos clics en la función de administración y el servidor empezó a trabajar. Antes de que pudiéramos empezar, teníamos que copiar el archivo de copia de seguridad y los de registro al segundo servidor para asegurarnos de que estábamos restaurando los mismos datos en ambos. El servidor entonces establecería el estado de las bases de datos a todo lo que estaba contenido en el archivo de copia de seguridad. Este proceso tardó varias horas. Después, se aplicarían todos los mensajes registrados para que, al final, ambas bases de datos fueran precisas hasta las 02:41. Esto también tardó mucho tiempo. El primer servidor acabó a la 1:37, y el segundo, a las 04:30.

(Nota 2: Además del trabajo que haces, la gente junto a la que trabajas es probablemente lo más importante en lo que respecta a elegir una compañía o un equipo. Había unas cuantas personas del equipo conectados desde las 05:30 o 06:00, y solo nos echábamos siestas cortas y trabajamos el resto del tiempo hasta las primeras horas del día siguiente. ¡Hasta tuvimos que hacer de niñera del servidor! No se puede menospreciar la habilidad que tuvieron todos los presentes de tomarse la situación con seriedad y, al mismo tiempo, tener una actitud jovial que nos ayudara a llegar al final del evento. Este equipo es increíble en lo que hace y en cómo lo hace).

La infraestructura de Guild Wars 2 es también increíble. Es capaz de actualizarse sin desconectarse y contiene muchas palancas que se pueden usar y que afectan a distintas funciones o contenido del juego para evitar fallos aprovechables, prevenir bloqueos o incluso cambiar la dificultad de los eventos dinámicos sin necesidad de compilar una nueva versión. El 12 de mayo usamos otra función del juego que no se había visto desde 2016: la posibilidad de lanzar el juego en vivo sin lanzar el juego en vivo. El juego estaría online, pero solo podrían entrar los desarrolladores, no los jugadores públicos.

A las 04:55, “conectamos” el juego, y un equipo entero de desarrolladores internos, analistas de control de calidad y un puñado de compañeros europeos iniciaron sesión en el juego. Me impresionó sobremanera que, en unos pocos minutos, los jugadores ya habían identificado que el juego se estaba probando en vivo y su progreso se restauró el lunes por la mañana. Supongo que eso pasa cuando hacemos públicas nuestras APIs.

Tras una prueba del entorno en vivo que comprobó la salud de la base de datos y las colas de mensajes, abrimos los servidores al público a las 05:37, más de 20 horas después de la desconexión. Todo el equipo estaba agradecido de poder haber ayudado a todos a volver a un mundo que adoran, yo mismo incluido. También me alegraba poder tener unas cuantas horas más de sueño.

Buf.

Tras descansar unas horas, todos volvimos a iniciar sesión para trabajar e intentar comprender cuál fue exactamente la raíz del problema. Aquella tarde, saltó una alarma en nuestra región europea: la cola de mensajes de las bases de datos era demasiado grande.

Porras. Otra vez.

Habíamos identificado el problema correctamente y añadimos unos cuantos mecanismos de alarma para estos recién descubiertos puntos de fallo. Durante los dos días siguientes, administramos de manera manual las duplicaciones de las bases de datos y las conexiones entre la primaria y la secundaria. Hablamos con administradores de bases de datos, operadores de redes, y nuestros gerentes de cuenta técnicos de AWS. Configuramos cada ajuste que pudimos relacionado con las colas de mensaje, los volúmenes, el almacenamiento y los registros. Tras días de leer la documentación, reuniendo los conocimientos de expertos e intentando cambios, al fin hallamos la solución el viernes.

¡Un redoble, por favor!

La causa eran los controladores.

Los controladores son lo que permiten a los sistemas operativos de software comunicarse con los dispositivos conectados: si tenéis periféricos como un ratón de juego o una tableta de dibujo, probablemente habréis descargado controladores específicos para ellos.
En este caso, el sistema operativo del servidor no tenía el último método de comunicación para interactuar con el disco duro. Algo que no es muy bueno para una base de datos cuya razón principal de existir consiste en un 99 % en leer y escribir datos en un disco. (El otro 1 % es el efecto “¡Hala!”. “¡Hala! ¿Tenéis una base de datos? Cómo mola).

Cuando actualizamos los servidores, nos trasladamos de los servidores de AWS de 4.ª generación a los de 5.ª generación, y eso suponía un cambio en la manera en la que los servidores interactuaban con los dispositivos conectados (yo mismo no comprendo del todo cómo funciona el sistema, pero AWS le ha puesto un nombre chulo a la tecnología de base: “Nitro”). Nuestra versión de los controladores era más avanzada que la de la versión básica que nos dio AWS, así que no esperábamos que hicieran falta realizar actualizaciones adicionales. Además, en nuestro entorno de desarrollo, esto no suponía ningún problema. Pero tampoco teníamos, ni de lejos, la misma carga de datos que en el juego en vivo. A pesar de ser otro viernes y de reconocer las consecuencias de una actualización de controladores fallida, decidimos seguir adelante.
Como antes, cortamos la conexión entre la base de datos, ejecutamos las actualizaciones de controladores y volvimos a conectarnos.

La cola se vació casi al instante.

La velocidad de escritura de datos iba a unos 100 000 kilobits por segundo, en vez de los 700 Kbps que habíamos visto antes.

Sonreí. Me reí (de manera algo descontrolada).

Repetimos el proceso en el otro servidor. Una vez más, la cola se vació en unos cuantos abrir y cerrar de ojos.

Me pasé aquel fin de semana durmiendo. Y me he despertado como una rosa muchos lunes más desde entonces.

Echar la vista atrás y adelante

Eso es lo que ocurrió, lo que se nos pasó por alto y por qué tuvo lugar el incidente. Lo siguiente es la parte que más me gusta sobre mi trabajo: ¿Qué lecciones aprendimos? ¿Cómo aprovechamos esto para crecer y mejorar? ¿Qué amigos hicimos en el camino?

En primer lugar, este fue un buen recordatorio de lo distintos que son el entorno de desarrollo y el entorno en vivo. El de desarrollo es genial para practicar, grabar métricas de rendimiento específicas y más. No obstante, para algunos cambios, todavía se necesitan herramientas clave como realizar pruebas de carga y de rendimiento en varias máquinas.

En segundo lugar, nos recordó que siempre hay que comprobar lo que se presupone y dar un paso atrás para ver el cuadro completo si algo no sale como se preveía. Habíamos hecho lo que había que hacer en los días anteriores a la desconexión, pero nos centramos en la parte equivocada del problema. Si hubiéramos consultado con otra gente, eso nos habría dado una perspectiva distinta y la necesidad de defender la irregularidad que estábamos viendo para determinar si podía ser un problema.

El cambio más significativo para nuestras bases de datos fue incrementar las alarmas en métricas de bases de datos clave, no solo en métricas del sistema como la CPU o el espacio en el disco duro. Para las operaciones en vivo, añadimos un número de alarmas a una herramienta de terceros para mejorar nuestro tiempo de respuesta en problemas futuros. En cuanto a las operaciones generales, hemos mejorado nuestra forma de almacenar los registros de nuestra infraestructura de AWS, de manera que ahora guardamos más información, no solo el tipo de instancia. Nuestros informes ahora incluyen el tipo de instancia, la generación, los controladores y los tipos de almacenamiento. Hemos creado un paquete común para instalar en todos los servidores nuevos que incluyen versiones específicas de los controladores. Cualquier plan de migración futuro actualizará este paquete común, asegurando que este problema no se repita de nuevo.

Hemos completado la migración de todas las instancias de bases de datos que faltaban y mucho más, lo que ofrece un mayor rendimiento en un servicio mejorado. En los últimos catorce meses, hemos experimentado una estabilidad del 99,98 % con solo cinco interrupciones menores que han impactado a inicios de sesión de usuarios.

Nuestros esfuerzos continuos siempre tienen como objetivo ofreceros la mejor experiencia en nuestros servicios y la mejor manera de usarlos. Nos encanta celebrar el diseño ideado por aquellos que vinieron antes que nosotros y las herramientas y procesos que usamos para mantener nuestra conexión de gran calidad, y nos alegra que nuestra racha de disponibilidad haya vuelto a superar la barrera de un año. Somos conscientes de que no hemos alcanzado la perfección, pero seguiremos apuntando a ella en cada procedimiento y despliegue futuros. A medida que esperamos las emocionantes funciones y proyectos nuevos que los equipos de jugabilidad y diseño de Guild Wars 2 os traen, nosotros seguiremos trabajando constantemente entre bambalinas para asegurarnos de que podéis iniciar sesión y divertiros en todo momento.

¡Vaya! Ya sabía que soy capaz de escribir mucho código. Al parecer, también puedo escribir publicaciones de blog bastante largas. Espero que la hayáis disfrutado. Puede que algunos llevarais mucho tiempo esperando esta publicación, pero estoy muy contento de poder compartir historias como esta con vosotros. Nos encantaría saber qué pensáis sobre este tipo de publicaciones, así que hemos preparado un hilo en nuestros foros oficiales para que dejéis vuestros comentarios.

Nos vemos en Tyria en línea:
Robert