Ir ao conteúdo

O cache do Amazon API Gateway realmente faz diferença?

Sempre que o assunto é performance de APIs, o uso de cache é uma das soluções mais abordadas. Ao utilizar cache para armazenar respostas estáticas (ou que mudam com pouca frequência), podemos reduzir a carga do servidor e aumentar os tempos de resposta, o que o torna uma solução essencial para a otimização do desempenho.

Há muitas maneiras de implementar cache, desde a camada de aplicação (no código) até a camada de infraestrutura. Hoje vamos testar uma das maneiras mais fáceis de fazer isso: ativando-o diretamente no Amazon API Gateway. Esse método exige pouco esforço de configuração e nenhuma atualização de código, mas será que ele realmente faz diferença? Vamos testar!

Ambiente de testes

A arquitetura da aplicação utilizada no teste será composta por uma Lambda que simulará a API consumida e uma API criada no Amazon API Gateway com dois stages: cache, para o teste com cache ativado e nocache, para o teste com o cache desativado (é, eu sei, óbvio né? xD).

A API (lambda) retorna sempre o mesmo body e tem um tempo de resposta entre 300ms e 600ms para simular uma API real. Já no API Gateway, o TTL (Time to live) do cache foi configurado com 180s (3 minutos).

Código da lambda:

import time
import random

def lambda_handler(event, context):
    # Gera uma espera entre 300ms (0.3s) e 600ms (0.6s)
    delay = random.uniform(0.3, 0.6)
    
    # Adiciona o delay no código
    time.sleep(delay)
    
    # Retorna a mensagem de sucesso.
    return {
        'statusCode': 200,
        'body': 'Success',
    }

Como o terraform para criação dos recursos é extenso, deixei o código disponível no GitHub.

O teste de carga

Primeiro, temos que definir as condições dos testes:

  • O teste tem um limite de execução de 10 minutos
  • O numéro de Usuários Virtuais (VU) é de 990 para ser equivalente a quantidade da concorrência provisionada na Lambda e evitar throttling.
  • Foi adicionado um delay de 200ms entre cada request para o mesmo usuário, para simular o uso “real” de uma API.
  • O teste terminará assim que 1M de requests forem atingidos OU o tempo acabar.

Com as condições definidas, é hora de criar o código para o teste. Neste cenário, iremos usar o k6, ferramenta de testes de carga open-source do Grafana Labs.

import http from 'k6/http';
import { sleep } from 'k6';

// Le o path da API via variável de ambiente
const API_PATH = __ENV.API_PATH;
const BASE_URL = 'https://<API_GATEWAY_ID>.execute-api.<REGION>.amazonaws.com';
const API_URL = BASE_URL + API_PATH;

// Define as condições do teste
export let options = {
    duration: '10m',
    vus: 990, // Number of Virtual Users
    iterations: 1000000, // Total number of requests
};

export default function () {
    // Faz a chamada GET as APIs
    http.get(API_URL);

    // Opcional: Adiciona um delay para simular o mundo real.
    sleep(0.2);
}

Primeiro teste (cache desativado):

O primeiro teste levou 9m17s para atingir 1M de requisições com um throughput de ~1792 requisições por segundo e um tempo de resposta médio de ~552ms. As requisições foram distribuídas desta maneira durante o teste:

** Aparentemente, as métricas do Lambda chegam ao CloudWatch mais rapidamente do que as métricas do API Gateway, o que dá a impressão de que o Lambda começou primeiro, mas não começou.

Segundo teste (com cache ativado):

O segundo teste levou 5m52s para atingir 1M de requisições com throughout de ~2923 requisições por segundo e um tempo de resposta médio de ~338ms. As requisições foram distribuídas desta maneira durante o teste:

** Aparentemente, as métricas do Lambda chegam ao CloudWatch mais rapidamente do que as métricas do API Gateway, o que dá a impressão de que o Lambda começou primeiro, mas não começou.

Resumo e conclusões

  • Throughput: 1792,42 requsições/seg vs 2922,82 requsições/seg ( ⬆️ ˜63% mais alto com cache)
  • Tempo de resposta médio: 551,88ms vs 338,27ms ( ⬆️ ~39% mais rápido com cache)
  • Backend API invocations (lambda): 1M invocações vs 5 invocações ( ⬆️ ~99.8% menos invocações com cache)

Com base nos dados, a implementação do cache proporciona melhorias substanciais no desempenho com pouco esforço de implementação. Outra nota importante é que a implementação de cache não significa necessariamente um aumento nos custos, pois menos chamadas serão feitas para o backend da API, o que pode levar a uma redução nos custos nessa camada. Nosso teste é um bom exemplo disso, já que o lambda é cobrado por invocações e ~98% menos invocações foram feitas com o cache ativado.

Qualquer dúvida, é só dizer 🙂


Descubra mais sobre contains(cloud)

Assine para receber nossas notícias mais recentes por e-mail.

Publicado emAWSInfraestrutura como Código

Seja o primeiro a comentar

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *