Todos os produtos
Search
Central de documentação

Tair (Redis® OSS-Compatible):Implementar locks distribuídos de alta performance com TairString

Última atualização: Jun 26, 2026

Quando vários hosts competem por um recurso compartilhado, locks distribuídos evitam corrupção de dados e falhas lógicas. Este tópico explica o funcionamento dos locks distribuídos, como implementá-los no ApsaraDB for Redis e Tair (Enterprise Edition) e como manter a consistência do lock após um failover. Os comandos CAD e CAS, específicos do Tair, eliminam a necessidade de scripts Lua exigidos pelo Redis padrão, reduzem a complexidade de implementação e aumentam o throughput.

Quando usar locks distribuídos

Cenários de concorrência diferentes exigem mecanismos de coordenação distintos:

Cenário

Mecanismo

Várias threads no mesmo processo

Mutex ou lock de leitura/escrita

Vários processos no mesmo host

Semáforo, pipeline ou memória compartilhada

Vários hosts em um sistema distribuído

Lock distribuído

Locks distribuídos são mecanismos de exclusão mútua com escopo global. Use-os para coordenar o acesso a recursos compartilhados entre hosts e prevenir falhas lógicas causadas por contenção de recursos.

Propriedades de um lock distribuído bem implementado

Um lock distribuído deve atender a três propriedades. Cada abordagem de implementação neste tópico é avaliada com base nesses critérios:

  • Exclusividade mútua: Em qualquer momento, apenas um cliente detém o lock.

  • Livre de deadlocks: Os locks usam um mecanismo baseado em concessão (lease). Se um cliente sofrer uma exceção após adquirir o lock, este expira automaticamente e evita o bloqueio indefinido do recurso.

  • Consistência: Após um switchover de alta disponibilidade (HA), o estado do lock deve permanecer intacto. Switchovers podem ser acionados por erros externos (falhas de hardware, exceções de rede) ou internos (consultas lentas, defeitos do sistema). Quando ocorre um switchover, um nó réplica é promovido a novo nó mestre.

Implementar locks distribuídos no Redis

Os métodos nesta seção aplicam-se tanto ao ApsaraDB for Redis quanto ao Redis Open-Source Edition.

Adquirir um lock

Execute o comando SET com as opções NX e EX para adquirir um lock atomicamente:

SET resource_1 random_value NX EX 5

Parâmetro

Descrição

resource_1

Chave do lock. Se esta chave existir, o recurso estará bloqueado e inacessível para outros clientes.

random_value

String aleatória única entre todos os clientes. Usada para verificar a propriedade antes de liberar o lock.

EX

Período de validade do lock em segundos. Use PX para precisão em milissegundos.

NX

Cancela a operação SET se a chave já existir.

Neste exemplo, o lock expira após 5 segundos caso não seja liberado explicitamente. A expiração previne deadlocks: se o cliente falhar, o sistema recupera o lock automaticamente.

Liberar um lock

Executar DEL resource_1 diretamente não é seguro. Considere este cenário de falha:

  1. No instante t1, a aplicação 1 adquire resource_1 com uma concessão de 3 segundos.

  2. A aplicação 1 trava por mais de 3 segundos. A chave expira no instante t2 e o lock é liberado automaticamente.

  3. No instante t3, a aplicação 2 adquire o lock.

  4. A aplicação 1 retoma no instante t4 e executa DEL resource_1, liberando acidentalmente um lock que não lhe pertence mais.

Somente o cliente que definiu o lock deve liberá-lo. Use o script Lua a seguir para verifique a propriedade e exclua atomicamente:

if redis.call("get", KEYS[1]) == ARGV[1] then
    return redis.call("del", KEYS[1])
else
    return 0
end

Renovar um lock

Caso o cliente não consiga concluir seu trabalho dentro do período de concessão, ele deve renovar o lock. Apenas o cliente que defina o lock pode renová-lo:

if redis.call("get", KEYS[1]) == ARGV[1] then
    return redis.call("expire", KEYS[1], ARGV[2])
else
    return 0
end

Implementar locks distribuídos no Tair

Instâncias suportadas: Instâncias baseadas em DRAM do Tair e instâncias otimizadas para memória persistente.

Nessas instâncias, o tipo de dado TairString fornece os comandos CAD e CAS. Esses comandos substituem os scripts Lua acima por operações atômicas únicas, reduzem a complexidade de implementação e melhoram o throughput.

Adquirir um lock

A aquisição do lock é idêntica à abordagem do Redis:

SET resource_1 random_value NX EX 5

Liberar um lock

O comando CAD (Compare-And-Delete) verifica a propriedade e exclui a chave em uma única operação atômica, substituindo totalmente o script Lua:

CAD resource_1 my_random_value

Isso equivale a: se GET(resource_1) == my_random_value, execute DEL(resource_1).

Renovar um lock

O comando CAS (Compare-And-Swap) estende a expiração do lock em uma única operação atômica, substituindo totalmente o script Lua:

CAS resource_1 my_random_value my_random_value EX 10
O comando CAS não verifica se o novo valor é igual ao valor original. Passe o mesmo valor aleatório tanto para o campo de valor antigo quanto para o novo para preservar a identidade do lock enquanto estende a concessão.

Código de exemplo com Jedis

