O blog da AWS

Observabilidade na AWS com CloudWatch – Parte II

Por Roberto Silva e Thiago Paulino, Arquitetos de Soluções da AWS Brasil

 

Introdução

Na parte I desta série sobre observabilidade exploramos o pilar de log e como podemos utilizar a AWS para endereçar os desafios relacionados.

Nessa segunda parte exploraremos o pilar de métricas.
Métricas são medidas de propriedades de um componente de software e/ou hardware. Esses componentes geram métricas que permitem acompanhar o seu estado ao longo do tempo.

Um exemplo clássico de métrica é o envio de dados relacionados ao consumo de infraestrutura, onde normalmente instalamos e configuramos um agente em um servidor que envia métricas de utilização de memória, CPU e disco para um backend de métricas em uma periodicidade estabelecida.

Quando plotamos essas métricas em uma linha do tempo, estabelecemos o consumo da nossa infraestrutura em um determinado período. Esse caso de consumo de infraestrutura é meramente ilustrativo, poderíamos aplicar o mesmo conceito aos pedidos feitos em uma plataforma de e-commerce a qual seria uma métrica muito mais focada na perspectiva de negócio.

Existem diversos tipos de métricas, como por exemplo contadores que só crescem ao longo do tempo, como o número de pedidos no dia, ou aquelas variáveis como o consumo de CPU que oscila ao longo do tempo, entre outros tipos.

É muito comum aplicarmos operações de agregação em métricas para entendermos o contexto daquela métrica em um dado momento, operações como médias, somas, medianas, percentis entre outras.

Imagine que uma determinada aplicação envia uma métrica que representa a quantidade de clientes cadastrados em uma plataforma nos últimos 10 minutos, caso seja necessário verificar qual hora do dia os clientes fazem cadastro com maior frequência, precisaremos agregar esta métrica utilizando soma em um agrupamento por hora.

Neste blog post exploraremos como utilizar a plataforma da AWS em um contexto de métricas. Utilizaremos como exemplo a mesma aplicação da parte I.

 

Pré-requisitos

Na parte I da série utilizamos o CloudWatch Container Insights para o envio de logs e métricas através do agente do CloudWatch e Fluentd respectivamente, agora aproveitaremos das métricas que o Fluentd envia do Amazon EKS com o intuito de explorarmos as possibilidades do que podemos fazer com estas métricas no Amazon CloudWatch.

 

 

CloudWatch Métricas

Quando enviamos métricas para o CloudWatch elas são agrupadas em namespaces os quais basicamente servem como um container de métricas, e não devem ser confundidos com o recurso namespace do kubernetes.

 

 

Detalhando as métricas podemos visualizar os agrupamentos aplicados as mesmas, como por exemplo ClusterName, InstanceID e NodeName que daremos o nome de dimensão, os quais podemos ver exemplo abaixo:

 

 

Uma vez na dimensão, podemos visualizar cada uma das métricas conforme exposto na figura abaixo, onde filtramos métricas relacionadas ao consumo de memória dos dois nós do EKS.

 

 

Muitas vezes se faz necessário pesquisar múltiplas métricas correlacionadas.

Por exemplo, imagine que gostaríamos de verificar todas as métricas relacionadas com a memória dos nossos servidores, através da funcionalidade de Expressão de Pesquisa do CloudWatch conseguimos consultar múltiplas métricas que atendam um determinado padrão.

SEARCH('{ContainerInsights,ClusterName,InstanceId,NodeName} cpu', 'Average', 300)

 

 

Na expressão acima em destaque pesquisamos métricas do namespace ContainerInsight, com a dimensão de ClusterName, InstanceID e NodeName e as métricas que contenham a palavra “CPU” em seus nomes, onde agregaremos seus valores a partir da média em intervalos de 5 minutos.

A sintaxe geral obedece o seguinte padrão:

SEARCH(' {Namespace, DimensionName1, DimensionName2, ...} SearchTerm', 'Statistic', Period)

Matemática em métricas é outra funcionalidade do CloudWatch que nos permite aplicar funções de agregação em múltiplas métricas.

No exemplo a seguir faremos a soma das médias da utilização de memória pelos nós do cluster através da aba Métricas em Gráficos e do botão Expressão matemática. Através dessa funcionalidade analisaremos o estado de um componente de nossa aplicação, como neste caso o consumo de memória dos nós.

 

 

Painéis

Para termos uma visão clara do estado de uma aplicação precisamos analisar e acompanhar múltiplas métricas. Métricas isoladas nos provê um entendimento limitado sobre o estado da aplicação. Dessa forma se faz necessário o agrupamento de múltiplas métricas em um local centralizado, para tal finalidade podemos utilizar painéis do CloudWatch.

Em um painel podemos agrupar diversos gráficos que representam métricas, facilitando significativamente nosso entendimento sobre o estado da aplicação.

Para criar um painel basta acessar a opção Painéis do CloudWatch, clicar em Criar Painel, prover um nome como observability-dashboard e escolher o tipo de widget que comportará o tipo de informação disponibilizada no dashboard.

