《Redis開發與運維》第二章 API的理解和使用(下)讀書筆記

搬磚大叔發表於2019-01-03

集合(set)

集合(set)型別是用來儲存多個的字串元素,但和列表型別不一樣的是,集合中不允許有重複元素,並且集合中的元素是無序的,不能通過索引下標獲取元素。集合支援多個集合取交集、差集、並集。

如下圖所示:

在這裡插入圖片描述

命令

  • 新增元素
## 命令:sadd key element \[element ... \],返回結果為新增成功的元## 素個數
## 例如:
172.17.236.250:6379> sadd myset a b c
(integer) 3
複製程式碼
  • 刪除元素
## 命令:srem key element \[element ... \],返回結果為成功刪除的元## 素個數
## 例如:
172.17.236.250:6379> srem myset a b
(integer) 2
複製程式碼
  • 計算元素個數
## 命令:scard key
## 例如:
172.17.236.250:6379> scard myset
(integer) 1
複製程式碼

  scard 的時間複雜度為 O(1) ,它不會遍歷集合所有元素,而是直接使用 Redis 內部變數。

  • 判斷元素是否在集合中
## 命令:sismember key element,在集合中,返回1,否則返回0
## 例如:
172.17.236.250:6379> sismember myset c
(integer) 1
複製程式碼
  • 隨機從集合中返回指定個數(不會刪除集合中的元素
## 命令:srandmember key [count] ,count 為可選引數,不寫預設為1
## 例如:
172.17.236.250:6379> srandmember myset 
"c"
複製程式碼
  • 從集合中隨機彈出元素(會刪除集合中的元素
## 命令:spop key,在 Redis3.2 版本之後,spop 也支援 [count] 引數
## 例如:
172.17.236.250:6379> smembers myset
1) "b"
2) "a"
3) "c"
172.17.236.250:6379> spop myset
"c"
172.17.236.250:6379> smembers myset
1) "b"
2) "a"
複製程式碼
  • 獲取所有元素
## 命令:smembers key,返回的結果是無序的
## 例如:
172.17.236.250:6379> smembers myset
1) "b"
2) "a"
複製程式碼

集合間的操作

  有兩個集合,set1set2 ,如下:

172.17.236.250:6379> sadd set1 a b c d e f j l
(integer) 8
172.17.236.250:6379> sadd set2 a b c d e f g h
(integer) 8
複製程式碼
  • 求集合間的交集
## 命令:sinter key \[key ... \]
## 例如:求 set1 和 set2 的交集
172.17.236.250:6379> sinter set1 set2
1) "c"
2) "b"
3) "e"
4) "a"
5) "d"
6) "f"
複製程式碼
  • 求集合間的並集
## 命令:sunion key [\ key ... \]
## 例如:求 set1 和 set2 的並集
172.17.236.250:6379> sunion set1 set2
 1) "h"
 2) "c"
 3) "e"
 4) "g"
 5) "a"
 6) "l"
 7) "f"
 8) "b"
 9) "j"
10) "d"
複製程式碼
  • 求集合的差集
## 命令:sdiff key [key ... \]
## 例如:求 set1 和 set2 的差集
172.17.236.250:6379> sdiff set1 set2
1) "l"
2) "j"
複製程式碼
  • 將交集、並集、差集的結果儲存
## 交集:sinterstore destination key \[key ... \]
## 並集:suionstore destination key \[key ... \]
## 差集:sdiffstore destination key \[key ... \]
例如:求 set1 和 set2 的交集並儲存在集合中
172.17.236.250:6379> sinterstore set1_2 set1 set2
(integer) 6
172.17.236.250:6379> smembers set1_2
1) "a"
2) "b"
3) "c"
4) "e"
5) "d"
6) "f"
複製程式碼

  集合常用命令時間複雜度圖,如下:

在這裡插入圖片描述

內部編碼

集合型別的內部編碼有兩種:

  • intset(整數集合): 當集合間的元素都是整數且元素個數小於 set-max-intset-entries 配置(預設512個)時,Redis 會使用 intset 當做集合的內部實現,從而減少記憶體的使用。
  • hashtable(雜湊表): 當集合型別無法滿足 intset 的條件時,Redis 會使用 hashtable 當做集合的內部編碼來時。

使用場景

  • sadd = Tagging(標籤)
  • spop/srandmember = Random item(生成隨機數,抽獎等)
  • sadd+sinter = Social Graph(社交需求)

有序集合

有序集合有集合元素不能重複的特性,但是,有序集合中的元素是可以排序的。但是有序集合和列表使用索引下標來排序不同的是,有序集合給每一個元素設定一個分值(score)作為排序的依據。

