El contenido de este sitio se ha traducido mediante inteligencia artificial (IA) o tecnología de traducción automática, y puede contener errores.

Skip to content

Cómo estamos haciendo que la infraestructura de Roblox sea más eficiente y resistente

A medida que Roblox ha crecido a lo largo de los últimos 16 años, también lo ha hecho la escala y la complejidad de la infraestructura técnica que da soporte a millones de experiencias colaborativas inmersivas en 3D. El número de máquinas que gestionamos se ha más que triplicado en los últimos dos años, pasando de aproximadamente 36 000 a 30 de junio de 2021 a casi 145 000 en la actualidad. Dar soporte a estas experiencias siempre activas para personas de todo el mundo requiere más de 1.000 servicios internos. Para ayudarnos a controlar los costes y la latencia de la red, implementamos y gestionamos estas máquinas como parte de una infraestructura de nube privada híbrida y personalizada que se ejecuta principalmente en nuestras propias instalaciones.  

Nuestra infraestructura da soporte actualmente a más de 70 millones de usuarios activos diarios en todo el mundo, incluidos los creadores que dependen de la economía de Roblox para sus negocios. Todos estos millones de personas esperan un nivel muy alto de fiabilidad. Dada la naturaleza inmersiva de nuestras experiencias, la tolerancia a los retrasos o la latencia es extremadamente baja, por no hablar de las interrupciones del servicio. Roblox es una plataforma de comunicación y conexión, donde las personas se reúnen en experiencias 3D inmersivas. Cuando las personas se comunican a través de sus avatares en un espacio inmersivo, incluso los retrasos o fallos más leves se notan más que en un hilo de texto o una conferencia telefónica.

En octubre de 2021, sufrimos una interrupción en todo el sistema. Comenzó de forma leve, con un problema en un componente de un centro de datos. Pero se extendió rápidamente mientras lo investigábamos y, finalmente, provocó una interrupción de 73 horas. En ese momento, compartimos tanto los detalles de lo ocurrido como algunas de nuestras primeras conclusiones sobre el problema. Desde entonces, hemos estado analizando esas conclusiones y trabajando para aumentar la resiliencia de nuestra infraestructura ante los tipos de fallos que se producen en todos los sistemas a gran escala debido a factores como picos extremos de tráfico, condiciones meteorológicas, fallos de hardware, errores de software o, simplemente, errores humanos. Cuando se producen estos fallos, ¿cómo nos aseguramos de que un problema en un único componente, o en un grupo de componentes, no se propague a todo el sistema? Esta cuestión ha sido nuestro centro de atención durante los últimos dos años y, aunque el trabajo sigue en marcha, lo que hemos hecho hasta ahora ya está dando sus frutos. Por ejemplo, en el primer semestre de 2023, ahorramos 125 millones de horas de interacción al mes en comparación con el primer semestre de 2022. Hoy compartimos el trabajo que ya hemos realizado, así como nuestra visión a largo plazo para construir un sistema de infraestructura más resiliente.

Creación de un sistema de respaldo

En los sistemas de infraestructura a gran escala, se producen fallos a pequeña escala muchas veces al día. Si una máquina tiene un problema y hay que dejarla fuera de servicio, es algo manejable, ya que la mayoría de las empresas mantienen múltiples instancias de sus servicios de back-end. Así, cuando falla una sola instancia, las demás asumen la carga de trabajo. Para hacer frente a estos fallos frecuentes, las solicitudes suelen configurarse para que se reintenten automáticamente si se produce un error.

Esto se convierte en un reto cuando un sistema o una persona reintenta con demasiada agresividad, lo que puede provocar que esos fallos a pequeña escala se propaguen por toda la infraestructura a otros servicios y sistemas. Si la red o un usuario reintenta con suficiente persistencia, acabará sobrecargando todas las instancias de ese servicio y, potencialmente, otros sistemas, a nivel global. Nuestra interrupción de 2021 fue el resultado de algo bastante común en los sistemas a gran escala: un fallo comienza siendo pequeño y luego se propaga por el sistema, creciendo tan rápido que es difícil resolverlo antes de que todo se caiga. 

