Redis其他功能(命令操作)

一、慢查詢

Redis生命週期

Redis一次請求完整的生命週期:

  1. 發送請求(可以是Jedis客戶端等)
  2. 排隊等待請求被Redis處理
  3. Redis執行命令
  4. 返回結果

Redis請求生命週期
又因爲Redis是單線程應用,也就是說只要有一個請求正在執行,後面的請求就必須全部等待。這也是我們爲什麼需要去關心慢查詢的原因。假設有一個命令keys *,該命令需要執行10s,而該命令後的所有請求都將等待keys *的執行。而這10s將會導致後續所有命令的滯後,甚至是請求超時!

跟我們集成Druid或者相關監控是一樣的道理,Druid爲我們揪出了慢sql語句,而Redis則爲我們揪出慢查詢語句。並且Redis由於是單線程應用,優化慢查詢顯得更爲重要。而我們需要做的就是監控Redis,記錄監控所有慢查詢語句,定期進行優化

配置慢查詢

在redis中有專門的一個先進先出隊列用於記錄慢查詢操作,我們需要做的是根據自己的需求進行配置,揪出慢查詢,以供優化。其中慢查詢默認的隊列長度是128,超過1000微秒,也就是10ms的算作是慢查詢。這個值並非適用於所有項目,因此我們需要根據自己的項目進行設置

如果你的Redis已經啓動,那麼不建議進行重啓,最好的方式是進行動態配置,也就是在Redis客戶端中發送。

# 慢查詢隊列長度
config set slowlog-max-len 1000
# 慢查詢閥值,也就是當請求處理時間大於1ms時記錄爲慢查詢
config set slowlog-log-slower-than 1000

當Redis還沒啓動時,可以通過修改配置文件的方式進行配置。運維小組一般也是在上線前通過配置制定好再進行上線

命令使用

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

二、Pipeline 流水線

在數據結構那節我們介紹了字符串有mget mset操作,可以一次發送多條設置查詢命令,減少網絡延遲,但是並非所有的數據結構或者命令都有批量操作,Redis爲我們提供了pipeline將多條命令進行一次打包,發送給redis-server,減少多次網絡開銷(當然)

假設發送網絡延遲和響應延遲均爲50ms,處理1次Redis時間爲1ms(一般1ms已經算慢查詢了)

  1. 如果我們分100次發送,則總時長 = 100次發送網絡延遲 * 50ms + 100次響應延遲 * 50ms + 100次 * 1ms = 10100ms
  2. 如果我們適用Pipeline,打包100次請求,一次發送。則總時長 = 1次發送網絡延遲 * 50ms + 1次響應延遲 * 50ms + 100次 * 1ms = 200ms

效果是很客觀的,該命令跟sql中單條savebatchSave的思想是一樣的,也就是將多條命令一次提交,減少網絡延遲帶來的時間浪費。但是需要注意的是

  1. batchSave是一次原子操作,也就是說這100條sql命令會被一起執行。但是Redis則不然,雖然我們一次性提交了100次操作,但是這些操作會根據順序進入到等待隊列中(中間往往會穿插一些其他客戶端的請求)
  2. 每次我們請求的pipeline也不宜太大,雖然pipeline並非原子操作,也就是不會阻塞其他客戶端同一時間的操作請求。但是如果數量太大,勢必引起後續請求的阻塞,同時也會導致當前pipeline的返回時間過長,導致超時
  3. 後續我們會講到集羣,也就是多個redis實例。而pipeline則只能作用於1個Redis節點

Jedis

// 無pipeline
Jedis jedis = new Jedis("127.0.0.1", 6379);
for (int i = 0; i < 10000; i++) {
  jedis.hset("key" + i, "field" + i, "value" + i);
}

// pipeline
Jedis jedis = new Jedis("127.0.0.1", 6379);
for (int i = 0; i < 100; i++) {
  Pipeline pipeline = jedis.pipeliend();
  for (int j = i * 100; j < (i + 1) * 100; j++) {
      jedis.hset("key" + j, "field" + j, "value" + j);
  }
  pipeline.syncAndReturnAll();
}

三、發佈訂閱

redis提供了發佈訂閱的功能,這裏我們只是做一個簡單的介紹,因爲這部分我們往往會選擇像kafkarabbitmq跟專業的中間件

角色

發佈訂閱的功能類似看電視,首先發布者適用publish channel message將需要發佈的內容發佈到頻道中,而所有的訂閱者都將收到這份消息,也就是說這是一個1對多的操作。

  1. 發佈者(publisher)
  2. 訂閱者(subscriber)
  3. 頻道(channel)