如下圖所示:

在這裡插入圖片描述
注意:有序集合的元素不能重複,但是 score 可以重複。 有序集合、列表、集合之間的異同如下圖:
在這裡插入圖片描述

命令

  • 新增成員
## 命令:zadd key score member \[score member ... \],返回的結果為成功新增的成員個數
## 例如:為有序集合 user:ranking 新增使用者 tom 和他的分數 251
172.17.236.250:6379> zadd user:ranking 261 tom
(integer) 1
複製程式碼
  • 注意:

    1. Redis3.2 為 zadd 命令新增了 nxxxchincr 四個選項
    2. nxmember 必須不存在,才可以設定成功,用於新增
    3. xxmember 必須存在,才可設定成功,用於修改
    4. ch:返回此操作後,有序集合的元素和 score 發生變化的個數
    5. incr:對 score 做增加操作
    6. 有序集合提供了排序欄位,但是也產生了代價,zadd 的時間複雜度為 O(log(n)),sadd 的時間複雜度為 O(1)
  • 計算成員個數

## 命令:zcard key,時間複雜度為 O(1)
## 例如:
172.17.236.250:6379> zcard user:ranking
(integer) 1
複製程式碼
  • 計算某個成員的分數
## 命令:zscore key member,如果成員不存在則返回 nil
## 例如:
172.17.236.250:6379> zscore user:ranking tom
"261"
複製程式碼
  • 計算成員的排名
## 從低到高:zrank key member
## 從高到低:zrevrank key member
## 例如:
172.17.236.250:6379> zadd user:ranking 100 tom2
(integer) 1
172.17.236.250:6379> zrank user:ranking tom
(integer) 1
172.17.236.250:6379> zrevrank user:ranking tom
(integer) 0
複製程式碼
  • 刪除成員
## 命令:zrem key member \[member ... \]
## 例如:將 tom2 從有序集合中刪除
172.17.236.250:6379> zrem user:ranking tom2
(integer) 1
複製程式碼
  • 增加成員的分數
## 命令:zincrby key increment member
## 例如:給 tom 增加 9 分
172.17.236.250:6379> zincrby user:ranking 9 tom
"270"
複製程式碼
  • 返回指定排名範圍的成員
## 從低到高:zrange user:ranking start end \[withscores \]
## 從高到低:zrevrange user:ranking start end \[withscores \]
## withscores:可選,加上會顯示成員的分數
例如:
172.17.236.250:6379> zrange user:ranking 0 2 withscores
1) "tom"
2) "270"
172.17.236.250:6379> zrevrange user:ranking 0 2 withscores
1) "tom"
2) "270"
複製程式碼
  • 返回指定分數範圍的成員
## 從低到高:zrangebyscore key min max \[withscores\] \[limit offest count\]
## 從高到低:zrevrangebyscore key max min \[withscores\] \[limit offest count\] 
## limit offest count:限制輸出的起始位置和個數
## 例如:
172.17.236.250:6379> zrangebyscore user:ranking 200 300 withscores
1) "tom"
2) "270"
## min 和 max 可以設定開區間(小括號)和閉區間(中括號),-inf 和+inf 代表無限小和無限大
例如:
172.17.236.250:6379> zrangebyscore user:ranking (200 +inf withscores
1) "tom"
2) "270"
複製程式碼
  • 返回指定分數範圍成員個數
## 命令:zcount key min max
## 例如:
172.17.236.250:6379> zcount user:ranking 200 300
(integer) 1
複製程式碼
  • 刪除指定排名內的升序元素
## 命令:zremrangebyrank key start end
## 例如:刪除 0 到 2 名的成員
172.17.236.250:6379> zremrangebyrank user:ranking 0 1
(integer) 2
複製程式碼
  • 刪除指定分數範圍的成員
## 命令:zremrangebyscore key min max,返回結果為成功刪除的個數
## 例如:
172.17.236.250:6379> zremrangebyscore user:ranking 200 290
(integer) 2
複製程式碼

集合間的操作

  有兩個集合 user:1 和 user:2 ,如下:

172.17.236.250:6379> zadd user:1 1 kris 91 mike 200 frank 220 tim 250 martin 251 tom
(integer) 6
172.17.236.250:6379> zadd user:2 8 james 77 mike 625 martin 888 tom
(integer) 4
複製程式碼
  • 交集
