O blog da AWS

Observabilidade na AWS com CloudWatch – Parte I

Por Erik Miyashita e Roberto Silva, Arquitetos de Soluções da AWS Brasil

 

Introdução

Nesta série (Parte 1, Parte 2, Parte 3) de blog posts abordaremos os desafios relacionados à adoção de microserviços em um contexto de observabilidade.

Arquiteturas baseadas em Microserviços têm se tornado um padrão na indústria de tecnologia, sendo adotadas de startups a grandes conglomerados corporativos.

Quando adotamos esse padrão identificamos diversos benefícios relacionados a produtividade, escalabilidade e resiliência das aplicações. Contudo novos desafios emergem como a monitoração de sistemas distribuídos.

Em uma aplicação monolítica todos os processo geram logs em um mesmo local, já em uma aplicação composta de centenas ou até milhares de microserviços o log está distribuído. Dessa forma a análise de uma única requisição de usuário implica em analisar o log de diversos microserviços que atendam esta requisição.

Neste cenário de aumento de complexidade, precisamos de um conjunto de técnicas e ferramentas que nos permitam ter visibilidade do estado destes serviços em nosso ambiente, com o intuito de agir, em caso de uma falha, bem como se antecipar em uma situação de degradação de performance.

O termo observabilidade relacionado ao assunto vem ganhando espaço na indústria, e este refere-se a habilidade de descrever o estado atual de um determinado sistema, com base em 3 pilares fundamentais: logs, métricas e rastreamento distribuído.

Esta série de blog posts demostrará como nossos clientes utilizam a plataforma da AWS para endereçar estes pilares.

 

Pré-requisitos

Utilizaremos uma aplicação baseada principalmente em containers, uma vez que é uma das escolhas mais comuns para execução de microserviços.

Abaixo está a arquitetura da aplicação:

 

 

A arquitetura acima é composta de um frontend baseado em containers entregue através do Amazon EKS, backend baseado em AWS Fargate e AWS Lambda, e por último sua camada de persistência é entregue pelo Amazon RDS e Amazon DynamoDB. Não é idéia focarmos no provisionamento desta infraestrutura neste blog post, contudo o passo-a-passo pode ser encontrado na seção de preparação do workshop de observabilidade da AWS a qual explora inclusive diversas outras ferramentas.

 

Logs

Em um cenário de microserviços uma requisição pode se desdobrar em chamadas de múltiplos microserviços cada um com o seu log.

Outro fator para levar em consideração é que muitas vezes estes microserviços executam em plataforma efêmeras, como é o caso de containers e do Lambda. Logo, fica evidente a necessidade de externalizar todos estes logs para um local centralizado, evitando que os mesmos sejam perdidos, bem como para se ter a visibilidade do todo.

Para endereçar este ponto, a AWS conta com o Amazon Elasticsearch Service e com o Amazon CloudWatch Nesse blog post utilizaremos o CloudWatch, por se tratar de um serviço gerenciado no qual a AWS é responsável por sua disponibilidade, escalabilidade e infraestrutura relacionada, liberando assim os times para focar seus esforços em atividades mais estratégicas ao seus negócios.

Nossa aplicação é implementada através de containers executando em EKS e Fargate, além de um serviço implementado em Lambda. A seguir vamos entender como estas plataformas centralizam seus logs no CloudWatch.

Logs no lambda

No que se refere ao lambda o desenvolvedor precisa apenas garantir que a função tenha permissão de envio do log para o CloudWatch. Uma vez configurada esta permissão padrão todo fluxo de STDOUT e STDERR do lambda será direcionado para o CloudWatch.

Com a configuração corretamente estabelecida basta prover uma instrução como o print() no Python ou console.log() no Node e esta saída será direcionada para o cloudwatch em um log group.

console.log("Updated petid: " + payload.petid + ", pettype: " + payload.pettype + ", to availability: " + availability);

Techo da função Lambda da aplicação

Logs no fargate

Para que o Fargate baseado em ECS envie logs para o CloudWatch é necessária a configuração do awslogs log driver na definição da tarefa do Fargate, onde desta forma todo fluxo de dado encaminhado para STDOUT e STDERR será encaminhada para o CloudWatch