En el momento de nuestra interrupción del servicio, contábamos con un centro de datos activo (con componentes en su interior que actuaban como respaldo). Necesitábamos la capacidad de realizar una conmutación por error manualmente a un nuevo centro de datos cuando un problema dejara fuera de servicio al existente. Nuestra primera prioridad era asegurarnos de contar con una implementación de respaldo de Roblox, por lo que creamos ese respaldo en un nuevo centro de datos, ubicado en una región geográfica diferente. Eso añadió protección para el peor de los casos: una interrupción que se propagara a suficientes componentes dentro de un centro de datos como para que este quedara totalmente inoperativo. Ahora contamos con un centro de datos que gestiona las cargas de trabajo (activo) y otro en espera, que sirve como respaldo (pasivo). Nuestro objetivo a largo plazo es pasar de esta configuración activa-pasiva a una configuración activa-activa, en la que ambos centros de datos gestionen las cargas de trabajo, con un equilibrador de carga que distribuya las solicitudes entre ellos en función de la latencia, la capacidad y el estado. Una vez que esto esté en marcha, esperamos tener una fiabilidad aún mayor para todo Roblox y poder realizar la conmutación por error de forma casi instantánea, en lugar de a lo largo de varias horas.

Pasando a una infraestructura celular

Nuestra siguiente prioridad fue crear sólidos muros de protección dentro de cada centro de datos para reducir la posibilidad de que todo un centro de datos dejara de funcionar. Las celdas (algunas empresas las llaman clústeres) son, en esencia, un conjunto de máquinas y son la forma en que estamos creando estos muros. Replicamos los servicios tanto dentro de las celdas como entre ellas para aumentar la redundancia. En última instancia, queremos que todos los servicios de Roblox se ejecuten en celdas para que puedan beneficiarse tanto de los sólidos muros de protección como de la redundancia. Si una célula deja de funcionar, se puede desactivar de forma segura. La replicación entre células permite que el servicio siga funcionando mientras se repara la célula. En algunos casos, la reparación de una célula puede implicar un reaprovisionamiento completo de la misma. En el sector, borrar y reaprovisionar una máquina individual, o un pequeño conjunto de máquinas, es bastante común, pero hacerlo para una célula completa, que contiene unas 1.400 máquinas, no lo es. 

Para que esto funcione, estas celdas deben ser en gran medida uniformes, de modo que podamos trasladar de forma rápida y eficiente las cargas de trabajo de una celda a otra. Hemos establecido ciertos requisitos que los servicios deben cumplir antes de ejecutarse en una celda. Por ejemplo, los servicios deben estar contenedorizados, lo que los hace mucho más portátiles y evita que cualquiera pueda realizar cambios de configuración a nivel del sistema operativo. Hemos adoptado una filosofía de «infraestructura como código» para las celdas: en nuestro repositorio de código fuente, incluimos la definición de todo lo que hay en una celda para poder reconstruirla rápidamente desde cero utilizando herramientas automatizadas. 

No todos los servicios cumplen actualmente estos requisitos, por lo que hemos trabajado para ayudar a los propietarios de los servicios a cumplirlos en la medida de lo posible, y hemos creado nuevas herramientas para facilitar la migración de los servicios a las celdas cuando estén listos. Por ejemplo, nuestra nueva herramienta de implementación «distribuye» automáticamente la implementación de un servicio entre las celdas, de modo que los propietarios de los servicios no tienen que preocuparse por la estrategia de replicación. Este nivel de rigor hace que el proceso de migración sea mucho más complejo y requiera más tiempo, pero la recompensa a largo plazo será un sistema en el que: 

  • Es mucho más fácil contener un fallo y evitar que se propague a otras celdas; 
  • Nuestros ingenieros de infraestructura pueden ser más eficientes y actuar con mayor rapidez; y 
  • Los ingenieros que crean los servicios a nivel de producto que finalmente se implementan en las celdas no necesitan saber ni preocuparse por en qué celdas se ejecutan sus servicios.

Resolver retos mayores

