O Redis usa tecnologia de pipeline + transações para obter um processamento de dados em lote eficiente

índice

Tecnologia de pipeline Redis

Exemplo de pipeline Redis

Vantagens da tecnologia de dutos

Transação Redis 

Exemplo de operação de transação

Comandos de transação do Redis

 Implementação Java do processamento em lote de envio de pipeline + transação

RedisCallback

API de chamada de pipeline


O Redis é um serviço TCP baseado em um modelo cliente-servidor e um protocolo de solicitação / resposta. Isso significa que, em circunstâncias normais, uma solicitação seguirá as seguintes etapas:

  • O cliente envia uma solicitação de consulta ao servidor e ouve o retorno do Socket, geralmente em modo de bloqueio, aguardando a resposta do servidor.
  • O servidor processa os comandos e retorna os resultados ao cliente.

Tecnologia de pipeline Redis

A tecnologia de pipeline do Redis pode continuar a enviar solicitações ao servidor quando o servidor não responde e, finalmente, ler todas as respostas do servidor de uma vez.

Exemplo de pipeline Redis

Para visualizar o pipeline do redis, basta iniciar a instância do redis e inserir o seguinte comando:

$(echo -en "PING\r\n SET w3ckey redis\r\nGET w3ckey\r\nINCR visitor\r\nINCR visitor\r\nINCR visitor\r\n"; sleep 10) | nc localhost 6379
 
+PONG
+OK
redis
:1
:2
:3

No exemplo acima, usamos o   comando PING para verificar se o serviço redis está disponível e, em seguida, definimos o valor de w3ckey para redis e, em seguida, obtemos o valor de w3ckey e aumentamos o visitante 3 vezes.

Nos resultados retornados, podemos ver que esses comandos são enviados ao serviço redis de uma só vez e, finalmente, lêem todas as respostas do servidor de uma vez


Vantagens da tecnologia de dutos

A vantagem mais significativa da tecnologia de pipeline é melhorar o desempenho do serviço redis.

No teste a seguir, usaremos o cliente Ruby da Redis para oferecer suporte aos recursos de tecnologia de pipeline e testar o efeito de melhoria de velocidade da tecnologia de pipeline. Exemplo:

require 'rubygems' 
require 'redis'
def bench(descr) 
start = Time.now 
yield 
puts "#{descr} #{Time.now-start} seconds" 
end
def without_pipelining 
r = Redis.new 
10000.times { 
        r.ping 
} 
end
def with_pipelining 
r = Redis.new 
r.pipelined { 
        10000.times { 
                r.ping 
        } 
} 
end
bench("without pipelining") { 
        without_pipelining 
} 
bench("with pipelining") { 
        with_pipelining 
}

Os dados da execução do script simples acima no sistema Mac OS X na rede local mostram que, depois que a operação de pipe é ativada, o atraso de ida e volta foi aprimorado para um nível muito baixo.

without pipelining 1.185238 seconds 
with pipelining 0.250783 seconds

Como você pode ver, após a abertura do pipeline, nossa velocidade e eficiência aumentaram 5 vezes.

Transação Redis 

As transações do Redis podem executar vários comandos ao mesmo tempo, com as duas garantias importantes a seguir:

  • A transação é uma operação isolada separada: todos os comandos na transação são serializados e executados sequencialmente. Durante a execução da transação, ela não será interrompida pelo pedido de comando enviado por outros clientes.
  • Uma transação é uma operação atômica: ou todos os comandos da transação são executados ou nenhum deles é executado.

Uma transação passará pelos três estágios a seguir, desde o início até a execução:

  • Comece o negócio.
  • Ordem para se juntar à equipe.
  • Realize negócios.

Exemplo de operação de transação

A seguir está um exemplo de transação. Primeiro, ele  inicia uma transação com  MULTI , depois enfileira vários comandos na transação e, por fim,  aciona a transação pelo  comando EXEC e executa todos os comandos na transação juntos:

redis 127.0.0.1:6379> MULTI
OK
 
redis 127.0.0.1:6379> SET book-name "Mastering C++ in 21 days"
QUEUED
 
redis 127.0.0.1:6379> GET book-name
QUEUED
 
