Microservicios vs arquitectura monolítica.png

Microservicios en Symfony cuándo usarlos y cuándo es mejor un monolito modular

Guillem

8 min de lectura

Cómo escalar una aplicación Symfony sin añadir complejidad antes de tiempo

A medida que una aplicación en Symfony crece, la arquitectura deja de ser solo una decisión técnica. Empieza a afectar al ritmo al que entregas, a la estabilidad con la que operas y a la facilidad con la que el equipo puede evolucionar el producto sin generar fricción innecesaria.

Lo que al principio funciona bien —un único repositorio, un despliegue simple y una base de datos centralizada— puede empezar a quedarse corto cuando el tráfico aumenta, las reglas de negocio se multiplican o varias personas trabajan a la vez sobre zonas muy distintas del sistema. En este tipo de escenarios, trabajar con un enfoque sólido de desarrollo de aplicaciones complejas en Symfony marca la diferencia entre escalar con criterio o arrastrar problemas.

En ese momento, la pregunta útil no es si los microservicios son una arquitectura más moderna. La pregunta útil es otra: qué problema concreto estás resolviendo al dividir el sistema.

La decisión no empieza en los microservicios

En muchos proyectos, el siguiente paso natural no es separar servicios, sino ordenar mejor el monolito.

Antes de repartir responsabilidades entre procesos, red y despliegues independientes, suele haber bastante margen para mejorar la estructura interna del sistema. Y ahí es donde un monolito modular tiene mucho sentido en Symfony: te permite organizar el código por dominios, hacer explícitas las dependencias y reducir el acoplamiento sin asumir todavía el coste operativo de una arquitectura distribuida.

Dicho de otro modo: no se trata de aguantar con un monolito hasta que no quede más remedio. Se trata de darle una forma que permita crecer con criterio. En muchos productos, esa forma es suficiente durante años.

Cuándo los microservicios sí empiezan a tener sentido

Los microservicios empiezan a ser una opción razonable cuando distintas partes del sistema dejan de comportarse igual.

Sucede, por ejemplo, cuando facturación tiene dependencias externas y requisitos de fiabilidad distintos al resto del producto, cuando reporting concentra carga intensiva pero no necesita la misma inmediatez que el flujo principal, o cuando las integraciones con terceros evolucionan a un ritmo mucho más impredecible que el núcleo de negocio.

También tiene sentido plantearlos cuando varios equipos trabajan sobre dominios diferentes y el cuello de botella ya no está en el código, sino en la coordinación. Si cada cambio obliga a sincronizar despliegues, revisar impactos laterales y negociar prioridades dentro del mismo bloque, la arquitectura empieza a penalizar la organización.

Hay una señal especialmente clara: cuando necesitas aislar una capacidad crítica para que pueda escalar, desplegarse o fallar de manera distinta al resto. Ahí la separación puede aportar valor real. No por fragmentar el sistema, sino por alinear mejor la tecnología con el comportamiento del negocio.

Un SaaS con autenticación, facturación, notificaciones, reporting e integraciones es un buen ejemplo. No todos esos módulos tienen el mismo volumen, la misma criticidad ni la misma cadencia de cambio. Intentar tratarlos siempre como una única pieza termina generando fricción tanto en desarrollo como en operación.

Cuándo no compensan

Los microservicios no son una mejora automática. Cambian un tipo de complejidad por otro.

Dentro de un monolito, muchos problemas se resuelven con llamadas internas, transacciones locales y una única traza mental del sistema. En cuanto separas servicios, entran en juego la latencia de red, el versionado de contratos, la gestión de fallos parciales, la observabilidad distribuida y la consistencia entre datos que ya no viven dentro del mismo proceso.

Por eso, en productos en fase inicial, equipos pequeños o aplicaciones cuya lógica todavía está consolidándose, dividir demasiado pronto suele salir caro. Cuando aún estás aprendiendo qué necesita de verdad el negocio, lo habitual es que el mayor valor no esté en repartir piezas, sino en iterar rápido y mantener el sistema comprensible.

Tampoco suele compensar cuando los límites del dominio todavía no están claros. En ese caso, extraer servicios no elimina el acoplamiento: simplemente lo empuja fuera del código y lo convierte en llamadas HTTP, eventos y dependencias entre esquemas.

El valor real de un monolito modular en Symfony

Symfony encaja especialmente bien en este punto intermedio. Te permite construir una base sólida sin forzarte a tomar demasiado pronto decisiones de distribución que luego son difíciles de revertir.