No nosso caso utilizaremos o tipo Linha sendo que as fontes de dados serão métricas do EKS.

 

 

Em nosso exemplo visualizamos o consumo de memória dos nós do EKS, para tal escolhemos o namespace do ContainerInsights com as dimensões ClusterName, InstanceId, NodeName e com a métrica node_memory_utilization, conforme abaixo:

 

Após clicar em Criar widget, o mesmo será adicionado no painel observability-dashboard disponibilizando as métricas selecionadas.

 

 

Além de métricas podemos utilizar o resultado de consultas executadas no CloudWatch Log Insights.

Na parte I da série utilizamos o CloudWatch Log Insights para pesquisarmos múltiplos logs groups através de um id de correlação, agora utilizaremos o resultado de uma consulta feita no CloudWatch Log Insights com o intuito de gerar um gráfico para o nosso painel.

Adicione um novo widget do tipo linha semelhante ao que fizemos no exemplo anterior, com exceção que agora utilizaremos como fonte de dados logs.

 

 

Uma vez escolhida a opção logs basta escolher o log group que contenha a informação e executar a consulta desejada.

 

 

Alarmes

Analisar e monitorar métricas através de painéis nos ajuda a compreender o estado da aplicação de forma mais ampla do que analisar métricas individualmente. Contudo, não podemos acompanhar esses painéis 24 horas 7 dias por semana, pois não seria uma abordagem eficaz. Tomar conhecimento apenas em situações que estejam fora da normalidade seria uma maneira mais eficiente de monitoramento.

Por exemplo, imagine que gostaríamos de ser notificados caso nossa aplicação tenha um consumo de memória superior a 80%, para assim tomarmos alguma ação como automatizar um processo que provisione um novo servidor para suprir o aumento desta demanda computacional, este tipo de ação pode ser orquestrada através de um alarme.

Exploraremos as capacidades de alarme do CloudWatch criando alarmes baseados em métricas ou através da composição de alarmes. Os que se utilizam de métricas monitoram o resultado de uma expressão matemática ou uma métrica do CloudWatch, onde alcançando um determinado valor o mesmo tem o seu estado alterado para alerta, podendo disparar uma ação como por exemplo uma notificação.

Abaixo vejamos isso na prática:

Uma vez que esteja na seção de alarme do CloudWatch basta criar alarme, selecionar métrica, escolher o namespace ContainerInsights, a dimensão ClusterName e por fim a métrica pod_cpu_utilization.

 

 

Uma vez estabelecida a métrica e sua periodicidade, também é necessário definir as condições para que o alarme mude de estado. Em condições podemos estabelecer o tipo de limite como estático ou uma detecção de anomalia.

No primeiro exemplo abaixo utilizamos o tipo estático onde estabelecemos um limite fixo de 50% por um período de 5 minutos. Caso a métrica atinja este limite pelo menos uma vez o alarme mudará de estado.

No segundo exemplo, ao invés de definirmos um limite fixo utilizamos a detecção de anomália a qual se utiliza de aprendizado de máquina para estabelecer um padrão de comportamento através do histórico da métrica. Caso essa métrica se desvie do comportamento esperado por duas vezes em 5 minutos o alarme mudará de estado.

 

 

Seguindo com o modelo estático, o próximo item que precisamos definir é a notificação.

Aqui definimos que, caso a métrica ultrapasse o limite estabelecido deverá ser enviado um email de notificação através do Amazon SNS.

Por fim, devemos prover um nome e descrição para o alarme, e uma tela de resumo será disponibilizada para que o mesmo seja criado.

 

Abaixo segue o alarme criado, onde a linha vermelha estabelece seu limite.

Uma vez que a métrica ultrapasse a linha por duas vezes em um intervalo de 5 minutos, o alarme mudará seu estado e disparará um email de notificação conforme configuração estabelecida.

 

 

Além dos alarmes baseados em métricas podemos criar também alarmes baseados em composição.

Alarmes compostos são aqueles que mudam o seu estado baseado na composição de alarmes filhos. Ou seja, para que ele fique no estado de alerta, todos os alarmes filhos que compõem o seu estado precisam estar em alerta também.

Abaixo vamos ver na prática:

Uma vez na aba alarme basta escolher os alarmes filhos, configurar o operador lógico bem como outros alarmes que se façam necessários, estabelecer a notificação e por último configurar o nome e a descrição desejada.

 

 

Desta forma criamos um alarme composto, onde ele só mudará de estado para alerta e enviará sua notificação se um dos alarmes filhos estiver em alerta.

Utilizando o operador lógico AND o alarme composto terá o seu estado alterado somente quando ambos alarmes filhos estejam em situação de alerta.

 

 

Containers Insights

O CloudWatch Container Insights coleta, agrega e sumariza log e métricas do nosso ambiente de container baseados em EKS ou Amazon ECS. Temos utilizado essa funcionalidade para externalizar log e métricas do nosso cluster de EKS, e agora exploraremos outras funcionalidades sob a perspectiva de métrica que ele nos entrega.