Os exemplos Java a seguir mostram um ciclo de vida completo de lock usando Jedis. Todas as três operações — adquirir, liberar e renovar — usam a mesma resourceKey e o mesmo randomValue.

Defina os comandos CAS e CAD

enum TairCommand implements ProtocolCommand {
    CAD("CAD"), CAS("CAS");

    private final byte[] raw;

    TairCommand(String alt) {
        raw = SafeEncoder.encode(alt);
    }

    @Override
    public byte[] getRaw() {
        return raw;
    }
}

Adquirir um lock

public boolean acquireDistributedLock(Jedis jedis, String resourceKey, String randomValue, int expireTime) {
    SetParams setParams = new SetParams();
    setParams.nx().ex(expireTime);
    String result = jedis.set(resourceKey, randomValue, setParams);
    return "OK".equals(result);
}

Liberar um lock

public boolean releaseDistributedLock(Jedis jedis, String resourceKey, String randomValue) {
    jedis.getClient().sendCommand(TairCommand.CAD, resourceKey, randomValue);
    Long ret = jedis.getClient().getIntegerReply();
    return 1 == ret;
}

Renovar um lock

public boolean renewDistributedLock(Jedis jedis, String resourceKey, String randomValue, int expireTime) {
    jedis.getClient().sendCommand(TairCommand.CAS, resourceKey, randomValue, randomValue, "EX", String.valueOf(expireTime));
    Long ret = jedis.getClient().getIntegerReply();
    return 1 == ret;
}

Garantir a consistência do lock após um failover

A replicação de mestre para réplica é assíncrona. Se um nó mestre falhar após gravar um lock, mas antes da replicação da gravação, a réplica promovida não terá registro desse lock. Dois clientes poderiam então manter o mesmo lock simultaneamente, violando a propriedade de consistência.

Três abordagens mitigam esse risco:

Abordagem

Custo

Limitações

Ideal para

Algoritmo Redlock

Alto (requer múltiplas instâncias)

Incompatível com instâncias cluster ou mestre-réplica padrão; aquisição de lock mais lenta

Requisitos máximos de tolerância a falhas

Comando WAIT

Baixo

Não garante consistência se ocorrer um switchover antes do retorno do WAIT

Implantações padrão onde o custo é relevante

Replicação semissíncrona do Tair

Integrado

Regride para assíncrono se uma réplica falhar

Cargas de trabalho de alta concorrência em instâncias Tair

Usar o algoritmo Redlock

O algoritmo Redlock, proposto pelos fundadores do projeto open source Redis, reduz a probabilidade de perda de lock distribuindo os locks entre N instâncias Redis independentes. Uma única instância mestre-réplica pode perder um lock com probabilidade de k% durante um switchover. Com o Redlock, a probabilidade de todas as N instâncias perderem seus locks simultaneamente cai para (k%)^N.

O algoritmo exige que os locks tenham sucesso em M de N nós, onde 1 < M ≤ N. Não é necessário que todos os N locks tenham sucesso simultaneamente.

Compensações do Redlock:

  • A aquisição e liberação de locks são mais lentas devido ao envolvimento de múltiplas instâncias.

  • Requer várias instâncias independentes do ApsaraDB for Redis ou Redis autogerenciado, aumentando os custos de infraestrutura.

  • Incompatível com instâncias cluster e instâncias mestre-réplica padrão.

Usar o comando WAIT

O comando WAIT bloqueia o cliente atual até que todos os comandos de escrita anteriores sejam replicados para um número especificado de nós réplica, ou até que o tempo limite (em milissegundos) expire. O comando WAIT é muito mais econômico que o algoritmo Redlock.

Após adquirir um lock, execute WAIT para confirme a replicação:

SET resource_1 random_value NX EX 5
WAIT 1 5000

Neste exemplo, o período de tempo limite é de 5.000 milissegundos. Se WAIT retornar 1, os dados estarão sincronizados entre o nó mestre e os nós réplica, garantindo a consistência. No entanto, se um switchover de HA for acionado antes que WAIT retorne uma resposta bem-sucedida, os dados podem ser perdidos — o valor de retorno indica apenas uma possível falha de sincronização. Após WAIT retornar um erro, readquira o lock ou verifique seu estado antes de prosseguir.

Notas de uso:

  • WAIT bloqueia apenas o cliente que o envia; outros clientes não são afetados.

  • Não execute WAIT antes de liberar um lock. Locks distribuídos são mutuamente exclusivos por design, portanto, uma liberação ligeiramente atrasada não causa falhas lógicas.

Usar o Tair

As instâncias baseadas em DRAM do Tair resolvem a consistência de locks no nível de infraestrutura:

  • Performance 3x superior: Instâncias baseadas em DRAM do Tair oferecem três vezes mais performance que o Redis open source, sustentando cargas de trabalho de locks com alta concorrência sem interrupção de serviço.

  • Replicação semissíncrona: Uma resposta de sucesso é retornada somente após a gravação ser confirmada no nó mestre e replicada para pelo menos um nó réplica. Isso evita a perda de locks após um switchover.

A replicação semissíncrona regride para replicação assíncrona se um nó réplica falhar ou se ocorrer uma exceção de rede durante a sincronização.

Os comandos CAD e CAS reduzem ainda mais a complexidade de implementação em comparação aos scripts Lua e eliminam a necessidade de múltiplas instâncias independentes exigidas pelo Redlock.