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();
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章