https://zhuanlan.zhihu.com/p/58608323html
Redis 的工做過程是基於 請求/響應 模式的。正常狀況下,客戶端發送一個命令,等待 Redis 應答;Redis 接收到命令,處理後應答。請求發出到響應的時間叫作往返時間,即 RTT(Round Time Trip)。在這種狀況下,若是須要執行大量的命令,就須要等待上一條命令應答後再執行。這中間不單單多了許屢次 RTT,並且還頻繁的調用系統 IO,發送網絡請求。爲了提高效率,pipeline 出現了,它容許客戶端能夠一次發送多條命令,而不等待上一條命令執行的結果。java
客戶端首先將執行的命令寫入到緩衝區中,最後再一次性發送 Redis。可是有一種狀況就是,緩衝區的大小是有限制的:若是命令數據太大,可能會有屢次發送的過程,可是仍不會處理 Redis 的應答。web
要支持 pipeline,既要服務端的支持,也要客戶端支持。對於服務端來講,所須要的是可以處理一個客戶端經過同一個 TCP 鏈接發來的多個命令。能夠理解爲,這裏將多個命令切分,和處理單個命令同樣。對於客戶端,則是要將多個命令緩存起來,緩衝區滿了就發送,而後再寫緩衝,最後才處理 Redis 的應答。redis
基於 SpringBoot 的自動配置,在使用 Redis 時只須要在 pom 文件中給出 spring-boot-starter-data-redis 依賴,就能夠直接使用 Spring Data Redis。關於 Redis pipeline 的使用方法,能夠閱讀 Spring Data Redis 給出的解釋。下面,我給出一個簡單的例子:spring
import com.imooc.ad.Application; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.StringRedisConnection; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.core.SessionCallback; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.test.context.junit4.SpringRunner; /** * <h1>Redis Pipeline 功能測試用例</h1> * 參考: https://docs.spring.io/spring-data/redis/docs/1.8.1.RELEASE/reference/html/#redis:template * Created by Qinyi. */ @RunWith(SpringRunner.class) @SpringBootTest(classes = {Application.class}, webEnvironment = SpringBootTest.WebEnvironment.NONE) public class RedisPipelineTest { /** 注入 StringRedisTemplate, 使用默認配置 */ @Autowired private StringRedisTemplate stringRedisTemplate; @Test @SuppressWarnings("all") public void testExecutePipelined() { // 使用 RedisCallback 把命令放在 pipeline 中 RedisCallback<Object> redisCallback = connection -> { StringRedisConnection stringRedisConn = (StringRedisConnection) connection; for (int i = 0; i != 10; ++i) { stringRedisConn.set(String.valueOf(i), String.valueOf(i)); } return null; // 這裏必需要返回 null }; // 使用 SessionCallback 把命令放在 pipeline SessionCallback<Object> sessionCallback = new SessionCallback<Object>() { @Override public Object execute(RedisOperations operations) throws DataAccessException { operations.opsForValue().set("name", "qinyi"); operations.opsForValue().set("gender", "male"); operations.opsForValue().set("age", "19"); return null; } }; System.out.println(stringRedisTemplate.executePipelined(redisCallback)); System.out.println(stringRedisTemplate.executePipelined(sessionCallback)); } }