Caso de estudio · Fincaraiz.com.co · 2019 a 2022

De monolito a microservicios, sin detener una plataforma de 5 millones de visitas.

Como CTO de Fincaraiz.com.co, uno de los principales portales inmobiliarios de Colombia, lideré la migración de un monolito ASP.NET heredado a microservicios con Django y React sobre Kubernetes. Migramos en cuatro niveles detrás de un API Gateway con Kong, mantuvimos sincronizados los datos viejos y nuevos con AWS Lambda y reconstruimos la búsqueda para que entendiera cómo la gente realmente nombra los lugares. La plataforma nunca se cayó, siguió igual de rápida y los costos de hosting y mantenimiento bajaron 50%.

50%menos costo de hosting y mantenimiento
100%disponibilidad durante la migración, para más de 5 millones de visitas al mes
<3 sLargest Contentful Paint, igual que el sistema anterior
30 mintiempo de publicación de inmuebles, mantenido durante el cambio

La situación

Fincaraiz.com.co es uno de los principales portales inmobiliarios de Colombia, parte del grupo Adevinta en ese momento. Más de 5 millones de personas lo visitaban cada mes para buscar lotes, apartamentos, casas y locales comerciales, y los agentes publicaban y actualizaban inmuebles todos los días.

Todo eso funcionaba sobre un monolito ASP.NET heredado, servido con Windows IIS en instancias virtuales de Amazon EC2, con Microsoft SQL Server para los datos y Apache Solr para la búsqueda. Se habían acumulado cuatro problemas:

  • Un monolito difícil de cambiar. Todo estaba muy acoplado, así que cada despliegue ponía en riesgo todo el sitio, y los servidores se parchaban a mano.
  • Costos altos. Las máquinas virtuales y las licencias de Microsoft encarecían el hosting y el mantenimiento.
  • Una búsqueda por palabras clave, no por intención. La configuración de Solr no manejaba bien la variedad de búsquedas inmobiliarias, con tipos de inmueble muy distintos.
  • Ubicaciones imprecisas. La gente busca con nombres informales de barrios, apodos locales y frases conversacionales. El buscador no entendía la mayoría.

Y una restricción por encima de todo: el sitio tenía que seguir funcionando. Sin caídas, sin inconsistencias de datos, sin picos de latencia y sin perder posiciones en buscadores.

El objetivo

  • Reemplazar el monolito por servicios en Django y React que el equipo pudiera cambiar y desplegar de forma independiente.
  • Salir del software con licencia y de los servidores administrados a mano para reducir costos.
  • Mantener el sitio arriba todo el tiempo, para usuarios y agentes.
  • Mantener los Core Web Vitals iguales o mejores que el sitio anterior, y la publicación de inmuebles en su referencia de 30 minutos.
  • Lograr que la búsqueda entendiera lo que la gente quiere decir, incluida la forma en que nombra los lugares.

El enfoque: cuatro niveles, una capa a la vez

Reescribir todo de una vez nunca fue una opción. Usé el patrón strangler fig: construir el sistema nuevo alrededor del viejo, mover el tráfico por partes y retirar el monolito cuando nada dependa de él. Para hacerlo manejable, dividí el trabajo en cuatro niveles, y cada uno hacía posible el siguiente.

NivelAntesDespués
1. PlataformaEC2 con máquinas virtuales, Windows IIS, parches manualesContenedores Docker en Kubernetes, NGINX, CI/CD automatizado
2. Entrada e identidadEl tráfico iba directo al monolitoKong API Gateway enruta cada solicitud, Keycloak para identidad y acceso
3. Datos y búsquedaMicrosoft SQL Server, Apache SolrPostgreSQL para transacciones, Elasticsearch para búsqueda, Lambda sincronizando ambos mundos
4. Servicios y frontendUn solo código en ASP.NETServicios en Django por dominio de negocio, frontend en React

Arquitectura durante la migración