## 命令:zinterstore destination numkeys key \[key ... \] \[weights 
## wright \[weight]] \[aggregate sum|min|max]
## destination:交集計算結果儲存到該鍵
## numkeys:需要做交集計算鍵的個數
## key[key ... \]:需要做交集計算的鍵
## weights weight[weight...]:每個鍵的權重,在做交集計算時,每個
## 鍵中的每一個 member 會將自己分數乘以這個權重,每個鍵的權重
## 預設值是1
## aggregate sum|min|max:計算成員交集後,分值可以按照 
## sum(和)、min(最小值)、max(最大值)做彙總,預設值是 su
## m
## 例如:對 user:1 和 user:2 求交集,weights 和 aggregate 使用預設## 配置,可以看到目標鍵對分值做了 sum 操作
172.17.236.250:6379> zinterstore user:1_2 2 user:1 user:2
(integer) 3
172.17.236.250:6379> zrange user:1_2 0 -1 withscores
1) "mike"
2) "168"
3) "martin"
4) "875"
5) "tom"
6) "1139"
複製程式碼
  • 並集
## 命令:zunionstore destination numkeys key \[key ... \] \[weights 
## weight ... \[weight ... \] \[aggregate sum|min|max]]
## 該命令所有引數都和 zinterstore 一樣。只不過是做並集計算。
## 例如:對 user:1 和 user:2 求並集,weights 和 aggregate 使用預設## 配置,可以看到目標鍵對分值做了 sum 操作
172.17.236.250:6379> zunionstore user2:1_2 2 user:1 user:2
(integer) 7
172.17.236.250:6379> zrange user2:1_2 0 -1 withscores
 1) "kris"
 2) "1"
 3) "james"
 4) "8"
 5) "mike"
 6) "168"
 7) "frank"
 8) "200"
 9) "tim"
10) "220"
11) "martin"
12) "875"
13) "tom"
14) "1139"
複製程式碼

  下圖為有序集合命令時間複雜度表,可根據此表選擇合適的命令進行開發。

在這裡插入圖片描述

內部編碼

有序集合的內部編碼有兩種:

  • ziplist(壓縮列表):當有序集合的元素個數小於 zset-max-ziplist-entries 配置(預設128個),每個元素的值都小於 zset-max-ziplist-value 配置(預設64位元組)時,Redis 內部會使用 ziplist 來作為有序集合的內部實現。
  • skiplist(跳躍表):當 ziplist 的條件不滿足時,有序集合會使用 skiplist 作為內部實現,因為此時 ziplist 的讀寫效能會下降。

使用場景

有序集合比較典型的使用場景就是排行榜系統。假設有一個視訊網站按照贊數去排名的,則該排行榜主要需要實現以下幾個功能。

  • 新增使用者的贊數
## 使用者 mike 上傳視訊並獲得 3 個贊
172.17.236.250:6379> zadd user:ranking 3 mike
(integer) 1
## 如果再獲得一個贊可以使用 zincrby
172.17.236.250:6379> zincrby user:ranking 1 mike
"4"
複製程式碼
  • 取消使用者的贊
## 取消贊可以直接刪除成員 tom(也可以直接將贊數修改為 0)
172.17.236.250:6379> zrem user:ranking mike
(integer) 1
複製程式碼
  • 展示獲取贊數前 10 的使用者
172.17.236.250:6379> zrevrange user:ranking 0 9
1) "mike"
複製程式碼
  • 展示使用者資訊以及使用者分數
## 將使用者名稱作為字尾,將使用者資訊儲存在 hash 中,使用者的分數和排名
## 可以使用 score 和 zrank 。
172.17.236.250:6379> hgetall user:info:mike
(empty list or set)
172.17.236.250:6379> zscore user:ranking mike
"3"
172.17.236.250:6379> zrank user:ranking mike
(integer) 0
複製程式碼

鍵管理

鍵重新命名

rename key newkey
複製程式碼

注意:如果在 rename 之前,鍵 newkey 已經存在,那麼它的值也會被覆蓋。

172.17.236.250:6379> set a b
OK
172.17.236.250:6379> set c d
OK
172.17.236.250:6379> rename a c
OK
172.17.236.250:6379> get c
"b"
複製程式碼
  • 只有在 newkey 不存在的情況下才允許重新命名
renamenx key newkey
複製程式碼

注意:重新命名期間會執行 del 命令刪除舊鍵,如果鍵對應的值比較大,可能會引起 Redis 阻塞。

  • 隨機返回一個鍵
randomkey
複製程式碼

鍵過期

## 鍵在 seconds 秒後過期
expire key seconds
## 鍵在秒級時間戳 timestamp 後過期
expireat key timestamp
## 過期剩餘時間,返回值:
## 大於 0 的整數(鍵過期剩餘時間,ttl 為秒,pttl 為毫秒)
## -1 (沒有設定過期時間)
## -2 (鍵不存在)
ttl key 
pttl key 
## 鍵在 millisecondes 毫秒過期
pexpire key millisecondes
## 鍵在毫秒級時間戳 millisecondes-timestamp 過期
pexpireat key millisecondes-timestamp
## 清楚過期時間
persist key
複製程式碼

