共計 3285 個字符,預計需要花費 9 分鐘才能閱讀完成。
這篇文章將為大家詳細講解有關 Redis 中管道機制的示例分析,丸趣 TV 小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
Pipeline 簡介
Redis 客戶端執行一條命令:
發送命令
命令排隊
執行命令
返回結果
其中發送命令和返回結果可以稱為 Round Trip Time (RTT, 往返時間)。在 Redis 中提供了批量操作命令,例如 mget、mset 等,有效地節約了 RTT。但是大部分命令是不支持批量操作的。
為此 Redis 提供了一個稱為管道 (Pipeline) 的機制將一組 Redis 命令進行組裝,通過一次 RTT 傳輸給 Redis, 再將這些 Redis 命令的執行結果按順序傳遞給客戶端。即使用 pipeline 執行了 n 次命令,整個過程就只需要一次 RTT。
對 Pipeline 進行性能測試
我們使用 redis-benchmark 對 Pipeline 進行性能測試,該工具提供了 -P 的選項,此選項表示使用管道機制處理 n 條 Redis 請求,默認值為 1。測試如下:
# 不使用管道執行 get set 100000 次請求
[root@iz2zeaf3cg1099kiidi06mz ~]# redis-benchmark -t get,set -q -n 100000
SET: 55710.31 requests per second
GET: 54914.88 requests per second
# 每次 pipeline 組織的命令個數 為 100
[root@iz2zeaf3cg1099kiidi06mz ~]# redis-benchmark -P 100 -t get,set -q -n 100000
SET: 1020408.19 requests per second
GET: 1176470.62 requests per second
# 每次 pipeline 組織的命令個數 為 10000
[root@iz2zeaf3cg1099kiidi06mz ~]# redis-benchmark -P 10000 -t get,set -q -n 100000
SET: 321543.41 requests per second
GET: 241545.89 requests per second
從上面測試可以看出,使用 pipeline 的情況下 Redis 每秒處理的請求數遠大于 不使用 pipeline 的情況。
當然每次 pipeline 組織的命令個數不能沒有節制,否則一次組裝 Pipeline 數據量過大,一方面會增加 客戶端等待時間,另一方面會造成一定的網絡阻塞。
從上面的測試中也可以看出,如果一次 pipeline 組織的命令個數為 10000,但是它對應的 QPS 卻小于 一次 pipeline 命令個數為 100 的。所以每次組織 Pipeline 的命令個數不是越多越好,可以將一次包含大量命令的 Pipeline 拆分為 多個較小的 Pipeline 來完成。
Pipeline 關于 RTT 的說明
在官網上有一段這樣的描述:
大致意思就是:
Pipeline 管道機制不單單是為了減少 RTT 的一種方式,它實際上大大提高了 Redis 的 QPS。原因是,在沒有使用管道機制的情況下,從訪問數據結構和產生回復的角度來看,為每個命令提供服務是非常便宜的。但是從底層套接字的角度來看,這是非常昂貴的,這涉及 read()和 write()系統調用,從用戶態切換到內核態,這種上下文切換開銷是巨大。而使用 Pipeline 的情況下,通常使用單個 read()系統調用讀取許多命令,然后使用單個 write()系統調用傳遞多個回復, 這樣就提高了 QPS
批量命令與 Pipeline 對比
批量命令是原子的,Pipeline 是非原子的
批量命令是一個命令多個 key,Pipeline 支持多個命令
批量命令是 Redis 服務端實現的,而 Pipeline 需要服務端和客戶端共同實現
使用 jedis 執行 pipeline
public class JedisUtils { private static final JedisUtils jedisutils = new JedisUtils();
public static JedisUtils getInstance() {
return jedisutils;
}
public JedisPool getPool(String ip, Integer port) { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(RedisConfig.MAX_IDLE);
jedisPoolConfig.setMaxTotal(RedisConfig.MAX_ACTIVE);
jedisPoolConfig.setMaxWaitMillis(RedisConfig.MAX_WAIT);
jedisPoolConfig.setTestOnBorrow(true);
jedisPoolConfig.setTestOnReturn(true);
JedisPool pool = new JedisPool(jedisPoolConfig, ip, port,RedisConfig.TIMEOUT,RedisConfig.PASSWORD);
return pool;
}
public Jedis getJedis(String ip, Integer port) {
Jedis jedis = null;
int count = 0;
while (jedis == null count RedisConfig.RETRY_NUM) {
try { jedis = getInstance().getPool(ip, port).getResource();
} catch (Exception e) {
System.out.println( get redis failed
}
count++;
}
return jedis;
}
public void closeJedis(Jedis jedis) { if (jedis != null) { jedis.close();
}
}
public static void main(String[] args) throws InterruptedException { Jedis jedis = JedisUtils.getInstance().getJedis(127.0.0.1 , 6379);
Pipeline pipeline = jedis.pipelined();
pipeline.set( hello , world
pipeline.incr( counter
System.out.println( 還沒執行命令
Thread.sleep(100000);
System.out.println( 這里才開始執行
pipeline.sync();
}
}
在睡眠 100s 的時候查看 Redis,可以看到此時在 pipeline 中的命令并沒有執行,命令都被放在一個隊列中等待執行:
127.0.0.1:6379 get hello
(nil)
127.0.0.1:6379 get counter
(nil)
睡眠結束后,使用 pipeline.sync() 完成此次 pipeline 對象的調用。
127.0.0.1:6379 get hello
world
127.0.0.1:6379 get counter
1
必須要執行 pipeline.sync() 才能最終執行命令,當然可以使用 pipeline.syncANdReturnAll 回調機制將 pipeline 響應命令進行返回。
關于“Redis 中管道機制的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。