高可用Redis(五):瑞士軍刀之慢查詢,Pipeline和發佈訂閱

1.慢查詢

1.1 慢查詢的生命週期

步驟一:client經過網絡向Redis發送一條命令
步驟二:因爲Redis是單線程應用,能夠把Redis想像成一個隊列,client執行的全部命令都在排隊等着server端執行
步驟三:Redis服務端按順序執行命令
步驟四:server端把命令結果經過網絡返回給client

說明:python

慢查詢發生在命令執行過程當中,不包含網絡延遲時間及排除等待執行的時間
客戶端超時不必定慢查詢,但慢查詢是客戶端超時的一個可能因素

1.2 慢查詢的配置項

slowlog-max-len             慢查詢隊列的長度
slowlog-log-slower-than     慢查詢閾值(單位:微秒),執行時間超過閥值的命令會被加入慢查詢命令
    若是設置爲0,則會記錄全部命令,一般在須要記錄每條命令的執行時間時使用
    若是設置爲小於0,則不記錄任何命令
slowlog list                慢查詢記錄

說明:redis

慢查詢是一個先進先出的隊列,若是一條命令在執行過程當中被列入慢查詢範圍內,就會被放入一個隊列,這個隊列是基於Redis的列表來實現
,並且這個隊列是固定長度的,當隊列的長度達到固定長度時,最早被放入隊列就會被pop出去
慢查詢隊列保存在內存之中,不會作持久化,當Redis重啓以後就會消失

1.3 慢查詢配置方法

1.3.1 修改配置文件重啓

修改/etc/redis.conf配置文件,配置慢查詢
修改配置方式應該在第一次配置Redis中時配置完成,生產後不建議修改配置文件

1.3.2 動態配置

127.0.0.1:6379> config get slowlog-max-len
1) "slowlog-max-len"
2) "128"
127.0.0.1:6379> config get slowlog-log-slower-than
1) "slowlog-log-slower-than"
2) "10000"
127.0.0.1:6379> config set slowlog-max-len 1000
OK
127.0.0.1:6379> config get slowlog-max-len
1) "slowlog-max-len"
2) "1000"
127.0.0.1:6379> config set slowlog-log-slower-than 1000
OK
127.0.0.1:6379> config get slowlog-log-slower-than
1) "slowlog-log-slower-than"
2) "1000"

1.4 慢查詢命令

slowlog get [n]         獲取慢查詢隊列
slowlog len             獲取慢查詢隊列長度
slowlog reset           清空慢查詢隊列

1.5 Redis慢查詢運維經驗

slowlog-max-len不要設置太小,一般設置1000左右
slowlog-log-slower-than不要設置過大,默認10ms,一般設置1ms
理解命令生命週期
能夠經過slowlog get等命令按期將慢查詢命令持久化到其餘數據源,這樣就能夠查到不少歷史的慢查詢操做命令
在生產環境中,無論slowlog-max-len設置多大,當慢查詢命令逐步增多時,最開始的慢查詢命令會被丟掉
當須要查詢歷史數據時,這些慢查詢命令都是很是關鍵的
能夠使用開源軟件來實現這些功能,對於分析解決Redis問題是很是有幫助的

2.Pipeline

2.1 Pipeline的概念

一次網絡命令通訊模型:網絡

client經過網絡傳輸命令到server端
server端經過計算獲得命令執行結果
server端把命令執行結果給client

此時:併發

一次網絡命令通訊時間=1次網絡時間 + 1次命令時間

此時若是有多條命令呢,那就只能一條一條的輸入命令執行了運維

n次時間 = n次網絡時間 + n次命令時間

Redis執行命令的時間很快,可是網絡傳輸卻可能有很大延遲,ui

pipeline就是把一批命令進行打包,而後傳輸給server端進行批量計算,而後按順序將執行結果返回給client端線程

使用Pipeline模型進行n次網絡通訊須要的時間code

1次pipeline(n條命令) = 1次網絡時間 + n次命令時間

2.2 例子

import redis
import time