De forma similar a como se utilizan las puertas cortafuegos para contener las llamas, las celdas actúan como sólidos muros de contención dentro de nuestra infraestructura para ayudar a contener cualquier problema que provoque un fallo dentro de una sola celda. Con el tiempo, todos los servicios que componen Roblox se implementarán de forma redundante dentro de las células y entre ellas. Una vez completado este trabajo, los problemas podrían seguir propagándose lo suficiente como para dejar inoperativa toda una célula, pero sería extremadamente difícil que un problema se propagara más allá de esa célula. Y si logramos que las células sean intercambiables, la recuperación será significativamente más rápida, ya que podremos realizar una conmutación por error a una célula diferente y evitar que el problema afecte a los usuarios finales. 

Lo complicado es separar estas celdas lo suficiente como para reducir la posibilidad de que se propaguen los errores, al tiempo que se mantiene el rendimiento y la funcionalidad. En un sistema de infraestructura complejo, los servicios necesitan comunicarse entre sí para compartir consultas, información, cargas de trabajo, etc. A medida que replicamos estos servicios en celdas, debemos pensar detenidamente en cómo gestionamos la comunicación cruzada. En un mundo ideal, redirigimos el tráfico de una celda defectuosa a otras celdas sanas. Pero, ¿cómo gestionamos una «consulta de la muerte», es decir, una que está provocando que una celda esté en mal estado? Si redirigimos esa consulta a otra celda, podemos provocar que esa celda pase a estar en mal estado, justo lo que estamos tratando de evitar. Necesitamos encontrar mecanismos para desviar el tráfico «bueno» de las celdas en mal estado, al tiempo que detectamos y suprimimos el tráfico que está provocando que las celdas se deterioren. 

A corto plazo, hemos desplegado copias de los servicios informáticos en cada celda de computación para que la mayoría de las solicitudes al centro de datos puedan ser atendidas por una sola celda. También estamos equilibrando la carga del tráfico entre las celdas. A más largo plazo, hemos comenzado a desarrollar un proceso de descubrimiento de servicios de próxima generación que será aprovechado por una malla de servicios, y que esperamos completar en 2024. Esto nos permitirá implementar políticas sofisticadas que permitirán la comunicación entre celdas solo cuando no afecte negativamente a las celdas de conmutación por error. También en 2024 se introducirá un método para dirigir las solicitudes dependientes a una versión del servicio en la misma celda, lo que minimizará el tráfico entre celdas y, por lo tanto, reducirá el riesgo de propagación de fallos entre celdas.

En momentos de máxima actividad, más del 70 % del tráfico de nuestros servicios de back-end se gestiona desde las celdas y hemos aprendido mucho sobre cómo crear celdas, pero prevemos más investigación y pruebas a medida que continuamos migrando nuestros servicios a lo largo de 2024 y más allá. A medida que avancemos, estas barreras de protección se volverán cada vez más sólidas.

Migración de una infraestructura siempre activa

Roblox es una plataforma global que da soporte a usuarios de todo el mundo, por lo que no podemos trasladar los servicios durante las horas de menor actividad o el «tiempo de inactividad», lo que complica aún más el proceso de migrar todas nuestras máquinas a celdas y nuestros servicios para que se ejecuten en ellas. Tenemos millones de experiencias siempre activas que deben seguir recibiendo soporte, incluso mientras trasladamos las máquinas en las que se ejecutan y los servicios que las respaldan. Cuando iniciamos este proceso, no contábamos con decenas de miles de máquinas sin usar y disponibles para migrar estas cargas de trabajo. 

Sin embargo, sí contábamos con un pequeño número de máquinas adicionales que se habían adquirido en previsión de un crecimiento futuro. Para empezar, creamos nuevas celdas utilizando esas máquinas y, a continuación, migramos las cargas de trabajo a ellas. Valoramos tanto la eficiencia como la fiabilidad, por lo que, en lugar de salir a comprar más máquinas una vez que se nos acabaron las máquinas «de repuesto», creamos más celdas borrando y reasignando las máquinas de las que habíamos migrado. A continuación, migramos las cargas de trabajo a esas máquinas reasignadas y volvimos a empezar el proceso desde cero. Este proceso es complejo: a medida que las máquinas se sustituyen y quedan libres para integrarse en las células, no se liberan de una manera ideal y ordenada. Están físicamente fragmentadas por las salas de datos, lo que nos obliga a aprovisionarlas de forma fragmentada, lo que requiere un proceso de desfragmentación a nivel de hardware para mantener las ubicaciones del hardware alineadas con los dominios de fallos físicos a gran escala. 