Un monolito modular bien planteado hace varias cosas bien a la vez.

  • Mantiene la simplicidad operativa de un único despliegue.
  • Facilita el debugging porque todo ocurre dentro del mismo contexto de ejecución.
  • Conserva la consistencia fuerte de los datos cuando la necesitas.
  • Y, además, te obliga a pensar en dominios y responsabilidades antes de pensar en infraestructura.

Eso tiene una ventaja poco vistosa, pero muy rentable: te da información. Cuando el sistema está ordenado por capacidades de negocio, es mucho más fácil identificar qué parte del producto realmente necesita independizarse y cuál no.

Por eso, en muchos proyectos, el monolito modular no es una solución provisional. Es una solución suficiente y, durante bastante tiempo, la más sensata.

Diseñar bien los límites empieza por el dominio

El error más habitual no es elegir mal la tecnología. Es diseñar mal las fronteras.

Un microservicio no debería nacer porque autenticación merece su propio proyecto o porque notificaciones parece sencillo de sacar. Debería nacer cuando existe una capacidad de negocio suficientemente diferenciada en responsabilidad, datos, ritmo de cambio y necesidades operativas.

Eso obliga a mirar menos la estructura del código y más el funcionamiento real del producto. Identidad y acceso, billing, pedidos, notificaciones, reporting o integraciones pueden ser buenos candidatos, pero no por su nombre, sino porque suelen tener procesos, datos y ciclos distintos.

Cuando una frontera está bien definida,

  • cada servicio tiene una responsabilidad clara
  • es dueño de sus datos
  • publica contratos explícitos
  • puede evolucionar sin coordinación constante con los demás

Cuando eso no pasa, el sistema solo parece distribuido. Por dentro sigue estando acoplado.

Cómo encaja Symfony en una arquitectura de microservicios

Symfony tiene una ventaja práctica en este terreno: no te obliga a usarlo siempre de la misma manera. Puedes construir un servicio con el framework completo o apoyarte solo en componentes concretos, según la naturaleza de la pieza que estés desarrollando. Además, Messenger permite gestionar mensajes de forma síncrona o asíncrona mediante transports y workers, lo que encaja bien cuando empiezas a separar responsabilidades o a sacar trabajo fuera del ciclo de una petición HTTP.

Eso hace que Symfony funcione bien tanto para APIs como para procesos en segundo plano, comandos operativos o integraciones. Y, sobre todo, mantiene algo que suele perderse cuando una plataforma crece: consistencia. Mismas convenciones, mismo conjunto de herramientas, mismas prácticas de testing y observabilidad. Menos folklore técnico y más foco en resolver bien el problema.

Comunicación entre servicios sin crear una maraña

En una arquitectura distribuida, decidir cómo se hablan los servicios importa casi tanto como decidir qué separas.

La comunicación síncrona por HTTP sigue teniendo su lugar. Es útil cuando necesitas una respuesta inmediata, cuando una validación forma parte del flujo principal o cuando la operación solo tiene sentido si el otro servicio responde en ese momento. El problema aparece cuando todo pasa por ahí. Entonces la latencia se acumula, los fallos se encadenan y una petición aparentemente simple acaba dependiendo de media plataforma.

La comunicación asíncrona cobra más sentido cuando el sistema puede aceptar que algunas acciones ocurran después. Notificaciones, generación de informes, sincronizaciones con terceros o ciertos procesos de facturación suelen encajar mejor en ese modelo. A nivel de infraestructura, Pub/Sub está pensado precisamente para desacoplar productores y consumidores mediante mensajería asíncrona y escalable. Eventarc, por su parte, sirve para enrutar eventos desde distintas fuentes hacia destinos gestionando la entrega, la seguridad, la observabilidad y el manejo de errores. Y cuando el problema ya no es solo publicar un evento, sino coordinar varios pasos entre servicios o APIs HTTP, Workflows permite orquestar esas dependencias de forma explícita y observable.

Aquí hay un matiz importante: pasar de HTTP a eventos no es simplemente cambiar de herramienta. Es cambiar la forma en la que diseñas el sistema. En Pub/Sub, por defecto, debes asumir entrega at-least-once, lo que implica diseñar consumidores idempotentes y preparar el sistema para reintentos y redelivery.

Dicho de forma menos elegante y más útil: si recibes 2 veces un evento como InvoicePaid, no puedes permitir que se emitan 2 facturas, se registren 2 cobros o se envíe 2 veces la misma notificación. Ese tipo de detalle no es accesorio. Es parte del diseño.