redis 127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series"
QUEUED
 
redis 127.0.0.1:6379> SMEMBERS tag
QUEUED
 
redis 127.0.0.1:6379> EXEC
1) OK
2) "Mastering C++ in 21 days"
3) (integer) 3
4) 1) "Mastering Series"
   2) "C++"
   3) "Programming"

Comandos de transação do Redis

A tabela a seguir lista os comandos relevantes para transações de redis:

Número de série Comando e descrição
1 DISCARD  cancela a transação e abandona a execução de todos os comandos no bloco de transação.
2 EXEC  executa todos os comandos no bloco de transação.
3 MULTI  marca o início de um bloco de transação.
4 UNWATCH  cancela o monitoramento de todas as chaves pelo comando WATCH.
5 A tecla WATCH [tecla ...]  monitora uma (ou mais) chaves. Se esta (ou essas) chaves forem alteradas por outros comandos antes que a transação seja executada, a transação será interrompida.

 Implementação Java do processamento em lote de envio de pipeline + transação

RedisCallback

O método de retorno de chamada executado pelo pipeline redis é um pouco parecido com a interface de retorno de chamada multi-threaded Java, mas o retorno de chamada não precisa ser tratado por nós mesmos:

/**
 * @Copyright: 2019-2021
 * @FileName: MessageStatusRedisCallback .java
 * @Author: PJL
 * @Date: 2020/6/5 14:25
 * @Description: 通知公告状态redis指令回调类
 */
public class MessageStatusRedisCallback implements RedisCallback<Object> {

    Logger logger = LoggerUtils.getLogger(LoggerUtils.PatrolLoggerType.REDIS);

    List<MessageStatus> messageStatusList;

    /**
     * 构造方法
     *
     * @param messageStatusList
     */
    public MessageStatusRedisCallback(List<MessageStatus> messageStatusList) {
        this.messageStatusList = messageStatusList;
    }

    @Override
    public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
        // 验证指令执行方式
        if (ObjectUtils.isNotEmpty(messageStatusList)) {
            long s = System.currentTimeMillis();
            String json = null;
            try {
                // 开启REDIS事务
                redisConnection.multi();
                for (MessageStatus messageStatus : messageStatusList) {
                    json = JSONObject.toJSONString(messageStatus);
                    /* redisTemplate.opsForHash().put(Constants.MOBILE_HASH_MESSAGE_KEY, userId, Boolean.toString(hasMessage));*/
                    redisConnection.hSet(Constants.MOBILE_HASH_MESSAGE_KEY.getBytes(), messageStatus.getUserId().getBytes(), Boolean.toString(messageStatus.isHasMessage()).getBytes());
                }
                // 提交事务批量执行
                redisConnection.exec();
            } catch (Exception e) {
                // 回滚事务不执行
                redisConnection.discard();
                logger.error("【回滚事务不执行】出问题的用户通知公告状态JSON:{}", json);
            }
            long e = System.currentTimeMillis();
            logger.info("pipeline 批量执行用户通知公告 status命令完成....耗时:{} {}", (e - s), "ms");
        }
        return null;
    }
}

API de chamada de pipeline

Use o método fornecido pelo RedisTemplate para chamar:

/**
 * @Copyright: 2019-2021
 * @FileName: MessageStatusRedisPipelineService.java
 * @Author: PJL
 * @Date: 2020/6/5 14:19
 * @Description: 通知公告redis pipeline执行命令服务
 */
@Service
public class MessageStatusRedisPipelineService {

    @Qualifier("redisTemplateByLettuce")
    @Autowired
    RedisTemplate redisTemplate;

    /**
     * 设置用户通知公告状态记录缓存到REDIS
     *
     * @param messageStatusList
     */
    public void saveMessageStatusToRedis(List<MessageStatus> messageStatusList) {
        redisTemplate.executePipelined(new MessageStatusRedisCallback(messageStatusList));
    }
}

Até agora, realizamos uma operação em lote da tecnologia e assuntos relacionados ao pipeline do Opportunity Pipeline.

Leitura de referência:

Acho que você gosta

Origin blog.csdn.net/boonya/article/details/108627519
Recomendado
Clasificación