REL04-BP04 Garantir a idempotência das operações de mutação - Pilar Confiabilidade

REL04-BP04 Garantir a idempotência das operações de mutação

Um serviço idempotente garante que cada solicitação seja processada exatamente uma vez, de modo que fazer várias solicitações idênticas tenha o mesmo efeito que uma única solicitação. Isso facilita para um cliente implementar novas tentativas sem o receio de que uma solicitação seja processada erroneamente várias vezes. Para fazer isso, os clientes podem emitir solicitações de API com um token de idempotência, que é usado sempre que a solicitação é repetida. Uma API de serviço idempotente usa o token para retornar uma resposta idêntica à resposta que foi retornada na primeira vez que a solicitação foi concluída, mesmo se o estado subjacente do sistema tiver mudado.

Em um sistema distribuído, é relativamente fácil executar uma ação no máximo uma vez (o cliente faz apenas uma solicitação) ou pelo menos uma vez (continue solicitando até o cliente receber a confirmação do sucesso). Mas é difícil garantir que uma ação seja realizada exatamente uma vez, de modo que fazer várias solicitações idênticas tem o mesmo efeito que fazer uma única solicitação. Usando tokens de idempotência em APIs, os serviços podem receber uma solicitação mutante uma vez ou mais sem necessidade de criar registros duplicados nem efeitos colaterais.

Resultado desejado: você tem uma abordagem consistente, bem documentada e amplamente adotada para garantir a idempotência em todos os componentes e serviços.

Práticas comuns que devem ser evitadas:

  • Aplicar a idempotência indiscriminadamente, mesmo quando não é necessária.

  • Introduzir uma lógica excessivamente complexa para implementar a idempotência.

  • Usar carimbos de data/hora como chaves para a idempotência. Isso pode causar imprecisões devido à distorção do relógio ou devido a vários clientes que usam os mesmos carimbos de data/hora para aplicar as alterações.

  • Armazenar cargas úteis inteiras para fins de idempotência. Nessa abordagem, você salva cargas úteis de dados completas para cada solicitação e as substitui a cada nova solicitação. Isso pode degradar o desempenho e afetar a escalabilidade.

  • Gerar chaves de maneira inconsistente nos serviços. Sem chaves consistentes, os serviços podem não reconhecer solicitações duplicadas, o que gera resultados indesejados.

Benefícios de implementar essa prática recomendada:

  • Maior escalabilidade: o sistema pode lidar com novas tentativas e solicitações duplicadas sem precisar executar lógica adicional ou gerenciamento complexo de estados.

  • Confiabilidade aprimorada: a idempotência ajuda os serviços a lidar com várias solicitações idênticas de maneira consistente, o que reduz o risco de efeitos colaterais indesejados ou registros duplicados. Isso é especialmente crucial em sistemas distribuídos, onde falhas e novas tentativas de rede são comuns.

  • Consistência de dados aprimorada: como a mesma solicitação produz a mesma resposta, a idempotência ajuda a manter a consistência dos dados em sistemas distribuídos. Isso é essencial para manter a integridade das transações e operações.

  • Tratamento de erros: os tokens de idempotência tornam o tratamento de erros mais simples. Se um cliente não receber uma resposta devido a um problema, ele poderá reenviar a solicitação com segurança com o mesmo token de idempotência.

  • Transparência operacional: a idempotência permite um melhor monitoramento e registro. Os serviços podem registrar solicitações com seus tokens de idempotência, o que facilita o rastreamento e a depuração de problemas.

  • Contrato de API simplificado: ele pode simplificar o contrato entre os sistemas do lado do cliente e do servidor e reduzir o medo de processamento incorreto de dados.

Nível de risco exposto se esta prática recomendada não for estabelecida: Médio

Orientação para implementação

Em um sistema distribuído, é relativamente fácil executar uma ação no máximo uma vez (o cliente faz apenas uma solicitação) ou pelo menos uma vez (o cliente continua solicitando até a confirmação do sucesso). No entanto, é difícil implementar um comportamento do tipo exatamente uma vez. Para conseguir isso, os clientes devem gerar e fornecer um token de idempotência para cada solicitação.

Ao usar tokens de idempotência, um serviço pode distinguir entre solicitações novas e repetidas. Quando um serviço recebe uma solicitação com um token de idempotência, ele verifica se o token já foi usado. Se o token tiver sido usado, o serviço recuperará e retornará a resposta armazenada. Se o token for novo, o serviço processará a solicitação, armazenará a resposta junto com o token e, em seguida, retornará a resposta. Esse mecanismo torna todas as respostas idempotentes, o que aumenta a confiabilidade e a consistência do sistema distribuído.

A idempotência também é um comportamento importante das arquiteturas orientadas por eventos. Essas arquiteturas geralmente são apoiadas por uma fila de mensagens, como Amazon SQS, Amazon MQ, Amazon Kinesis Streams ou Amazon Managed Streaming for Apache Kafka (MSK). Em algumas circunstâncias, uma mensagem publicada somente uma vez pode ser entregue acidentalmente mais de uma vez. Quando um publicador gera e inclui tokens de idempotência nas mensagens, ele solicita que o processamento de qualquer mensagem duplicada recebida não resulte em uma ação repetida para a mesma mensagem. Os consumidores devem acompanhar cada token recebido e ignorar as mensagens que contêm tokens duplicados.

Os serviços e os consumidores também devem passar o token de idempotência recebido para qualquer serviço downstream que ele chame. Cada serviço downstream na cadeia de processamento é igualmente responsável por garantir que a idempotência seja implementada para evitar o efeito colateral de processar uma mensagem mais de uma vez.

