- Twilio Segment operó una arquitectura de microservicios con cientos de servicios, pero cambió a un servicio único (monolítico) debido a la complejidad y a la carga de mantenimiento
- Al principio separó cada API de destino para lograr aislamiento de fallas y escalabilidad, pero al superar los 140 servicios, el overhead operativo se disparó
- La gestión de múltiples repositorios y bibliotecas compartidas se volvió difícil, y durante las pruebas y los despliegues surgían problemas que afectaban al conjunto de los servicios
- Para resolverlo, introdujo el sistema Centrifuge y una estructura de monorepo, y creó Traffic Recorder para automatizar las pruebas
- Como resultado, la velocidad de desarrollo y la estabilidad mejoraron considerablemente, y Twilio Segment mantiene la estructura monolítica por productividad y eficiencia operativa
Adopción de microservicios y sus límites
- Twilio Segment adoptó una arquitectura de microservicios para su infraestructura de datos de clientes, diseñada para que cada servicio orientado a un propósito procesara eventos de forma independiente
- Enviaba datos a cientos de destinos del lado del servidor (por ejemplo, Google Analytics, Optimizely, etc.)
- Al principio usaba una sola cola, pero cuando un destino fallaba se producía head-of-line blocking, lo que generaba retrasos generales
- Para resolverlo, configuró un servicio y una cola separados para cada destino, logrando aislamiento de fallas y escalado independiente
- Sin embargo, a medida que aumentó el número de servicios, la complejidad operativa y el costo de mantenimiento crecieron con rapidez, lo que derivó en menor velocidad de desarrollo y mayor tasa de defectos
Problemas de los repositorios individuales y las bibliotecas compartidas
- Cada destino usaba un formato de API distinto, por lo que hacía falta código de transformación personalizado
- Al principio se gestionaba en un solo repositorio, pero como los fallos en pruebas afectaban a todo, se optó por la separación de repositorios
- Después, al agregarse más de 50 destinos nuevos, surgieron más de 50 repositorios
- Se introdujeron bibliotecas compartidas para funciones comunes, pero crecieron los problemas de versiones inconsistentes y la carga de despliegue
- Como los patrones de carga variaban entre servicios, era difícil configurar el autoescalado, y en algunos casos los operadores tenían que ajustarlo manualmente
Transición al monolito e introducción de Centrifuge
- Se decidió integrar más de 140 servicios en un solo servicio
- Para reemplazar las colas individuales, se desarrolló el sistema Centrifuge, que envía todos los eventos a un único servicio
- Más adelante, Centrifuge evolucionó hasta convertirse en la infraestructura backend de Connections de Twilio Segment
- Con la transición a una estructura de servicio único se logró reducir la carga operativa y simplificar la respuesta ante fallas
Monorepo y automatización de pruebas
- Todo el código de destinos se fusionó en un solo repositorio, unificando en una sola versión más de 120 dependencias
- Se simplificó la gestión de versiones y mejoró la eficiencia del mantenimiento
- Para automatizar las pruebas se introdujo Traffic Recorder
- Registra y reproduce solicitudes y respuestas HTTP reales para eliminar la dependencia de redes externas
- La velocidad de las pruebas pasó de varios minutos a milisegundos, con una mejora importante en estabilidad
- Disminuyó la tasa de fallos en pruebas y mejoró notablemente la productividad de los desarrolladores
Efectos y trade-offs de la estructura monolítica
- Tras integrar todo en un solo servicio, la velocidad de despliegue y la eficiencia de desarrollo mejoraron mucho
- En un año, la cantidad de mejoras en bibliotecas compartidas aumentó de 32 a 46
- Un solo ingeniero puede desplegar en cuestión de minutos
- También mejoró la eficiencia operativa, ya que incluso ante aumentos bruscos de carga puede absorberse con un gran pool de workers
- Sin embargo, existen desventajas como la dificultad para aislar fallas, la menor eficiencia de caché y el riesgo al actualizar dependencias
- Parte de esas pérdidas se compensa con la simplicidad operativa y la mejora de productividad
Conclusión
- Los microservicios resolvieron problemas iniciales de rendimiento, pero no eran adecuados para la expansión a gran escala y las actualizaciones masivas
- La transición a un monolito mejoró tanto la estabilidad operativa como la velocidad de desarrollo
- Para que la transición sea exitosa, son indispensables un sistema de pruebas sólido y la aceptación de los trade-offs
- Aunque Twilio Segment todavía mantiene microservicios en parte de su infraestructura, considera que para los destinos del lado del servidor el monolito es una estructura más adecuada
2 comentarios
Creo que fragmentarlo y normalizarlo todo conlleva cierto riesgo.
Comentarios en Hacker News
Al reunir el código de todos los destinos en un solo repo, pudieron fusionarlo en un único servicio
Como resultado, la productividad de desarrollo mejoró mucho. Ahora ya no hace falta desplegar más de 140 servicios cada vez que se modifica una librería compartida
Un solo ingeniero puede desplegar en cuestión de minutos
Si hay que volver a desplegar todos los servicios por un cambio en una librería, entonces no se trata de servicios reales, sino de un monolito distribuido
La idea misma de tener que sincronizar a la fuerza una librería compartida en todos los servicios no encaja con la filosofía de una arquitectura de servicios
Esto se parece más a un sistema compartido de build y despliegue al estilo Amazon que a “volver a desplegar todo con cada actualización de librería”
Se toman librerías de una única fuente centralizada, y si las versiones difieren, todos tienen que migrar por problemas de compatibilidad
Cuando hay que retirar una versión específica por una vulnerabilidad de seguridad, sí hace falta volver a desplegar todo, pero los beneficios de la gestión centralizada son mucho mayores
Este tipo de sistema sigue clasificándose como microservicios, pero en costos y eficiencia operativa funciona como un entorno compartido
Llamarlo monolito distribuido es una interpretación exagerada
Cuando sigues el patrón de microservicios, el riesgo de despliegue aumenta, aunque al principio no se note
Por ejemplo, si corriges un bug en una librería relacionada con dinero, en la realidad terminas preguntándote si no deberías volver a desplegar todos los servicios
Una librería con una vulnerabilidad de seguridad debe reemplazarse por completo sin importar el diseño del sistema
En casos así, una arquitectura monolítica incluso puede ser más fácil de manejar
Si fueran microservicios de verdad, deberían intercambiar mensajes y usar JSON
Bastaría con conocer la API, no el código. Solo así se pueden desplegar y escalar de forma independiente
¿No tiene más sentido usar módulos compartidos?
En mi empresa anterior, todo corría como microservicios, y en la de antes de esa usábamos AWS serverless
En ambos casos, la comunicación entre servicios era el mayor problema. Era difícil sincronizar los contratos, y los despliegues también eran complejos
Al principio nos movíamos rápido, pero con el tiempo la complejidad explotó. Surgió el desarrollo basado en el miedo y había demasiadas reuniones
Mi empresa actual usa una arquitectura monolítica y es mucho más fácil de manejar. Los tipos son claros y el refactoring es sencillo
Es interesante ver agentes de IA construidos sobre nuestra propia plataforma mejorándose solos dentro del codebase
La única desventaja es el tiempo de build, pero con las mejoras en la toolchain esperamos despliegues 10 veces más rápidos para 2026
Mi conclusión es que, gracias a la arquitectura monolítica, pudimos crecer y escalar mucho más rápido
En una arquitectura monolítica siempre se rompía la separación de responsabilidades y había mucho acoplamiento entre equipos
La verdadera velocidad y la escalabilidad solo fueron posibles cuando los equipos estaban separados
Para pasar de ORM a DTO se necesitaron 2 años, 50 equipos y más de 150 personas
Un trabajo complejo así habría sido imposible sin microservicios
Al leer este texto, parece que el verdadero núcleo del problema no es la elección técnica entre microservicios vs. monolito,
sino la calidad y estructura de la organización de ingeniería
El repositorio de código y la estructura de pruebas reflejan exactamente el nivel de la organización
Si no hay nadie capaz de decir “eso no lo hagamos”, la complejidad explota
Tiene que existir un líder con autoridad para que el equipo pueda detenerse y pensar
Cuando había problemas de API, no analizaban la causa raíz; solo corregían los datos y cerraban el ticket
Aunque el mismo problema se repitiera, nunca resolvían la causa fundamental
Incluso con solo hacer entrevistas, puedes predecir hasta cierto punto la estructura del codebase de una empresa
Esto no parece realmente una transición a monolito, sino que sigue siendo una arquitectura SOA
Solo aumentó el alcance de los servicios
Si un solo equipo administra 140 servicios, entonces SOA es una estructura para escalar equipos, no para escalar servicios
Cuando un solo equipo administra todas las librerías compartidas, aparecen desajustes de versiones y confusión en las APIs
Al final, la estructura organizacional determina la arquitectura. Un solo equipo integró todo para reducir la complejidad
Esto no es “monolítico”, sino un nivel de servicio ajustado adecuadamente al tamaño del equipo
Me parece que esta estructura es la más ideal. Si el equipo crece, entonces habría que volver a separarlo
No soy un defensor de los microservicios, pero me llama la atención la falsa dicotomía entre “monorepo vs. microservicios”
Demasiadas herramientas asumen una relación 1:1 entre servicio y repo
Pero puedes tener todo en un solo repo y aun así desplegar de forma independiente
Sería bueno que en lugares como GitHub se pudiera tratar cada carpeta como un servicio independiente
Gestionábamos el árbol de dependencias con Bazel y usábamos
bazel querypara encontrar los targets afectados y ejecutar pruebas automáticamenteTambién armamos un workflow conectado con GitHub Actions para bloquear PRs
Funcionó bien, pero llevó varios meses construirlo
El problema real era la falta de operación y herramientas — CI, autoescalado y sistema de guardias, todo era insuficiente
Ambos enfoques pueden fracasar
En entornos como Node.js o Python, hay un límite en la cantidad de código que el event loop puede manejar
He visto a 6~8 personas administrar 200 servicios, y también a 80 personas administrar un solo monolito
Los microservicios son convenientes para cambios pequeños, pero dificultan los cambios globales,
mientras que el monolito es lo contrario
Al final, lo importante no es la arquitectura, sino la abstracción, las pruebas y la forma de desacoplar
El criterio de “micro” no es técnico, sino una unidad de negocio
Si lo divides más allá de eso, se convierte en nanoservicios
En entornos como Beam, JVM, Rust o Go, es un problema ya resuelto
¿Es un problema de caché de CPU?
Yo pensaba que normalmente se usaba Go, Java o C#
En la mayoría de las empresas, los microservicios fueron más bien la causa del 90% de los problemas
A menos que seas una organización gigante como AWS, Google o Netflix, no parecen encajar
Ya es difícil dividir un sistema en unidades componibles, así que agregar además fronteras de red es una tontería
Creo que la próxima tendencia será alejarse de React o las SPA y volver a un enfoque centrado en el servidor
Que se hayan pasado a microservicios porque “las pruebas se rompían seguido” suena como un enfoque demasiado al revés
Es raro cambiar por completo la estructura del codebase solo porque las pruebas fallen
Al separar por equipo las VMs y la configuración de CI/CD, desaparecieron los conflictos en las pruebas
La desventaja es que no detectas de inmediato los choques entre funcionalidades, pero como la propiedad del código estaba clara, no fue un gran problema
Hubo una petición para agregar [2018] al título
Dicen que separaron el repo porque “si una prueba fallaba, había que modificar incluso código no relacionado”,
pero parece que también pudo haber habido otras soluciones, como cambiar la forma de ejecutar las pruebas o permitir despliegues manuales
Separar el repo no era la única solución