Una parte de nuestro equipo de ingeniería de infraestructura se centra en migrar las cargas de trabajo existentes desde nuestro entorno heredado, o «pre-célula», a las células. Este trabajo continuará hasta que hayamos migrado miles de servicios de infraestructura diferentes y miles de servicios de back-end a las células recién construidas. Esperamos que esto nos lleve todo el próximo año y posiblemente hasta 2025, debido a algunos factores que complican la tarea. En primer lugar, este trabajo requiere la creación de herramientas robustas. Por ejemplo, necesitamos herramientas para reequilibrar automáticamente un gran número de servicios cuando desplegamos una nueva celda, sin que ello afecte a nuestros usuarios. También hemos observado servicios que se crearon partiendo de supuestos sobre nuestra infraestructura. Necesitamos revisar estos servicios para que no dependan de elementos que podrían cambiar en el futuro a medida que avanzamos hacia las celdas. También hemos implementado tanto una forma de buscar patrones de diseño conocidos que no funcionarán bien con la arquitectura celular, como un proceso de pruebas metódico para cada servicio que se migra. Estos procesos nos ayudan a evitar cualquier problema para los usuarios causado por la incompatibilidad de un servicio con las células.

Hoy en día, cerca de 30 000 máquinas están gestionadas por celdas. Es solo una fracción de nuestro parque total, pero hasta ahora la transición ha sido muy fluida, sin ningún impacto negativo para los jugadores. Nuestro objetivo final es que nuestros sistemas alcancen un tiempo de actividad del 99,99 % para los usuarios cada mes, lo que significa que no interrumpiríamos más del 0,01 % de las horas de actividad. En el sector, el tiempo de inactividad no se puede eliminar por completo, pero nuestro objetivo es reducir cualquier tiempo de inactividad de Roblox hasta un punto en el que sea casi imperceptible.

Preparándonos para el futuro a medida que crecemos

Aunque nuestros primeros esfuerzos están dando buenos resultados, nuestro trabajo en las células está lejos de haber concluido. A medida que Roblox siga creciendo, continuaremos trabajando para mejorar la eficiencia y la resiliencia de nuestros sistemas mediante esta y otras tecnologías. A medida que avancemos, la plataforma se volverá cada vez más resistente a los problemas, y cualquier incidencia que se produzca debería ser cada vez menos visible y menos perjudicial para los usuarios de nuestra plataforma.

En resumen, hasta la fecha, hemos: 

  • Construido un segundo centro de datos y logrado con éxito el estado activo/pasivo. 
  • Creado celdas en nuestros centros de datos activos y pasivos y migrado con éxito más del 70 % del tráfico de nuestros servicios de back-end a estas celdas.
  • Establecido los requisitos y las mejores prácticas que debemos seguir para mantener todas las celdas uniformes a medida que continuamos migrando el resto de nuestra infraestructura. 
  • Iniciado un proceso continuo de construcción de «muros de contención» más sólidos entre las celdas. 

A medida que estas celdas se vuelvan más intercambiables, habrá menos interferencias entre ellas. Esto nos abre oportunidades muy interesantes en cuanto a aumentar la automatización en torno a la supervisión, la resolución de problemas e incluso el desplazamiento automático de cargas de trabajo. 

En septiembre también comenzamos a realizar experimentos «activo/activo» en todos nuestros centros de datos. Este es otro mecanismo que estamos probando para mejorar la fiabilidad y minimizar los tiempos de conmutación por error. Estos experimentos ayudaron a identificar una serie de patrones de diseño del sistema, principalmente en torno al acceso a los datos, que debemos reelaborar a medida que avanzamos hacia un modelo totalmente «activo/activo». En general, el experimento tuvo suficiente éxito como para dejarlo en funcionamiento para el tráfico de un número limitado de nuestros usuarios. 

Estamos encantados de seguir impulsando este trabajo para aportar mayor eficiencia y resiliencia a la plataforma. Este trabajo sobre celdas e infraestructura activa-activa, junto con nuestras otras iniciativas, nos permitirá convertirnos en un servicio fiable y de alto rendimiento para millones de personas, y seguir creciendo a medida que trabajamos para conectar a mil millones de personas en tiempo real.