Datos y consistencia en una arquitectura distribuida

Aquí es donde muchas arquitecturas aparentemente limpias empiezan a torcerse.

Como criterio general, cada servicio debería ser dueño de sus datos y exponerlos mediante contratos, no mediante acceso directo a las tablas de otro servicio. Ese principio no existe por purismo. Existe para proteger la autonomía del sistema. Cuando varios servicios dependen del mismo esquema, cualquier cambio sencillo se vuelve una negociación.

Eso no significa que desde el día 1 necesites una base de datos físicamente distinta por servicio. En determinados contextos, varias capacidades pueden convivir en la misma instancia si los límites están claros, el ownership está definido y no existen consultas cruzadas que mezclen responsabilidades. El problema aparece cuando esa comodidad inicial termina borrando las fronteras y devolviéndote al mismo acoplamiento, pero con más complejidad alrededor.

En microservicios, la consistencia no desaparece como requisito. Lo que cambia es la forma de conseguirla. En algunos casos necesitarás consistencia fuerte dentro de un servicio y consistencia eventual entre servicios. Y eso exige modelar mejor el dominio, los estados intermedios y las compensaciones cuando algo falla.

Escalabilidad real en Symfony no consiste solo en dividir

Una aplicación no escala automáticamente porque esté repartida en varios servicios.

Escala cuando está diseñada para su carga real. Eso implica servicios sin estado cuando conviene escalar horizontalmente, caché bien utilizada, trabajo costoso fuera del ciclo de petición y respuesta, consultas de base de datos saneadas y dependencias externas aisladas para que no contaminen todo el flujo.

A veces, la mejor mejora de escalabilidad no es extraer un servicio, sino dejar de hacer trabajo innecesario dentro de una petición, usar técnicas como ESI, o mover a procesamiento asíncrono una tarea que no necesita bloquear al usuario. O evitar que una integración lenta condicione todo el sistema.

Dividir puede ayudar. Sustituir el diseño por división, no.

Despliegue de microservicios Symfony en Google Cloud

Symfony encaja bien en un entorno cloud cuando la prioridad no es usar muchas piezas, sino operar con claridad. En Google Cloud, una base razonable suele pasar por containerizar cada servicio y elegir Cloud Run según el tipo de carga: services para endpoints HTTP, jobs para tareas batch o programadas y worker pools para cargas de fondo siempre activas, como consumidores pull. Cloud Run, además, ejecuta estas variantes en el mismo entorno y evita tener que gestionar clusters para ser productivo.

A partir de ahí, Pub/Sub puede cubrir la mensajería asíncrona entre servicios, Eventarc el enrutado de eventos hacia destinos concretos y Workflows la orquestación de procesos con varios pasos o dependencias explícitas.

Kubernetes tiene sentido cuando de verdad necesitas más control operativo, no como peaje de entrada. Mientras no exista esa necesidad, la combinación de despliegues predecibles, observabilidad y un número razonable de piezas suele dar mucho más rendimiento que una plataforma sobredimensionada.

Errores que se repiten más de la cuenta

El primero es dividir demasiado pronto. Cuando todavía no entiendes bien el dominio, la arquitectura distribuida solo consigue repartir la confusión.

El segundo es crear servicios que no son realmente autónomos. Si un microservicio depende continuamente de otros para completar cualquier operación, no has aislado una capacidad de negocio: has fragmentado un flujo.

El tercero es mantener el acoplamiento a través de APIs. Cambiar llamadas internas por 5 llamadas HTTP no convierte un sistema en mejor arquitectura. A veces solo convierte una operación sencilla en una cadena de fallos potenciales.

El cuarto es subestimar los datos. Muchas decisiones aparentemente razonables se rompen cuando llegan las sincronizaciones, los reintentos, los desfases entre estados o la necesidad de auditar lo ocurrido.

Y el quinto es dejar la observabilidad para después. En un monolito, muchas cosas se pueden entender siguiendo una traza local. En microservicios, si no sabes qué pasó, dónde pasó y por qué pasó, el coste operativo se dispara.

Un enfoque práctico para evolucionar sin romper lo que funciona

El camino más sensato suele ser menos épico y más efectivo.

  1. Empieza con un monolito.
  2. Ordénalo por dominios.
  3. Haz visibles las fronteras.
  4. Observa dónde aparece la fricción real.
  5. Y solo entonces extrae aquello que de verdad gana autonomía técnica o de negocio al independizarse.