"logConfiguration": {
"logDriver": "awslogs",
"secretOptions": [],
"options": {
"awslogs-group": "/ecs/PetListAdoptions",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs-logs"
}

Techo da definição da task PetTrafficGenerator no fargate

Logs no EKS

Quando utilizamos o EKS baseado em EC2 um padrão comum é de externalizar o logs dos containers através de um daemonset, este tipo de recurso é utilizado pelo Kubernetes quando existe a necessidade de garantir que tenhamos um pod por nó. Utilizamos esta abstração quando precisamos entregar algo comum aos diversos pods que estão executando em um nó, como no nosso caso de externalizar log de todos os pods para o CloudWatch.

O CloudWatch Container Insights coleta, agrega e resume métricas e logs de seus aplicativos, o mesmo pode ser utilizado no Amazon ECS como no Amazon EKS.

O provisionamento que fizemos anteriormente não instalou o Container Insights no EKS, contudo, o guia de configuração pode ser utilizado para tal.

Quando instalamos utilizando a configuração rápida para o container insights são criados diversos recursos, contudo, 3 merecem destaque: o namespace amazon-cloudwatch e dois DaemonSet, sendo o agente do Cloudwatch executado em uma versão conternizada, e o fluentd, responsáveis por enviar métricas e logs respectivamente.

O comando abaixo demonstra como esta configuração rápida pode ser aplicada e verificada (se atentar a substituição do nome da região e do nome do cluster).

curl https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-
insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-
monitoring/quickstart/cwagent-fluentd-quickstart.yaml | sed "s/{{cluster_name}}/cluster-
name/;s/{{region_name}}/cluster-region/" | kubectl apply -f -

kubectl get all -n amazon-cloudwatch

Como já comentado acima, uma vez que este log sejam externalizados, os mesmos poderão ser encontrados nos respectivos log group e log stream.

Logs centralizados

Uma vez que este log esteja armazenado em um stream de um log group, é possível filtrar eventos do log considerando um intervalo de data, bem como uma determinada string, no caso abaixo o filtro aplicado foi de 1 hora e utilizamos a string PetType.

 

 

Correlacionando logs

Um bom começo é centralizar os logs, porém como citado anteriormente, uma única requisição pode implicar no acionamento de múltiplos microserviços, e mesmo que todos os logs estejam em um local centralizado, ainda é necessário que seja estabelecida uma correlação entre estes logs para assim entendermos a requisição em sua totalidade.

Esta correlação pode ser obtida através de um ID único por requisição o qual é compartilhado entre os diversos microserviços envolvidos nessa requisição. Outro ponto fundamental é a habilidade de consultar múltiplos log group no CloudWatch utilizando este ID para entender a requisição como um todo, isto pode ser feito através do CloudWatch Log Insights.

Quando utilizamos a funcionalidade de pesquisa da nossa aplicação dois microserviços são acionados, sendo o primeiro no EKS responsável pelo frontend, e o segundo no fargate que obterá os dados dos pets que atendam o critério de pesquisa enviada pelo frontend.

Um ponto importante aqui é a geração de um ID o qual é compartilhado com o frontend, bem como o serviço de pesquisa de pets. Ambos serviços utilizam este ID quando gravam seus logs, desta forma podemos analisar a requisição como um todo através deste ID.

 

 

Com este ID em mãos, é possível utilizar o Log Insights pesquisando nos log groups de cada um dos serviços utilizando o ID da requisição para correlaciona-los:

fields @timestamp, @message
| sort @timestamp desc
| limit 20
| filter @message like /1-5f6e248f-63abca7cf51f6a3b3f047b2a/

 

 

Além de permitir aplicar filtros em múltiplos Log groups, o Log Insights permite também agregarmos logs, por exemplo:

Imagine que gostaríamos de verificar quantas vezes o serviço PetSearch foi acionado nos últimos minutos, para tal verificação bastaria executar a consulta abaixo:

fields @timestamp, @message
| stats count(@message) as number_of_events by bin(5m)
| limit 20
| filter @message like /PetSearch.SearchParams/

 

 

Outro recurso interessante do Log Insights é a possibilidade de salvar uma consulta para utilização futura e o histórico de consultas.

Salvando

 

 

Histórico das consultas executadas

 

Conclusão

Durante este blog post entendemos como a AWS apoia os clientes para endereçar desafios relacionados com logs em sistemas distribuídos, a importância dos mesmos estarem em um repositório centralizado como o CloudWatch, bem como a necessidade de um ID com o intuito de estabelecer correlações entre os logs de múltiplos microserviços.

Outros aspectos importantes que devemos levar em consideração com relação a log em um cenário de microserviços são:

Formato de armazenamento, existem diversos formatos de log como o GELF, SYSLOG, NCSA entre outros, contudo JSON é um formato amplamente utilizado e suportado, além de ser um formato muito utilizado em analytics e aprendizado de máquina.

Desenvolvimento, durante o ciclo de desenvolvimento de microserviços utilize um framework de log bem estabelecido, como por exemplo o log4j muito utilizado em aplicações java. Padronize os logs com níveis como trace, debug, information, warning, error e critical com o intuito de facilitar a depuração em caso de problema.

Estrutura do log, além da sua utilização natural na depuração de uma aplicação, logs são frequentemente utilizados em cargas de trabalhos analiticas, aprendizado de máquina entre outros processos automatizados. Estabelecer uma estrutura minima de log facilita o processamento nesse tipo de carga de trabalho.

Bom, este foi o primeiro blog post da série a qual abordaremos os pilares de observabilidade.

Na parte II trataremos o pilar de métricas.


Sobre os autores

Erik Miyashita é arquiteto de soluções na AWS com larga experiência em sistemas distribuídos, DevOps e monitoração. Atualmente atende clientes do segmento enteprise, auxiliando-os a utilizar melhor os recursos de cloud computing.

 

 

 

 

Roberto Fernandes da Silva é arquiteto de soluções na AWS com mais de 14 anos no mercado de tecnologia. Atualmente seu foco esta no suporte a clientes do segmento enterprise em suas jornadas de nuvem bem como em ferramentas de gerenciamento.