Etapas de implementação

  1. Identifique operações idempotentes

    Determine quais operações exigem idempotência. Elas geralmente incluem métodos HTTP POST, PUT e DELETE e operações de inserção, atualização ou exclusão do banco de dados. Operações que não alteram o estado, como consultas somente leitura, geralmente não exigem idempotência, a menos que tenham efeitos colaterais.

  2. Usar identificadores exclusivos

    Inclua um token exclusivo em cada solicitação de operação de idempotência enviada pelo remetente, diretamente na solicitação ou como parte dos metadados (por exemplo, um cabeçalho HTTP). Isso permite que o destinatário reconheça e manipule solicitações ou operações duplicadas. Os identificadores comumente usados para tokens incluem Universally Unique Identifiers (UUIDs) e K-Sortable Unique Identifiers (KSUIDs).

  3. Rastreie e gerencie o estado

    Mantenha o estado de cada operação ou solicitação na workload. Isso pode ser feito armazenando o token de idempotência e o estado correspondente (como pendente, concluído ou com falha) em um banco de dados, cache ou outro armazenamento persistente. Essas informações de estado permitem que a workload identifique e processe solicitações ou operações duplicadas.

    Mantenha a consistência e a atomicidade usando mecanismos de controle de concorrência apropriados, se necessário, como bloqueios, transações ou controles de simultaneidade otimistas. Isso inclui o processo de registrar o token de idempotência e executar todas as operações de mutação associadas ao atendimento da solicitação. Isso ajuda a evitar condições de corrida e verifica se as operações de idempotência são executadas corretamente.

    Remova regularmente os tokens de idempotência antigos do datastore para gerenciar o armazenamento e o desempenho. Se o sistema de armazenamento oferecer suporte a isso, considere usar carimbos de data/hora de expiração para os dados (geralmente conhecidos como valores de vida útil, ou TTL). A probabilidade de reutilização do token de idempotência diminui com o tempo.

    As opções de armazenamento da AWS normalmente usadas para armazenar tokens de idempotência e estados relacionados incluem:

    • Amazon DynamoDB: O DynamoDB é um serviço de banco de dados NoSQL que fornece desempenho de baixa latência e alta disponibilidade, o que o torna adequado para o armazenamento de dados relacionados à idempotência. O modelo de dados de documentos e valores-chave do DynamoDB permite o armazenamento e a recuperação eficientes dos tokens de idempotência e das informações de estado associadas. O DynamoDB também pode expirar automaticamente os tokens de idempotência se a aplicação definir um valor de TTL ao inseri-los.

    • Amazon ElastiCache: o ElastiCache pode armazenar tokens de idempotência com alto throughput, baixa latência e baixo custo. Tanto o ElastiCache (Redis) quanto o ElastiCache (Memcached) também podem expirar automaticamente os tokens de idempotência se a aplicação definir um valor de TTL ao inseri-los.

    • Amazon Relational Database Service (RDS): você pode usar o Amazon RDS para armazenar tokens de idempotência e informações de estado relacionadas, especialmente se a aplicação já usa um banco de dados relacional para outros fins.

    • Amazon Simple Storage Service (S3): o Amazon S3 é um serviço de armazenamento de objetos altamente escalável e durável que pode ser usado para armazenar tokens de idempotência e metadados relacionados. Os recursos de versionamento do S3 podem ser particularmente úteis para a manutenção do estado das operações de idempotência. A escolha do serviço de armazenamento geralmente depende de fatores como o volume de dados relacionados à idempotência, as características de desempenho necessárias, a necessidade de durabilidade e disponibilidade e como o mecanismo de idempotência se integra à arquitetura geral da workload.

  4. Implemente operações de idempotência

    Projete os componentes de API e workload para serem idempotentes. Incorpore verificações de idempotência nos componentes de workload. Antes de processar uma solicitação ou realizar uma operação, verifique se o identificador exclusivo já foi processado. Se já tiver sido processado, retorne o resultado anterior em vez de executar a operação novamente. Por exemplo, se um cliente enviar uma solicitação para criar um usuário, verifique se já existe um usuário com o mesmo identificador exclusivo. Se o usuário existir, deverão ser retornadas as informações do usuário existente em vez de criar outro. Da mesma forma, se um consumidor da fila receber uma mensagem com um token de idempotência duplicado, ele deverá ignorá-la.

    Crie conjuntos de testes abrangentes que validem a idempotência das solicitações. Eles devem abranger uma ampla variedade de cenários, como solicitações bem-sucedidas, solicitações malsucedidas e solicitações duplicadas.

    Se a workload utilizar funções do AWS Lambda, considere o Powertools para AWS Lambda. O Powertools for AWS Lambda é um kit de ferramentas para desenvolvedores para implementar as práticas recomendadas da tecnologia sem servidor e aumentar a velocidade do desenvolvedor ao trabalhar com funções do AWS Lambda. Em particular, ele fornece um utilitário para converter funções do Lambda em operações de idempotência que podem ser repetidas com segurança.

  5. Comunique a idempotência com clareza

    Documente a API e os componentes da workload para comunicar claramente a natureza de idempotência das operações. Isso ajuda os clientes a entender o comportamento esperado e a interagir com a workload de forma confiável.

  6. Monitore e audite

    Implemente mecanismos de monitoramento e auditoria para detectar quaisquer problemas relacionados à idempotência das respostas, como variações inesperadas de respostas ou tratamento excessivo de solicitações duplicadas. Isso pode ajudar você a detectar e investigar quaisquer problemas ou comportamentos inesperados na workload.

Recursos

Práticas recomendadas relacionadas:

Documentos relacionados:

Vídeos relacionados:

Ferramentas relacionadas: