Preparação e números de tech da maior beauty week do Brasil.
A beleza na web e o grupo boticário passaram pela maior beauty week nos e-commerces este ano e aqui estão alguns números e algumas das lições que aprendemos nos preparando para esta semana.
Primeiro um panorama do cenário e os números de infraestrutura :
- 4 Kubernetes clusters ( AWS EKS ).
- 60+ micro serviços.
- 476 K8s ec2 worker nodes.
- 4.000+ pods.
- 200+ deployments.
- 15TB ram em uso pelos clusters kubernetes.
- 900 cpu cores em uso pelos clusters kubernetes.
- 250.000 requests por minuto em nosso api-gateway.
- 197.000 requests por minuto em nosso storefront.
- 1 elasticsearch cluster , 200 i3.2xlarge data nodes.
- 13.000+ buscas ativas por minuto em nosso cluster de elasticsearch( roda em ec2 self managed ).
- 25 Rds postgresql DBs.
- 25 mongodb replica sets + 1 sharded cluster ( Todos ec2 self managed ).
- 6.5 Milhões de execuções da nossa principal função lambda durante a sexta feira.
Suportamos picos de 100% de tráfego em questões de poucos minutos sem grandes picos de tempo de resposta.
Alcançamos este resultado realizando stress testes, pre scale e uma série de otimizações nas aplicações e a nível de infra.
Neste artigo foco nos números e otimizações de infra.
A realização de stress tests + visibilidade é crucial para obter este resultado. Testamos e garantimos a estabilidade do ambiente com uma carga maior do que a prevista.
Diversos ajustes de aplicações foram necessários, mas encontramos e ajustamos alguns números a nível de deployment no kubernetes também :
- Aplicações nodeJS receberam 1.5GB de ram por cpu. O máximo reconhecido pela engine V8 via flag. Assim atingimos a estabilidade e capacidade de lidar com picos repentinos de tráfego sem problemas.
- 1GB de headroom para todas as apis java + ajuste fino de escala vertical para liberar theads e memória para as jvms.
Todos estes valores foram encontrados durante os testes de carga !
Nosso backend core também suportou com tempos de respostas otimizados durante os picos.
Durante os testes descobrimos que o backend demorava mais que o ideal para escalar organicamente em alguns casos, em outros mesmo escalando olhando para consumo de CPU / RAM ainda não era o suficiente para obter o tempo de resposta ideal.
Para tal foi necessário um pre scale para um mínimo de 25 pods em cada uma das apps. Com este valor o tempo de resposta estabilizou conforme acima.
Para 2021 queremos escalar por RPM e tempo de resposta da JVM além de CPU / RAM utilizando o custom metrics no kubernetes , atualmente já utilizamos o JMX_EXPORTER para reportar o consumo de ram diretamente da JVM para o custom metrics / hpa do kubernetes.
Ao otimizar as instâncias ec2 dos mongodbs e os volumes EBS conseguimos reduzir o tempo de espera da CPU por IO. Saímos de uma média de 2% do tempo de CPU para apenas 0.2% ao adequar o tamanho da instância.
Isso traduz em querys rápidas e apis com tempo de resposta ideal e estável durante picos.
Outro indicador de saúde que precisa ficar o mais próximo de 0 sempre é o page faults. Um número elevado desta métrica indica que o mongoDB está lendo muitos dados diretamente do disco pois o dataset não está cabendo na memória.
O tempo de resposta aumenta assim e a saúde geral cai. A ideia é sempre manter próximo de 0. Um número alto de documentos escaneados por minuto pode indicar falta de índice.
Ao mudar a instance family para uma acima ( xlarge -> 2xlarge ) os indicadores de saúde melhoraram.
Um último ajuste foi conferir IOPS nos discos destas instâncias. Se a soma de IOPS de leitura + escrita estivessem acima do que o disco possuia e a métrica de queue no disco seja para leitura ou pra escrita estivesse acima de 0, nós provisionamos para IO1 com o número adequado de IOPS e removemos este gargalo.
Nos bancos relacionais postgresql atuamos em 2 frentes :
- Camada de dados, otimização de querys e índices.
- Otimização a nível de RDS ( parâmetros do parameter group ).
Com otimizações nessas 2 frentes conseguimos resultados expressivos como o acima onde uma query com tempo médio de resposta de 80ms baixou para apenas 3.5ms.
Isso garante a estabilidade destes bancos e apis que dependem deles durante alto tráfego. Os valores e ajustes são muito específicos de acordo com cada banco e realidade. Porém alguns dos parâmetros que ajustamos foram :
wal_buffer , work_mem, effective_cache_size, effective_io_concurrency, shared_buffers …
Um último ponto de atenção foi o pool de conexões com estes bancos relacionais como o ambiente é elástico e o pool acompanhava precisamos ajustar de acordo. Para 2021 queremos um pool estático que não acompanhe o número de pods.
Um número elevado de conexões pode sobrecarregar o banco ou simplesmente esgotarem e novos pods não conseguirem se conectar ao banco e falharem o seu health check.
Utilizamos a família de instâncias I3 recomendadas pela elastic e pela aws para este tipo de workload que precisa de muito IOPS e sofre picos no mesmo.
A família I3 é custo eficiente em termos de IO.
A configuração de shards e réplicas por index é bem delicada e depende de cada ambiente, index e frequência de acesso. Temos alguns índices de alto acesso com mais de 10GB de dados e para estes utilizamos a configuração de :
11 shards.
10 réplicas.
Removemos índices antigos ( versões ) que ainda existiam ( caso um rollback emergencial fosse necessário ), esta ação aliviou todos os data nodes do cluster em termos de consumo de cpu e load average, mesmo estes índices não recebendo requisições.
Outro ponto que foi essencial para a escalabilidade e estabilidade da plataforma foi o cache de DNS implementado diretamente nas aplicações nodeJS no front-end. Chegamos a estourar o hard limit de 1024 pacotes por segundo por ENI dentro da aws antes desse cache ser implementado e requisições de resolução DNS falhavam dentro do cluster.
Um ponto que já deve ter ficado claro é que sem medir não é possível melhorar e otimizar. É um princípio básico se você quer otimizar algo você precisa medir e ter como comparar o antes e depois. Sempre trabalhamos em cima de métricas e dados.
Com toda essa preparação e testes conseguimos passar por uma excelente semana de beauty week com o ambiente estável. Aprendemos algumas lições e anotamos alguns pontos que não conseguimos identificar durante os testes.
O time por trás dessa infraestrutura tem apenas 6 pessoas, conseguimos esse grau de eficiência trabalhando com muita automação e gestão automatizada de configurações.