Facturación suele ser un buen candidato cuando concentra reglas sensibles, dependencias externas y necesidades de trazabilidad. Notificaciones también, porque el volumen y el modelo asíncrono suelen justificar su aislamiento. Reporting puede ganar mucho al separarse si consume recursos de forma intensiva y no necesita formar parte del flujo interactivo. E integraciones con terceros suelen beneficiarse de un límite propio porque viven sometidas a latencias, contratos y errores que no deberían contaminar el núcleo del producto.

Mientras tanto, el núcleo puede seguir siendo monolítico sin que eso sea un problema. De hecho, muchas veces esa es la decisión más madura.

Conclusión

Symfony te permite construir tanto un monolito modular sólido como una arquitectura de microservicios. La diferencia no está en la herramienta. Está en la calidad del criterio con el que decides.

Los microservicios aportan valor cuando ayudan a aislar dominios, a escalar partes concretas del sistema y a reducir fricción organizativa. Pero también introducen más diseño, más operación y más puntos de fallo. Por eso no deberían ser un punto de partida, sino una respuesta consciente a una necesidad real.

En la mayoría de proyectos, el recorrido más robusto empieza con algo más simple: un monolito bien diseñado, modular por dentro y suficientemente claro como para saber qué merece separarse y qué no.

Si estás valorando cómo escalar una aplicación en Symfony, merece la pena parar aquí y tomar esa decisión con criterio. No solo por arquitectura. También por mantenibilidad, por coste operativo y por la velocidad a la que tu equipo va a poder seguir construyendo sin fricción.

¿Estás evaluando si tu producto necesita seguir como monolito modular o empezar a extraer servicios en Symfony?

Conoce cómo trabajamos el desarrollo de aplicaciones Symfony para sistemas complejos y escalables.

FAQs

¿Cuándo merece la pena pasar de un monolito a microservicios en Symfony?

Cuando hay una necesidad clara que el monolito ya no resuelve bien. Por ejemplo, cuando distintas partes del sistema tienen requisitos de escalabilidad diferentes, cuando varios equipos necesitan trabajar con autonomía real o cuando una capacidad crítica requiere aislarse a nivel operativo.

Si el sistema sigue siendo comprensible, desplegable y escalable dentro de un monolito modular, normalmente todavía no es el momento.


¿Se puede escalar una aplicación Symfony sin microservicios?

Sí, y de hecho es lo más habitual.

Un sistema bien diseñado puede escalar durante bastante tiempo sin dividirse en servicios independientes. Uso de caché, procesamiento asíncrono, optimización de base de datos y una buena separación por dominios dentro del monolito suelen aportar más valor que introducir microservicios demasiado pronto.

Dividir no sustituye un buen diseño.


¿Qué es mejor para Symfony: Cloud Run o Kubernetes?

Depende del nivel de complejidad operativa que necesites asumir.

Cloud Run suele ser suficiente en muchos casos: permite desplegar servicios, jobs y workers sin gestionar infraestructura y con un modelo de escalado automático bastante sólido.

Kubernetes tiene sentido cuando necesitas un control más fino sobre la plataforma, pero también implica más carga operativa. No debería ser el punto de partida si no hay una necesidad clara.


¿Cómo se comunican los microservicios en Symfony?

Hay dos enfoques principales.

La comunicación síncrona (HTTP) es útil cuando necesitas respuesta inmediata, pero introduce dependencia directa entre servicios.

La comunicación asíncrona (eventos y colas) permite desacoplar procesos y mejorar la resiliencia del sistema. Aquí es habitual usar herramientas como Symfony Messenger a nivel de aplicación y sistemas como Pub/Sub para mensajería distribuida.

La clave no es la herramienta, sino diseñar bien contratos, reintentos e idempotencia.


¿Es obligatorio que cada microservicio tenga su propia base de datos?

No necesariamente desde el principio.

Lo importante no es tanto la separación física como el ownership. Cada servicio debería ser responsable de sus datos y no depender del esquema de otros.

Puedes compartir infraestructura en fases iniciales, pero si los límites no están claros, el sistema termina acoplado aunque esté dividido.

📫
Hasta aquí el artículo de hoy. ¡Si quieres puedes escribirnos por redes sociales como siempre, o a hola@softspring.es con cualquier duda o sugerencia!

¡Trabajemos juntos!

¿Quieres contarnos tu idea?

CONTÁCTANOS