client = redis.StrictRedis(host='192.168.81.100',port=6379)
start_time = time.time()

for i in range(10000):
    client.hset('hashkey','field%d' % i,'value%d' % i)

ctime = time.time()
print(client.hlen('hashkey'))
print(ctime - start_time)

程序執行結果:server

10000
2.0011684894561768

在上面的例子裏,直接向Redis中寫入10000條hash記錄,須要的時間爲2.00秒生命週期

使用pipeline的方式向Redis中寫入1萬條hash記錄

import redis
import time

client = redis.StrictRedis(host='192.168.81.100',port=6379)
start_time = time.time()

for i in range(100):
    pipeline = client.pipeline()
    j = i * 100
    while j < (i+ 1) * 100:
        pipeline.hset('hashkey1','field%d' % j * 100,'value%d' % i)
        j += 1
    pipeline.execute()

ctime = time.time()
print(client.hlen('hashkey1'))
print(ctime - start_time)

程序執行結果:

10000
0.3175079822540283

能夠看到使用Pipeline方式每次向Redis服務端發送100條命令,發送100次所須要的時間僅爲0.31秒,能夠看到使用Pipeline能夠節省網絡傳輸時間

2.3 Pipeline使用建議

首先要注意每次pipeline攜帶數據量不能太大
pipeline能夠提升Redis批量處理的併發的能力,可是並不能無節制的使用
若是批量執行的命令數量過大,則很容易對網絡及客戶端形成很大影響,此時能夠把命令分割,每次發送少許的命令到服務端執行
pipeline每次只能做用在一個Redis節點上

3.發佈訂閱

3.1 發佈訂閱中的角色

發佈者(publisher)
訂閱者(subscriber)
頻道(channel)

3.2 發佈訂閱的模型

Redis server就至關於頻道
發佈者是一個redis-cli,經過redis server發佈消息
訂閱者也是於一個redis-cli,若是訂閱了這個頻道,就能夠經過redis server獲取消息

說明:

發佈訂閱就是一個生產者消費者模型
每一個訂閱者能夠訂閱多個頻道
發佈者發佈消息後,訂閱者就能夠收到不一樣頻道的消息
訂閱者不能夠接收未訂閱頻道的消息
訂閱者訂閱某個頻道後,Redis沒法作消息的堆積,不能接收頻道被訂閱以前發佈的消息

3.3 發佈訂閱的命令

publish channel message         發佈消息
subscribe [channel]             訂閱頻道
unsubscribe [channel]           取消訂閱
psubscribe [pattern...]         訂閱指定模式的頻道
punsubscribe [pattern...]       退訂指定模式的頻道
pubsub channels                 列出至少有一個訂閱者的頻道
pubsub numsub [channel...]      列表給定頻道的訂閱者數量
pubsub numpat                   列表被訂閱模式的數量

例子:

打開一個終端1

127.0.0.1:6379> subscribe sohu_tv               # 訂閱sohu_tv頻道
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "sohu_tv"
3) (integer) 1

再次打開一個終端2

127.0.0.1:6379> publish sohu_tv 'hello python'      # sohu_tv頻道發佈消息
(integer) 1
127.0.0.1:6379> publish sohu_tv 'hello world'       # sohu_tv頻道發佈消息
(integer) 3

能夠看到終端1中已經接收到sohu_tv發佈的消息

127.0.0.1:6379> subscribe sohu_tv
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "sohu_tv"
3) (integer) 1
1) "message"
2) "sohu_tv"
3) "hello python"
1) "message"
2) "sohu_tv"
3) "hello world"

打開終端3,取消訂閱sohu_tc頻道

127.0.0.1:6379> unsubscribe sohu_tv
1) "unsubscribe"
2) "sohu_tv"
3) (integer) 0

3.4 發佈訂閱與消息隊列

redis server維護一個隊列
消息發佈者,至關於一個redis-cli,經過redis server發佈消息
消息訂閱者就至關於一個redis-cli,全部的消息訂閱者經過redis server搶消息發佈者發佈的消息
相關文章
相關標籤/搜索