Redis事务、管道测试

  • PipeLine图解,在本地缓存,一次性发送

IMPORTANT NOTE: While the client sends commands using pipelining, the server will be forced to queue the replies, using memory. So if you need to send a lot of commands with pipelining, it is better to send them as batches having a reasonable number, for instance 10k commands, read the replies, and then send another 10k commands again, and so forth. The speed will be nearly the same, but the additional memory used will be at max the amount needed to queue the replies for this 10k commands. https://redis.io/topics/pipelining

  • Transaction
    所有的指令在 exec 之前不执行,而是缓存在服务器的一个事务队列中,服务器一旦收到 exec 指令,才开执行整个事务队列,执行完毕后一次性返回所有指令的运行结果。因为 Redis 的单线程特性,它不用担心自己在执行队列的时候被其它指令打搅,可以保证他们能得到的「原子性」执行.

  • Maven

<dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.10</version>
</dependency>
<dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.4.2</version>
</dependency>
<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
</dependency>
  • 测试脚本
package com.example.redis;

import org.apache.commons.lang3.time.StopWatch;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Transaction;

import java.util.concurrent.TimeUnit;

public class JedisTest {

    private static final String HOST = "localhost";

    private Jedis jedis;

    @Before
    public void setUp() {
        jedis = new Jedis(HOST);
    }

    @Test
    public void testGeneralSet() {

        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        for (int i = 0; i < 10000; i++) {
            jedis.set("key0:" + i, String.valueOf(i));
        }
        stopWatch.stop();
        System.out.println("普通的操作10000次字符串数据类型set写入,耗时:" + stopWatch.getTime(TimeUnit.MILLISECONDS) + "毫秒");
    }

    /**
     * 事务操作
     */
    @Test
    public void testTransaction() {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        Transaction transaction = jedis.multi();

        for (int i = 0; i < 10000; i++) {
            transaction.set("key3:" + i, String.valueOf(i));
        }
        transaction.exec();

        stopWatch.stop();
        System.out.println("事务操作10000次字符串数据类型set写入,耗时:" + stopWatch.getTime(TimeUnit.MILLISECONDS) + "毫秒");
    }

    /**
     * Pipeline批量提交
     * 最主要是为了控制网络开销
     */
    @Test
    public void testPipeline() {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        Pipeline pipeline = jedis.pipelined();
        for (int i = 0; i < 10000; i++) {
            pipeline.set("key1:" + i, String.valueOf(i));
        }

        //表示一次性的异步发送到redis,不关注执行结果。
        pipeline.sync();
        //程序会阻塞,等到所有命令执行完之后返回一个List集合
//        pipeline.syncAndReturnAll();
        stopWatch.stop();
        System.out.println("pipeline操作10000次字符串数据类型set写入,耗时:" + stopWatch.getTime(TimeUnit.MILLISECONDS) + "毫秒");
    }

    /**
     *  Redis 事务在发送每个指令到事务缓存队列时都要经过一次网络读写,当一个事务内部的指令较多时,需要的网络 IO 时间也会线性增长。
     *  所以通常 Redis 的客户端在执行事务时都会结合 pipeline 一起使用,这样可以将多次 IO 操作压缩为单次 IO 操作
     */
    @Test
    public void testPipelineWithTransaction() {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        Pipeline pipeline = jedis.pipelined();

        pipeline.multi();
        for (int i = 0; i < 10000; i++) {
            pipeline.set("key2:" + i, String.valueOf(i));
        }
        pipeline.exec();

        //表示一次性的异步发送到redis,不关注执行结果。
        pipeline.sync();
        stopWatch.stop();
        System.out.println("带事务的pipeline操作10000次字符串数据类型set写入,耗时:" + stopWatch.getTime(TimeUnit.MILLISECONDS) + "毫秒");
    }

    @After
    public void tearDown()  {
        jedis.close();
    }
}

posted @ 2020-09-27 16:05  zendwang  阅读(161)  评论(0编辑  收藏  举报