Em busca da latência perfeita
Esse blogpost é sobre meu caminho para chegar no SLO de latência em um ambiente de microsserviços com arquitetura assíncrona e de como a ferramenta latency-agregattor me ajudou a chegar no meu objetivo. Também é meio que uma continuação sobre o tema observabilidade e SLO de posts passados.
Primeiro, o que é SLO? SLO é o acrônimo para Service-Level Objective, ou objetivo de nível de serviço. Na prática um acordo formal, normalmente dentro de uma SLA, entre produtos & negócios com o time de desenvolvimento para definir o valor alvo a ser atingindo sobre uma métrica específica, como tempo de atividade ou tempo de resposta. Você pode se aprofundar mais na fonte, o livro de SRE do google.
SLO — Tempo de resposta
Como foi dito, SLO é um acordo, e este acordo pode ser simples assim:
99% das requisições da página inicial devem retornar em menos de 100ms nos últimos 30 dias.
Pronto! Temos um SLO de latência, porém…SRE é User-Centred, SLO deve ser sobre as jornadas críticas dos seus usuários e não sobre serviços. Neste momento que as coisas ficam complicadas em sistemas com arquitetura assíncrona, porque, diferente de uma aplicação monolítica, o serviço não é o início e o fim, mas sim apenas um pedaço do todo.
SLO — Sistema monolítico
Partindo da premissa que estamos usando o serviço instrumentado para gerar a métrica, vamos precisar apenas marcar o início de um processo e no fim gerar um histograma com o valor da duração.
SLO — Arquitetura síncrona
Mesmo tendo mais serviços durante o fluxo, ainda temos um único ponto de entrada e saída, o que facilita gerarmos nossa métrica de latência.
SLO — Arquitetura Assíncrona
Aqui as coisas podem ser difíceis, por exemplo, você pode ter um serviço de pedidos que escreve em um tópico (ou fila) e um serviço de pagamento que vai efetuar o pagamento. O fluxo inicia em um serviço e termina no outro.
As coisas evoluem e surge um novo serviço depois do pagamento para fazer a entrega do pedido.
Neste cenário que o latency-agregattor poderá ser útil, atuando como um centralizador da métrica de latência, mas vamos ver primeiro como cheguei nele.
Latency agregattor
Precisava de uma forma simples de contabilizar a latência levando em conta todos os percalços no meio do caminho, como por exemplo atraso nos tópicos e erro no meio do fluxo.
Primeiro eu tentei gerar um histograma de cada serviço e juntar isso pra tentar chegar no valor de latência da jornada, porém, essa abordagem não leva em consideração o atraso do consumidor da fila, por exemplo, o que já gera um furo na nossa métrica.
Depois eu tentei passar esse o valor inicial da jornada(created_at) no serviço inicial, no serviço final usei o diff de tempo (now() - created_at) para gerar a métrica, porém… se aparecer um serviço depois do último furaria a métrica, se desse qualquer erro no meio ficaria complexo garantir que o serviço problemático “fechasse” a métrica.
Inspirado no Pushgateway e no Prometheus Aggregation Gateway que surgiu o latency-agregattor, que tem como objetivo deixar fácil a adição de novos serviços na jornada e tratar os casos onde temos problemas no meio.
Latency Agregattor na pratica
Você pode subir uma instância usando a imagem disponível docker hub que ira expor as métricas para o scrape do Prometheus no path /metrics, desta forma:
docker run -p 7070:7070 fsrg/latency-aggregator:0.0.1
Se estiver usando GoLang, basta usar a lib que o projeto oferece para submeter sua métrica
Ou, se preferir, pode usar a API do serviço, assim:
Sob o capô
O.K., mas como ele funciona?
A mecânica por de trás do Latency Agregattor é bem simples. Primeiro ele agenda o export da métrica a cada intervalo de life_span para um UUID, e a cada novo request ele reagenda esse export. Desta forma, se um request não chegar no tempo esperado, a métrica será gerada, ou seja, se algo de imprevisto acontecer no meio do fluxo, a métrica será gerada. Seguindo a mesma lógica ele encerra o fluxo, já que, depois do último request, a task agendada vai ser executado no final do life_span expondo a métrica com o tempo que levou do primeiro request até o último.
O serviço ainda esta sendo estressado por aqui, a lista de todo é grande, mas qualquer pitaco será sempre bem-vindo! vlw!
[]s