Todos os produtos
Search
Central de documentação

Tair (Redis® OSS-Compatible):Implementar bloqueio otimista de alto desempenho com TairString

Última atualização: Jun 26, 2026

Quando vários clientes leem e atualizam simultaneamente a mesma chave, a última gravação substitui silenciosamente todas as anteriores — uma condição de corrida conhecida como "última gravação vence". O TairString, tipo de dado de string estendida (exString) no Tair (Enterprise Edition), possui um número de versão integrado que torna o bloqueio otimista uma operação nativa. Esse recurso permite detectar e repetir gravações conflitantes sem locks ou transações externas.

Como funciona o bloqueio otimista com número de versão

O bloqueio otimista associa um número de versão a cada chave. Ao ler uma chave, você também obtém sua versão. Durante a gravação, forneça a versão lida anteriormente. Se outro cliente gravou na chave nesse intervalo, o servidor incrementou a versão e ela não corresponde mais à sua. Nesse caso, o sistema rejeita a gravação em vez de aplicá-la silenciosamente. Repita a operação com o valor e a versão atualizados.

O TairString resolve esse problema nativamente: strings nativas do Redis consistem apenas em chaves e valores, sem nenhum mecanismo para detectar se uma chave mudou entre uma leitura e uma gravação.

A condição de corrida: por que a última gravação vence causa perda de dados

O diagrama a seguir ilustra uma condição de corrida típica.

Concurrent write race condition

Considere um contador que dois clientes incrementam simultaneamente. Ambos leem o valor atual (10), calculam independentemente 11 e gravam o resultado. O valor final é 11 em vez do esperado 12 — um incremento se perde silenciosamente. O mesmo padrão se aplica a qualquer chave compartilhada:

  1. key_1 inicia com o valor hello.

  2. A Aplicação 1 lê hello.

  3. A Aplicação 2 lê hello.

  4. A Aplicação 1 grava world em key_1.

  5. A Aplicação 2 grava universe em key_1.

A Aplicação 1 espera que key_1 seja world, mas o valor real é universe. Para evitar isso, a sequência de leitura-modificação-gravação deve ser atômica — exatamente o que o mecanismo de número de versão do TairString oferece.

Comandos do TairString para bloqueio otimista

Os TairStrings são compostos por chaves, valores e números de versão. O TairString integra todos os recursos de string do Redis, exceto operações de bits.

Nota

Os comandos do TairString e os comandos de string nativos do Redis não são intercambiáveis.

Comando

Finalidade

Comportamento

EXSET

Crie uma chave TairString

O número de versão padrão é 1

EXGET

Consultar uma chave TairString

Retorna tanto o value quanto a version

EXSET com versão

Atualize com verificação de versão

Tem êxito e incrementa a versão em 1; falha com ERR update version is stale se a versão não corresponder

EXCAS

Compare-And-Swap em uma única chamada

Verifica a versão e aplica a gravação atomicamente; em caso de falha, retorna o erro, o valor atual e a versão atual em uma única resposta

Para obter a referência completa de comandos, consulte exString.

Implementar bloqueio otimista com EXGET e EXSET

O padrão básico de bloqueio otimista utiliza um loop de repetição: leia o valor e a versão atuais com EXGET, calcule o novo valor e grave com EXSET, passando a versão lida. Se ocorrer uma gravação concorrente entre sua leitura e gravação, a verificação de versão falhará e o loop repetirá a operação.

while(true){
    {value, version} = EXGET(key);      // Retrieve the value and version number of the key.
    value2 = update(...);               // Save the new value as value 2.
    ret = EXSET(key, value2, version);  // Update the key and assign the return value to the ret variable.
    if(ret == OK)
       break;                           // If the return value is OK, the update is successful and the while loop exits.
    else if (ret.contains("version is stale"))
       continue;                        // If the return value contains the "version is stale" error message, the update fails and the while loop is repeated.
}

Isso garante que, se qualquer outro cliente atualizou a chave após seu EXGET, seu EXSET falhará em vez de substituir silenciosamente a alteração. Cada iteração desse loop requer duas viagens de ida e volta ao Tair: um EXGET para ler o valor e a versão atuais e um EXSET para tentar a gravação.

Nota
  • Quando uma chave TairString é excluída e recriada com o mesmo nome, a nova chave começa na versão 1. Ela não herda a versão anterior.

  • Para ignorar a verificação de versão e forçar a substituição de um valor, use a opção ABS com EXSET. Consulte EXSET para obter detalhes.

Reduzir E/S com EXCAS

O loop EXGET seguido de EXSET exige duas operações de E/S por ciclo de repetição. O comando EXCAS (Compare-And-Swap) reduz isso para uma única operação de E/S por ciclo — uma melhoria significativa sob alta concorrência.

O EXCAS verifica atomicamente a versão e aplica a gravação em uma única viagem de ida e volta. Em caso de falha, ele retorna os três itens a seguir em uma única resposta:

  • "ERR update version is stale"

  • O valor atual

  • O número de versão atual

Como o estado atual está incluído na resposta de falha, o próximo ciclo de repetição pode começar imediatamente — nenhuma chamada extra de EXGET é necessária.

while(true){
    {ret, value, version} = excas(key, new_value, old_version)    // Use the CAS command to replace the original value with a new value.
    if(ret == OK)
       break;                                                     // If the return value is OK, the update is successful and the while loop exits.
    else (if ret.contains("update version is stale"))            // If the return value contains the "update version is stale" error message, the update fails. The values of the value and old_version variables are updated.
       update(value);
       old_version = version;
 }

Tópicos relacionados