注意: 1. 如果 expire key 的鍵不存在,返回結果為 0 2. 如果過期時間為負值,鍵會被立即刪除 3. 對於字串型別鍵,執行 set 命令會去掉過期時間 4. Redis 不支援二級資料結構內部元素的過期功能 5. setexset +expire 的組合) 不但是原子執行,同時減少了一次網 絡通訊時間

遷移鍵

  • move

在 Redis 內部可能有多個資料庫,這些資料庫彼此在資料上是相互隔離的。

如下圖:

在這裡插入圖片描述

## 將指定的鍵從源資料庫遷移到目標資料庫
move key db
複製程式碼
  • dump + restore
dump key
restore key ttl value
複製程式碼

   dump + restore可以實現在不同的 Redis 例項之間進行資料遷移功能,整個遷移的過長分為兩步:   1、在源 Redis 上,dump 命令會將鍵值序列化(RDB)格式。   2、在目標 Redis 上,restore 命令將上面序列化的值進行復原,如果 ttl = 0,則沒有過期時間。 整個過程如下圖所示:

在這裡插入圖片描述
注意:   1、整個遷移過程並非原子性,而是通過客戶端分步完成   2、遷移過程中開啟了兩個客戶端連線,所以 dump 的結果不是在源 Redis 和目標 Redis 之間進行傳輸。

示例:

  1、在源 Redis 上執行 dump

set hello world
OK
dump hello
"\\x00\\x05world\\x06\\x00\\x8f<T\\x04%\\xfcNQ"
複製程式碼

  2、在目標 Redis 上執行 restore

restore hello 0 "\\x00\\x05world\\x06\\x00\\x8f<T\\x04%\\xfcNQ"
複製程式碼
  • migrate
## host:目標 Redis 的 ip 地址
## port:目標 Redis 的埠
## key|"":遷移的鍵,如需遷移多個鍵則此處為空字串
## destination-db:目標 Redis 的資料庫索引
## timeout:遷移的超時時間(單位為毫秒)
## copy:如果新增該引數,則遷移後不刪除源鍵
## replace:不管目標 Redis 是否存在該鍵都會正常遷移進行資料覆蓋
## keys key \ ... \:要遷移的多個鍵
migrate host port key | "" destination-db timeout \[copy\] \[replace\] \[keys key \[key ... \]]
複製程式碼

  migrate的整個過程是原子性的,資料的傳輸直接在源 Redis 和目標 Redis 之間完成,目標 Redis 完成 restore 後會傳送 OK 給源 Redis ,源 Redis 接收後會根據 migrate 對應的選項來決定是否在源 Redis 上刪除對應的鍵。

下圖為 migrate 在 Redis 之間原子性遷移資料:

在這裡插入圖片描述

下圖為 movedump+restoremigrate 三個命令比較:

在這裡插入圖片描述

遍歷鍵

  • 全量遍歷鍵
## pattern可以為 *(任意字元)、.*(一個字元)、.[](匹配部分字元)、.\x(* 或者 ? 需要轉義)
keys pattern    
複製程式碼
  • 漸進式遍歷
## cursor:是一個遊標,必須引數,從0開始遍歷,遍歷完會返回當前遊## 標值,當為0時,則遍歷結束。
## match pattern:可選引數,用做模式匹配
## count number:每次遍歷的鍵的個數,預設是10
scan cursor \[match pattern\] \[count number\]
複製程式碼

  雜湊型別、集合型別、有序集合型別對應的命令分別是 hscansscanzscan注意:在使用 scan 命令遍歷時並不能保證完整的遍歷出所有的鍵,這在開發的時候需要考慮。

資料庫管理

Redis 預設配置是可以有16個資料庫,這16個資料庫之間沒有任何關聯。redis-cli-h{ip}-p{port}就是預設的使用的第一個資料庫

  • 切換資料庫
select dbIndex
複製程式碼

缺點:   1、Redis是單執行緒的。如果使用多個資料庫,這些資料庫共用一個CPU,彼此之間是會受到影響的。   2、會讓除錯和運維不同的資料庫變得困難,使業務方定位問題非常的困難。   3、部分 Redis 客戶端不支援這種方式。

  • flushdb/flushall flushdb清楚當前資料庫資料,flushall 清楚所有資料庫的資料。慎用這兩個命令

相關文章