Em grandes aplicações monolíticas, o rastreamento e o monitoramento de erros muitas vezes tornam-se ineficazes devido à falta de propriedade clara. Este guia aborda o problema propondo uma abordagem estruturada para atribuir responsabilidades por meio de anotações de domínio.
Configurar um monitoramento eficaz para grandes sistemas monolíticos com várias equipes pode ser um desafio. Sem uma propriedade clara, o rastreamento de erros torna-se genérico e muitas vezes ignorado. Uma solução é fazer com que engenheiros de plantão identifiquem qual equipe deve responder aos alarmes de monitoramento. No entanto, uma abordagem mais eficiente é incluir informações de domínio e equipe em cada log e intervalo do Datadog.
Para saber qual equipe é responsável por diversas partes de nossa aplicação, usamos um sistema chamado Domain Annotations. As Anotações de Domínio rotulam cada parte do código do seu aplicativo, indicando claramente quem é responsável por quê. Isso fornece organização clara e responsabilidade no gerenciamento de responsabilidades.
As anotações de domínio fornecem um método claro e organizado para rastrear as responsabilidades da equipe em um aplicativo monolítico. Ao marcar partes do seu código com anotações de domínio, você pode:
Para garantir monitoramento e rastreabilidade eficientes, cada solicitação da web é marcada com as informações de domínio apropriadas. Isto é conseguido através da colaboração de vários componentes: DomainProvider
, DomainSpanService
, DomainMdcProvider
e DomainHandlerInterceptor
.
Aqui está uma visão geral de alto nível do processo descrito no diagrama a seguir:
A implementação detalhada desses componentes será encapsulada em uma biblioteca compartilhada, fornecendo uma solução reutilizável para marcação e monitoramento de solicitações da Web em grandes aplicações monolíticas.
Definir a propriedade no nível da classe é simples com anotações de domínio. Ao aplicar anotações de nível superior às classes principais, a propriedade se propaga para todos os recursos detalhados dentro dessas classes. Cada equipe pode rotular as classes de sua propriedade com as anotações de domínio apropriadas, garantindo clareza e responsabilidade sem a necessidade de marcar cada método.
Nos casos em que várias equipes possuem código em uma classe e a refatoração imediata não é apropriada, você pode marcar métodos individuais com anotações de domínio diferentes, que têm prioridade sobre as anotações em nível de classe. Isto permite que métodos específicos sejam atribuídos a diferentes equipes, proporcionando flexibilidade sem complicar a estrutura geral.
Embora as anotações de domínio sejam extremamente úteis, há casos raros em que elas não podem ser usadas. Por exemplo, encontramos problemas com a criação de trabalhos do Quartz, que não funcionavam perfeitamente com anotações de domínio devido a um conflito entre a lógica AOP do Quartz e a lógica AOP usada para anotações de domínio.
Para jobs e processos que não podem ser anotados diretamente, utilizamos o DomainTagsService diretamente nas implementações dos jobs. Essa abordagem nos permitiu adicionar manualmente tags de domínio à lógica de execução do trabalho.
Aqui está um exemplo de como integramos DomainTagsService em um trabalho Quartz:
final override fun execute(context: JobExecutionContext) { domainTagsService.invoke(domain) { withLoggedExecutionDetails(context, ::doExecute) } }
Embora ter serviços separados para cada equipe ofereça vantagens significativas no monitoramento e na propriedade, isso acarreta altos custos e esforços para dividir o monólito, juntamente com possíveis despesas adicionais de desenvolvimento. Considerando a possibilidade de melhorar os tempos de construção com Gradle quando o monólito é dividido em módulos, manter um monorepo pode ser a solução mais eficiente em muitos casos.
Para simplificar o monitoramento das atividades de cada equipe no Datadog, você pode atribuir nomes de serviço artificiais para períodos de equipes diferentes. Essa abordagem garante que cada equipe tenha sua própria seção dedicada nas ferramentas de monitoramento do Datadog. Embora o uso de nomes de serviços artificiais possa ser confuso se você tiver muitos serviços para gerenciar, ele se torna gerenciável com um número limitado de serviços de back-end. Adicionar prefixos a esses nomes de serviço artificiais ajuda a manter a organização e a clareza na configuração do Datadog, tornando mais fácil distinguir entre diferentes equipes e suas responsabilidades.
usar o diagrama em vez da captura de tela? ter trabalhador/webapp não faz sentido aqui
Usar nomes de serviço artificiais para logs pode criar confusão, pois a mesma entrada de log pode aparecer em serviços diferentes.
Por exemplo, considere dois endpoints usando o mesmo serviço de autenticação. Se esses endpoints forem anotados com domínios diferentes, a lógica de autenticação produzirá logs sob diferentes serviços artificiais. Isso pode causar confusão ao explorar os logs, pois eles aparecem sob vários nomes de serviço. Para evitar esse problema, é melhor aplicar nomes de serviço artificiais apenas a intervalos agregados em rastreamentos, para que haja menos confusão
Isto faz algum sentido? Eu não acho que seja
Aqui está uma representação visual deste problema:
O uso de serviços artificiais permite não apenas trabalhar com rastreamentos de APM, mas também filtrar por serviço nas métricas do Datadog, que são armazenadas por um período prolongado, permitindo o rastreamento de alterações por um período prolongado.
Abaixo está uma captura de tela de um monitor no Datadog que usa o nome de serviço artificial konsus-assets
na consulta:
Abaixo está uma captura de tela de um painel no Datadog que usa o nome de serviço artificial konsus-assets
no filtro:
Ao utilizar serviços falsos em sua estratégia de monitoramento, você pode aumentar a visibilidade e a responsabilidade das atividades de cada equipe em um aplicativo monolítico. Essa abordagem simplifica o processo de criação e manutenção de monitores e painéis específicos da equipe, levando a um monitoramento mais eficaz e organizado no Datadog.
As anotações de domínio fornecem uma abordagem direta para simplificar o monitoramento de aplicativos monolíticos no Datadog. Ao implementar esta estratégia, você pode melhorar a capacidade de gerenciamento de logs, spans e métricas, transformando sua configuração de monitoramento em uma ferramenta adaptada para equipes específicas. Isso melhora a responsabilidade e a organização e facilita a solução de problemas e a análise de desempenho de forma mais eficaz e eficiente em todo o seu aplicativo.
DomainTagsService
diretamente nas implementações de trabalhos garante que o monitoramento específico do domínio ainda possa ser mantido.Definir Domínios e Equipes
Isso vai mudar com a lib!!!
Crie enums representando diferentes domínios e equipes em seu aplicativo:
@Domain
é uma anotação que pode ser aplicada a classes ou funções, marcando-as com um valor de domínio específico.DomainValue
é um enum que representa diferentes domínios, cada um associado a uma equipe.Team
é um enum que representa as diversas equipes que trabalham no aplicativo. @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 }
Anote classes (e métodos, se necessário)
@Domain(DomainValue.USER_MANAGEMENT) class UserService { @Domain(DomainValue.PAYMENT_PROCESSING) fun processPayment() { ... } }
Lidar com casos não suportados
Para casos que não podem ser anotados diretamente, use DomainTagsService
diretamente para encapsular a lógica
fun executeNotSupportedByAnnotationsLogic() { domainTagsService.invoke(domain) { executeLogic() } }
Monitore com Datadog
Use filtros de serviço artificiais para filtros de monitores, painéis e rastreamentos de APM
Seguindo essas etapas, você pode implementar efetivamente anotações de domínio em seu aplicativo monolítico, garantindo monitoramento, responsabilidade e eficiência geral aprimorados.