Usuarios y agentesMás de 5 millones de visitas al mes
Kong API GatewayNivel 2: envía cada ruta al sistema viejo o al nuevo
KeycloakNivel 2: una sola capa de identidad y acceso para ambos
Monolito ASP.NET heredadoIIS en EC2, SQL Server y Solr. Retirado por partes
Sincronización con AWS LambdaNivel 3: basada en eventos, mantiene ambos almacenes idénticos
Servicios Django y ReactNivel 4: asumen un dominio a la vez
PostgreSQLNivel 3: transacciones e integridad de datos
ElasticsearchNivel 3: búsqueda con NLP y polígonos geográficos
Celery y RabbitMQPublicación masiva de inmuebles
Kubernetes, Docker, NGINX y CI/CD en AWSNivel 1: la plataforma donde corre todo lo nuevo
HeredadoNuevoPiezas de migración

Nivel 1: una plataforma para el sistema nuevo

Antes de mover código, los servicios nuevos necesitaban dónde correr. Reemplazamos las máquinas virtuales de EC2 administradas a mano por contenedores Docker orquestados con Kubernetes, cambiamos Windows IIS por NGINX como servidor web y proxy inverso, y pusimos pipelines de CI/CD automatizados antes de cada despliegue. Desplegar pasó de ser un evento riesgoso y manual a algo rutinario, y el nuevo stack usaba menos recursos para más tráfico.

Nivel 2: una sola puerta de entrada, una sola identidad

Después pusimos Kong API Gateway delante de ambos sistemas. Desde entonces, cada solicitud pasaba por un solo punto que decidía si respondía el sistema viejo o el nuevo. Eso nos permitió mover el tráfico ruta por ruta, y devolver una ruta al sistema viejo si algo se veía mal. Keycloak dio a ambos sistemas una sola capa compartida de identidad y acceso.

Nivel 3: datos y búsqueda, siempre sincronizados

Movimos los datos transaccionales de Microsoft SQL Server a PostgreSQL, lo que mejoró la integridad y el rendimiento y eliminó el costo de licencias. La búsqueda pasó de Apache Solr a Elasticsearch, hecho para lecturas rápidas y de alto volumen. PostgreSQL manejaba lo que tenía que ser correcto; Elasticsearch, lo que tenía que ser rápido.

Lo más difícil fue operar dos sistemas al mismo tiempo. Funciones de AWS Lambda basadas en eventos copiaban cada cambio entre los almacenes viejos y nuevos en tiempo real, así que nunca se contradecían mientras los servicios se migraban uno por uno. Un inmueble publicado en cualquiera de los dos lados seguía apareciendo en la misma ventana de 30 minutos de antes.

Nivel 4: servicios por dominio y un frontend nuevo

Con la plataforma, el gateway y los datos listos, dividimos el monolito en servicios Django, uno por dominio de negocio, con un frontend en React. Cada servicio asumió su parte del sitio detrás de Kong, un dominio a la vez. El trabajo pesado, como publicar inmuebles en gran volumen, pasó a tareas en segundo plano con Celery y RabbitMQ, para que un pico de cargas de agentes no volviera lento el sitio para todos.

Una búsqueda que entiende cómo la gente nombra los lugares

Pasar la búsqueda a Elasticsearch también fue la oportunidad de hacerla más inteligente. Fue trabajo temprano con IA, años antes de la ola actual de IA generativa.

  • Consultas en lenguaje natural. Agregamos comprensión de lenguaje natural, para que la búsqueda leyera la intención de una consulta conversacional en lugar de depender de filtros.
  • Un mapa de todo el país. Adquirimos datos cartográficos y de malla vial de Colombia: ciudades, municipios, barrios y puntos de referencia.
  • Nombres oficiales y apodos locales. Relacionamos los nombres oficiales con los nombres informales y alias que la gente realmente usa, y convertimos límites y zonas de interés en polígonos geográficos y vectores dentro de Elasticsearch.

Un ejemplo: "Zona T" es como mucha gente llama a una zona de Bogotá, pero ningún mapa oficial usa ese nombre. La búsqueda lo resolvía así:

Ejemplo: de un apodo local a un barrio oficial

Búsqueda del usuario"apartamentos en Zona T"
Coincidencias candidatasZona T · Zona Rosa · El Retiro · Chapinero · referencias cercanas
NormalizaciónApodo y alias resueltos contra los polígonos oficiales
Barrio oficial: EL RETIROCódigo 008310 · Localidad: CHAPINERO
Resultados inmobiliariosInmuebles dentro de ese límite exacto

La búsqueda pasó de comparar palabras a entender lugares.

Lo que salió mal: el inicio de sesión único

No todas las decisiones funcionaron. Keycloak era la idea correcta, una sola capa de identidad para ambos sistemas, pero era nuevo para el equipo y está construido en Java, que estaba fuera de nuestras habilidades principales. Encontramos problemas de integración que no habíamos previsto, y los vacíos en la documentación los hicieron lentos de resolver. Esa parte del proyecto tomó seis veces más de lo estimado.

En herramientas críticas, que el equipo las conozca y el soporte que tengan importan tanto como sus funcionalidades.

Hicimos una sesión abierta de lecciones aprendidas en lugar de buscar culpables, y agregamos un paso de evaluación para herramientas críticas: ¿el equipo conoce el stack?, ¿qué tan buena es la documentación y la comunidad?, ¿a quién llamamos cuando falle?

Liderar a 30 ingenieros en el proceso

  • Propiedad para los seniors. Diseñé la arquitectura de alto nivel y les di a los ingenieros senior la propiedad total de implementarla. Eso hizo crecer la capacidad de liderazgo dentro del equipo y evitó que yo fuera un cuello de botella.
  • Scrum en todas las áreas. Llevamos Scrum más allá de ingeniería y acordamos una sola Definición de Terminado y un solo formato de sprint review, para que producto, ingeniería y negocio vieran el mismo avance.
  • Meter las manos cuando importaba. Cuando el nuevo stack abrumó al equipo, lo aprendí lo bastante rápido para desbloquear a la gente directamente, hasta que tuvieron confianza por su cuenta.
  • Hacer crecer a las personas. Acompañé a un ingeniero junior para que asumiera un módulo crítico y defendiera sus decisiones de diseño, como PostgreSQL en lugar de NoSQL. Lo promovieron a nivel medio a los cinco meses.

Resultados

MedidaAntesDespués
Costo de hosting y mantenimientoMáquinas virtuales y licencias de Microsoft50% menos
Disponibilidad durante la migraciónn/a100%, sin caídas
DesplieguesParches manuales, alto riesgoCI/CD automatizado, en contenedores
Largest Contentful PaintMenos de 3 sMenos de 3 s, con un sistema más complejo
Tiempo de publicación de inmuebles30 minutos30 minutos, con dos sistemas en paralelo
BúsquedaPalabras clave en Apache SolrLenguaje natural y coincidencia geográfica en Elasticsearch
Servidor webWindows IIS en EC2NGINX en Kubernetes, menos recursos, más capacidad
APIs REST en el nuevo backendn/aMás de 15, con 25% menos latencia

Lo que llevaría a la próxima migración

  • Construir primero la plataforma y el gateway. Después, cada movimiento es una decisión de enrutamiento que se puede deshacer.
  • Reservar tiempo real para mantener dos sistemas sincronizados. Es la parte más difícil y la que protege al negocio.
  • Elegir herramientas que el equipo ya conoce para todo lo crítico en seguridad.
  • Medir desde el primer día lo que sienten los usuarios, como la velocidad de la página, para que "sin regresiones" sea un número y no una esperanza.

Erwin MonguiDirector de Tecnología en Cedar Planters e ingeniero certificado en Inteligencia Artificial, en Toronto. Más de 18 años construyendo plataformas y los equipos que las operan.

Recibe mis próximos casos y artículos en la Búsqueda de Google.