Com o Container Insights temos uma guia de performance e monitoramento que podemos explorar em diversos níveis de granularidade, como por exemplo Cluster, Namespace, Servidores, Services e Pods. Ele se utiliza das métricas enviadas pelo agente do CloudWatch e cria um painel para fácil visualização, além de possuir atalhos para os alarmes configurados para as métricas, e logs dos containers enviados para o CloudWatch.

 

 

O Container Insights também se integra com métricas compatíveis com o Prometheus.

Os passos necessários para configuração podem ser obtidos no workshop de observabilidade da AWS.

Após a devida configuração a arquitetura será a seguinte:

 

O frontend da aplicação que utilizamos ao longo desta série possui um endpoint /metrics ao qual expõe métricas no formato do Prometheus. Um novo agente do CloudWatch é instalado sendo este capaz de coletar as métricas do Prometheus e envia-las a um log group no CloudWatch.

O CloudWatch utiliza sua capacidade de métricas incorporadas extraindo as mesmas a partir do log, enviando-as no namespace e dimensões estabelecidas.

 

O trecho de código abaixo refere-se a um evento no log stream, no qual podemos constatar que as métricas petsite_pet_kitten_searches_total, petsite_petsearches_total, petsite_pet_puppy_searches_total e petsite_pet_bunny_searches_total devem ser extraídas para o namespace ContainerInsights com as dimensões ClusterName, Namespace e app.

{
    "CloudWatchMetrics": [{
        "Metrics": [{
            "Name": "process_cpu_seconds_total"
        }],
        "Dimensions": [
            ["ClusterName", "Namespace"]
        ],
        "Namespace": "ContainerInsights/Prometheus"
    }, {
        "Metrics": [{
            "Name": "dotnet_jit_method_seconds_total"
        }],
        "Dimensions": [
            ["ClusterName", "Namespace"]
        ],
        "Namespace": "ContainerInsights/Prometheus"
    }, {
        "Metrics": [{
            "Name": "petsite_pet_kitten_searches_total"
        }, {
            "Name": "petsite_petsearches_total"
        }, {
            "Name": "petsite_pet_puppy_searches_total"
        }, {
            "Name": "petsite_pet_bunny_searches_total"
        }],
        "Dimensions": [
            ["ClusterName", "Namespace", "app"]
        ],
        "Namespace": "ContainerInsights/Prometheus"
    }],
    "ClusterName": "PetSite",
    "Namespace": "default",
    "Timestamp": "1600989834796",
    "Version": "0",
    "app": "petsite",
    "container_name": "petsite",
    "dotnet_contention_seconds_total": 0,
    "dotnet_contention_total": 0,
    "dotnet_jit_method_seconds_total": 0,
    "dotnet_threadpool_scheduled_total": 39,
    "instance": "11.0.130.0:80",
    "job": "PetSite",
    "petsite_pet_bunny_searches_total": 0,
    "petsite_pet_kitten_searches_total": 0,
    "petsite_pet_puppy_searches_total": 0,
    "petsite_petadoptions_total": 0,
    "petsite_petsearches_total": 0,
    "pod_controller_kind": "ReplicaSet",
    "pod_controller_name": "petsite-deployment-7777dfb546",
    "pod_name": "petsite-deployment-7777dfb546-6pkxq",
    "pod_phase": "Running",
    "pod_template_hash": "7777dfb546",
    "process_cpu_seconds_total": 0.4500000000000455,
    "prom_metric_type": "counter"
}

Uma vez processadas como métricas podemos consulta-las na funcionalidade de métricas, e utilizar todos os conceitos que vimos até o momento neste blog post.

 

 

Conclusão

Ao longo deste blog post constatamos como CloudWatch pode ser útil para trabalharmos com métricas, nos ajudando a entender o estado de nossas aplicações sem ter que lidar com infraestrutura.

Além dos aspectos já expostos neste blog post vale salientar os seguintes pontos:

Considere o seu negócio, se souber dizer o consumo de memória de um container, mas não sabe quando uma aplicação está indisponível, provavelmente está trabalhando com as métricas erradas. Um bom ponto aqui é considerar os KPI(s) do seu negócio.
A frequência importa, em software muita coisa acontece em um intervalo de minutos ou até segundos. Dessa forma estabeleça intervalos curtos para a coleta de métricas.
Tenha uma metodologia, aplique uma metodologia em suas métricas para analisar a performance da sua aplicação como por exemplo o método USE.
Facilite sua análise, crie painéis que facilitem a visualização das métricas e permitam ter o panorama do estado da aplicação.
Descrédito no alerta, quando criar alertas baseados em métricas atente-se ao falsos positivos para que os alertas não caiam em descrédito sendo completamente ignorados.

Bom, este foi o segundo blog post da série que abordamos os pilares de observabilidade.

No último blog post da série trataremos o pilar de rastreamento distribuído.

 


Sobre os autores

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.

 

 

 

 

Thiago Paulino é arquiteto de soluções da AWS com mais de 15 anos de experiência e especialização em BigData & Analytics. Atualmente seu foco está no suporte a clientes do segmento enterprise.

 

 

 

 

Agradecimento aos revisores:

Guilherme França e Tiago Reichert: Arquitetos de Solução da AWS.