En aplicaciones monolíticas de gran tamaño, el seguimiento y la supervisión de errores a menudo se vuelven ineficaces debido a la falta de una propiedad clara. Esta guía aborda el problema proponiendo un enfoque estructurado para asignar responsabilidades a través de anotaciones de dominio.
Configurar un monitoreo efectivo para grandes monolíticos con múltiples equipos puede ser un desafío. Sin una propiedad clara, el seguimiento de errores se vuelve genérico y a menudo se ignora. Una solución es hacer que los ingenieros de guardia identifiquen qué equipo debe responder a las alarmas de monitoreo. Sin embargo, un enfoque más eficiente es incluir información del dominio y del equipo en cada registro y tramo de Datadog.
Para realizar un seguimiento de qué equipo es responsable de las distintas partes de nuestra aplicación, utilizamos un sistema llamado Anotaciones de Dominio. Las anotaciones de dominio etiquetan cada parte del código de su aplicación, indicando claramente quién es responsable de qué. Esto proporciona una organización clara y responsabilidad en la gestión de responsabilidades.
Las anotaciones de dominio proporcionan un método claro y organizado para realizar un seguimiento de las responsabilidades del equipo dentro de una aplicación monolítica. Al etiquetar partes de su código con anotaciones de dominio, puede:
Para garantizar un seguimiento y una trazabilidad eficientes, cada solicitud web se etiqueta con la información de dominio adecuada. Esto se logra mediante la colaboración de varios componentes: DomainProvider
, DomainSpanService
, DomainMdcProvider
y DomainHandlerInterceptor
.
A continuación se ofrece una descripción general de alto nivel del proceso que se muestra en el siguiente diagrama:
La implementación detallada de estos componentes se encapsulará en una biblioteca compartida, proporcionando una solución reutilizable para etiquetar y monitorear solicitudes web en grandes aplicaciones monolíticas.
Definir la propiedad a nivel de clase es sencillo con las anotaciones de dominio. Al aplicar anotaciones de nivel superior a las clases principales, la propiedad se propaga a todos los recursos detallados dentro de esas clases. Cada equipo puede etiquetar las clases de su propiedad con las anotaciones de dominio adecuadas, lo que garantiza claridad y responsabilidad sin la necesidad de marcar cada método.
En los casos en que varios equipos poseen código en una clase y la refactorización inmediata no es apropiada, puede marcar métodos individuales con diferentes anotaciones de dominio, que tienen prioridad sobre las anotaciones a nivel de clase. Esto permite asignar métodos específicos a diferentes equipos, lo que proporciona flexibilidad sin complicar la estructura general.
Si bien las anotaciones de dominio son increíblemente útiles, hay casos raros en los que no se pueden utilizar. Por ejemplo, encontramos problemas con la creación de trabajos de Quartz, que no funcionaba perfectamente con las anotaciones de dominio debido a un choque entre la lógica AOP de Quartz y la lógica AOP utilizada para las anotaciones de dominio.
Para trabajos y procesos que no se pueden anotar directamente, utilizamos DomainTagsService directamente en las implementaciones de trabajos. Este enfoque nos permitió agregar manualmente etiquetas de dominio dentro de la lógica de ejecución del trabajo.
A continuación se muestra un ejemplo de cómo integramos DomainTagsService en un trabajo de Quartz:
final override fun execute(context: JobExecutionContext) { domainTagsService.invoke(domain) { withLoggedExecutionDetails(context, ::doExecute) } }
Si bien tener servicios separados para cada equipo ofrece ventajas significativas en cuanto a monitoreo y propiedad, conlleva altos costos y esfuerzos para dividir el monolito, junto con posibles gastos de desarrollo adicionales. Teniendo en cuenta la posibilidad de mejorar los tiempos de compilación con Gradle cuando el monolito se divide en módulos, mantener un monorepo podría ser la solución más eficiente en muchos casos.
Para simplificar el seguimiento de las actividades de cada equipo en Datadog, puede asignar nombres de servicios artificiales para grupos de diferentes equipos. Este enfoque garantiza que cada equipo tenga su propia sección dedicada en las herramientas de monitoreo de Datadog. Si bien el uso de nombres de servicios artificiales puede resultar confuso si tiene muchos servicios que administrar, resulta manejable con una cantidad limitada de servicios backend. Agregar prefijos a estos nombres de servicios artificiales ayuda a mantener la organización y la claridad en la configuración de Datadog, lo que facilita la distinción entre diferentes equipos y sus responsabilidades.
¿Usar diagrama en lugar de captura de pantalla? tener trabajador/aplicación web no tiene sentido aquí
El uso de nombres de servicios artificiales para los registros puede crear confusión, ya que la misma entrada de registro puede aparecer en diferentes servicios.
Por ejemplo, considere dos puntos finales que utilizan el mismo servicio de autenticación. Si estos puntos finales están anotados con diferentes dominios, la lógica de autenticación producirá registros en diferentes servicios artificiales. Esto podría causar confusión cuando se exploran registros, ya que aparecen bajo varios nombres de servicios. Para evitar este problema, es mejor aplicar nombres de servicios artificiales solo a intervalos que se agregan en seguimientos para que haya menos confusión.
¿Tiene algún sentido? no creo que lo sea
Aquí hay una representación visual de este problema:
El uso de servicios artificiales le permite no solo trabajar con seguimientos de APM, sino también filtrar por servicio en Datadog Metrics, que se almacenan durante un período prolongado, lo que permite realizar un seguimiento de los cambios durante un período prolongado.
A continuación se muestra una captura de pantalla de un monitor en Datadog que utiliza el nombre de servicio artificial konsus-assets
en la consulta:
A continuación se muestra una captura de pantalla de un panel en Datadog que utiliza el nombre de servicio artificial konsus-assets
en el filtro:
Al utilizar servicios falsos en su estrategia de monitoreo, puede mejorar la visibilidad y la responsabilidad de las actividades de cada equipo dentro de una aplicación monolítica. Este enfoque simplifica el proceso de creación y mantenimiento de monitores y paneles de control específicos del equipo, lo que lleva a un monitoreo más efectivo y organizado en Datadog.
Las anotaciones de dominio proporcionan un enfoque sencillo para simplificar el monitoreo de aplicaciones monolíticas en Datadog. Al implementar esta estrategia, puede mejorar la capacidad de administración de registros, intervalos y métricas, transformando su configuración de monitoreo en una herramienta adaptada a equipos específicos. Esto mejora la responsabilidad y la organización y facilita una solución de problemas y un análisis de rendimiento más efectivos y eficientes en toda su aplicación.
DomainTagsService
directamente en las implementaciones de trabajos garantiza que aún se pueda mantener el monitoreo específico del dominio.Definir dominios y equipos
¡¡¡Eso cambiará con la lib !!!
Cree enumeraciones que representen diferentes dominios y equipos en su aplicación:
@Domain
es una anotación que se puede aplicar a clases o funciones, marcándolas con un valor de dominio específico.DomainValue
es una enumeración que representa diferentes dominios, cada uno asociado con un equipo.Team
es una enumeración que representa los distintos equipos que trabajan en la aplicación. @Retention(AnnotationRetention.RUNTIME) @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) annotation class Domain(val value: DomainValue) enum class DomainValue(val team: Team) { USER_MANAGEMENT(Team.TEAM_A), PAYMENT_PROCESSING(Team.TEAM_B), NOTIFICATIONS(Team.TEAM_C) } enum class Team { TEAM_A, TEAM_B, TEAM_C }
Anotar clases (y métodos si es necesario)
@Domain(DomainValue.USER_MANAGEMENT) class UserService { @Domain(DomainValue.PAYMENT_PROCESSING) fun processPayment() { ... } }
Manejar casos no admitidos
Para los casos que no se pueden anotar directamente, use DomainTagsService
directamente para ajustar la lógica.
fun executeNotSupportedByAnnotationsLogic() { domainTagsService.invoke(domain) { executeLogic() } }
Monitorear con Datadog
Utilice filtros de servicio artificiales para monitores, paneles y filtrado de seguimiento de APM
Si sigue estos pasos, podrá implementar de forma eficaz anotaciones de dominio en su aplicación monolítica, lo que garantizará una mejor supervisión, responsabilidad y eficiencia general.