Resumo

  • O RFC 1045, de David Cheriton, descreveu em fevereiro de 1988 o VMTP, transporte experimental para transações de pedido e resposta. Cliente, número de transação de 32 bits e contador de encaminhamento identificavam a operação; o servidor mantinha estado para barrar duplicatas.
  • Quando a resposta era marcada como idempotente, o cliente reenviava o pedido perdido e o servidor produzia outra resposta ao refazer a operação. Uma resposta que exigia preservação era copiada ou retida até confirmação. Pedir a hora outra vez podia devolver uma informação mais atual.

Um botão de “tentar novamente” parece inofensivo até a pergunta sobre o primeiro pedido: ele chegou a ser executado? O RFC 1045 tratou esse problema como trabalho de protocolo. David Cheriton projetou o Versatile Message Transaction Protocol para trocas como chamadas remotas de procedimento, sobre um serviço de datagramas capaz de perder pacotes. O pedido podia ter sido atendido enquanto a resposta sumia no caminho. Na segunda visita, o servidor precisava reconhecer a ficha antes de atender de novo.

A ficha tinha três coordenadas dentro de um domínio de entidades: Client, Transaction e ForwardCount. O identificador Transaction usava 32 bits, começava com valor aleatório quando o cliente era criado e normalmente avançava após cada transação. ForwardCount tinha quatro bits e ficava em zero até um encaminhamento. O servidor guardava um registro de estado por cliente e descartava como duplicata outro pedido com a mesma combinação. A numeração servia para evitar que o mesmo serviço fosse chamado duas vezes por acidente.

O arquivo de estado também tinha prazo. Em geral o servidor o conservava algum tempo depois de responder, protegendo a aplicação de cópias atrasadas do pedido. Se o registro não estivesse lá, o RFC oferecia caminhos: consultar o módulo de gestão do cliente com Probe; inferir que o pedido era novo se a retenção cobrisse a vida máxima dos pacotes mais a janela de retries e o servidor não tivesse reiniciado; ou repetir uma operação comprovadamente segura de refazer. Nada de mágica no “de novo”: era preciso saber por quanto tempo o passado ainda poderia chegar.

Na primeira trilha, a resposta recebia a marca de idempotência. O VMTP dispensava a cópia antiga. O cliente retransmitia o pedido e o servidor entregava a última transação novamente à aplicação, que refazia o trabalho e gerava resposta nova. Pedidos mais antigos daquele cliente eram descartados. Cheriton escolheu o relógio para explicar por quê: ao perguntar a hora atual depois da perda, uma nova consulta vale mais do que um papel meticulosamente guardado com a hora de antes. O arquivista perde para o ponteiro.

Na segunda trilha, o resultado precisava continuar sendo o mesmo. O módulo guardava a resposta, fisicamente ou por cópia na escrita, ou impedia o servidor de prosseguir até a confirmação. O custo passava a ser memória ou espera. A leitura do relógio aceita outra execução; uma atualização de conta ou registro exige cuidado com a repetição. A etiqueta no pacote só funciona quando quem conhece a operação sabe o que ela faz no mundo.

O VMTP economizava também na retransmissão comum. Com pouca perda, podia mandar só o bloco de controle e deixar o destinatário pedir os trechos de dados ausentes. Um pedido posterior podia encerrar respostas anteriores na contabilidade do transporte. Assim, os três gastos apareciam juntos: guardar bytes, transmitir bytes e executar a aplicação outra vez. O protocolo não escolhia um único preço para todo tipo de trabalho.

Há humor na ideia de um servidor guardando perfeitamente uma resposta sobre a hora e, por isso mesmo, entregando uma resposta pior. A história fica séria quando o serviço altera alguma coisa que não pode ser alterada duas vezes. O RFC organizou identificadores, memória e descarte de pedidos antigos ao redor dessa decisão. A aplicação ainda precisava conhecer o próprio trabalho: um pedido repetido só é bom negócio quando a operação tolera a segunda execução.