等待 Redis 應答

https://zhuanlan.zhihu.com/p/58608323html

 

mq消息合併:因爲mq請求發出到響應的時間,即往返時間, RTT(Round Time Trip),每次提交都要消耗RTT,不支持相似redis的pipeline機制。

 

Redis pipeline

關於 Redis pipeline

爲何須要 pipeline ?

Redis 的工做過程是基於 請求/響應 模式的。正常狀況下,客戶端發送一個命令,等待 Redis 應答;Redis 接收到命令,處理後應答。請求發出到響應的時間叫作往返時間,即 RTT(Round Time Trip)。在這種狀況下,若是須要執行大量的命令,就須要等待上一條命令應答後再執行。這中間不單單多了許屢次 RTT,並且還頻繁的調用系統 IO,發送網絡請求。爲了提高效率,pipeline 出現了,它容許客戶端能夠一次發送多條命令,而不等待上一條命令執行的結果。java

實現思路

客戶端首先將執行的命令寫入到緩衝區中,最後再一次性發送 Redis。可是有一種狀況就是,緩衝區的大小是有限制的:若是命令數據太大,可能會有屢次發送的過程,可是仍不會處理 Redis 的應答。web

實現原理

要支持 pipeline,既要服務端的支持,也要客戶端支持。對於服務端來講,所須要的是可以處理一個客戶端經過同一個 TCP 鏈接發來的多個命令。能夠理解爲,這裏將多個命令切分,和處理單個命令同樣。對於客戶端,則是要將多個命令緩存起來,緩衝區滿了就發送,而後再寫緩衝,最後才處理 Redis 的應答。redis

Redis pipeline 的參考資料

在 SpringBoot 中使用 Redis pipeline

基於 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)); } }

總結:Redis pipeline 的特性以及使用時須要注意的地方

  • pipeline 減小了 RTT,也減小了IO調用次數(IO 調用涉及到用戶態到內核態之間的切換)
  • 若是某一次須要執行大量的命令,不能放到一個 pipeline 中執行。數據量過多,網絡傳輸延遲會增長,且會消耗 Redis 大量的內存。應該將大量的命令切分爲多個 pipeline 分別執行。
發佈於 2019-03-07
相關文章
相關標籤/搜索