命令

# publish channel message
# 發佈消息到頻道中,返回訂閱者個數

# subscribe unsubscribe
# 訂閱頻道 取消訂閱

# psubscribe punsubscribe
# 訂閱頻道 取消訂閱 使用通配符

# pubsub channels
# 列出至少有一個訂閱者的頻道

# pubsub numsub [channel] 
# 列出給定頻道的訂閱者數量

四、消息隊列

消息隊列發佈訂閱的區別在於,發佈訂閱就像電視,每個人都可以收看訂閱某個頻道,每個人也都將收到信息。而消息隊列則是搶紅包的概念,雖然多個客戶端都訂閱了該隊列,但是隻有一個客戶端會收到該消息,也就是隻有一個客戶端能搶到紅包。

redis原生並不支持消息隊列,但是由於Redis是單線程應用,因此我們可以通過Redis的隊列數據結構進行消息隊列的實現。當然了,我們還是跟推薦適用專業的Rabbitmq等中間件

五、Bitmap 位圖

位圖本質就是2進制串,如0101110111這麼一個串,長度限制512mb。這種數據結構特別適合做稠密圖。假設一個APP有10w用戶量,要統計每天用戶的登錄情況,只需生成一個....0000...的位圖,pkid爲1的用戶登錄,則將第一位置爲1,即...00001,而一天統計用戶登錄情況所需的內存空間爲100000b。如果存儲的是pkid,每個pkid需要32b。也就是說,當每天用戶登錄量小於100000b / 32b時,所用空間更佔優勢,當數量大於100000b / 32b時,則位圖跟佔優勢。這也就是所說的稀疏圖稠密圖的概念

命令使用

# setbit key offset value
# 設置第offset位的比特位爲value,返回原比特位的值
127.0.0.1:6381> get bit
"a"
127.0.0.1:6381> setbit bit 6 1
(integer) 0
127.0.0.1:6381> get bit
"c"
127.0.0.1:6381> getbit bit 6
(integer) 1
# bitcount key [start end]
# 獲取範圍內1的個數
127.0.0.1:6381> bitcount bit 0 -1
(integer) 4
# bitop op destkey key [key]
# op: and交 or或 not非 xor異或
127.0.0.1:6381> get bit
"c"
127.0.0.1:6381> set opbit 0
OK
127.0.0.1:6381> bitop and bit opbit
(integer) 1
127.0.0.1:6381> get bit
"0"
# bitpos key targetBit [start] [end](start end指字節,不是bit位)
# 獲取第一個targitBit出現的位置
# bit = 00110000
127.0.0.1:6381> bitpos bit 1
(integer) 2

六、hyperLogLog

本質爲字符串,使用極小的空間實現統計功能。

注意:hyperLogLog只能用於統計,加入的數據無法像map一樣進行取出,只能是不斷插入,最後進行統計!而且hyperLogLog存在一定機率的錯誤,因此一般是做大數據量的統計,如一個百萬流量APP,統計每天用戶活躍數。需要的只是一個大致的數字,而非確切數字

# pfadd key elment
# 添加
# pfcount key 
# 統計個數
# pfmerge destkey sourcekey
# 合併
127.0.0.1:6381> pfadd ids:0301 "uid1" "uid2" "uid3"
(integer) 1
127.0.0.1:6381> pfcount ids:0301
(integer) 3
127.0.0.1:6381> pfadd ids:0302 "uid3" "uid4" "uid5"
(integer) 1
127.0.0.1:6381> pfmerge ids:0301-0302 ids:0301 ids:0302
OK
127.0.0.1:6381> pfcount ids:0301-0302
(integer) 5

七、GEO 地理位置

顧名思義,就是經緯度給座標的,用於計算座標差,或者距離點的。比如搖一搖、外賣、附近商家等都可以使用。這裏給大家做個介紹而已,知道有這些功能,需要用時再去查就行

# geoadd key 經度 緯度 member
# geopos key member
# 獲取地理信息
127.0.0.1:6381> geoadd cities 116.28 39.55 beijing 117.12 39.08 tianjing
(integer) 2
127.0.0.1:6381> geopos cities beijing
1) 1) "116.28000229597091675"
   2) "39.5500007245470826"
# geodis key member1 member2 unit
# 獲取兩地距離
127.0.0.1:6381> geodist cities beijing tianjing km
"89.2061"
# georadius 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章