列表(list)相當于是 數組 或者 順序表list 內部編碼方式并非是一個簡單的數組,而是更接近于“雙端隊列”(deque)列表中的元素是有序的(元素位置),允許插入重復元素
常見命令
1)lpush? lpushx? rpush? rpushx
lpush key element [element ...]? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? —— 頭插
返回 list 的長度? O(1)
lpushx?key element [element ...]
當 key 存在是返回 list 的長度,否則直接返回? O(1)?? ? ? ? ? ? ? ? ?—— 頭插
rpush key element [element ...]? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? ? ?—— 尾插
返回 list 的長度? O(1)
rpush key element [element ...]? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? —— 尾插
當 key 存在是返回 list 的長度,否則直接返回? O(1)?
若果 key 已經存在,并且 key 對應的 value 類型不是 list,此時會報錯
2)lrange
獲取從 start 到 end 區間內的所有元素(左閉右閉)
lrange key start end? (支持負數)
返回指點區間內的元素? O(N)
此處 數字 只是標識返回元素的順序(結果集),和下標無關
當給出非法下標時,Redis 會盡可能的取到給定區間內的元素(魯棒性)
3)lpop? rpop
lpop key [count]? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?—— 頭刪
返回指定區間內的元素或者 nil? O(count)
rpop key [count]? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?—— 尾刪
返回指定區間內的元素或者 nil? O(count)
Redis 中的 list 是一個雙端隊列,從兩頭插入/刪除是非常高效的? O(1)
rpush + lpop ——> 隊列
rpush + rpop ——> 棧
4)lindex
lindex key index
返回指定下表的元素 ,非法下標則返回 nil? O(N)
正數表示從左數,負數反之,起始點為 0
5)linsert
linsert key <before | after> pivot element
返回插入后的 list 的長度? O(N)
pivot? 基準值(從左往右)? ? element? 要插入的元素
6)len
len key
返回 list 的長度? O(1)
7)lrem
lrem key count element
返回刪除的元素個數? O(1)
count? 要刪除的元素的個數? ? ? ?element? 要刪除的元素的值
8)ltrim?
ltrim key count element
返回 ok? O(N)
保留 start 和 stop 區間內的元素(區間外的被直接刪除)
9)lset
lset key index element
返回 OK,若下表越界返回 nil? O(1)
10)blpop? brpop
blpop key [key ...] timeout? ? ? ? ? ? ? ? ? ?—— 尾刪
返回取出的元素或者 nil? O(1)
brpop key [key ...] timeout? ? ? ? ? ? ? ? ? ?—— 尾刪
返回取出的元素或者 nil? O(1)
返回結果相當于是一個pair(二元組)
一方面表示當前數據來自哪個 key? ? ? ? ??
一方面表示取到的數據是什么
生產者—消費者模型? —— BlockingQueue
使用隊列作為中間的“交易場所”(broker)
1.線程安全
2.隊列為空,嘗試出隊列,產生阻塞,直到隊列不空,阻塞解除
? ?隊列為滿,嘗試入隊列,產生阻塞,直到隊列不滿,阻塞解除
Redis 的 list 也相當于 阻塞隊列
線程安全 —— 單線程模型? ? ? ? 阻塞 —— 只支持“隊列為空”,不考慮“隊列滿”
顯示設置阻塞時間,此處不會對 Redis 服務器造成太大影響
可以同時去嘗試獲取多個鍵,一旦有一個鍵對應的列表中可以彈出元素,命令立即返回
命令如果設置了多個鍵,會從左向右進行遍歷,一旦有一個鍵對應的列表中可以彈出元素,命令立即返回
如果多個客戶端同時對一個鍵進行 blpop ,最先執行的客戶端會獲得元素
編碼方式
quecklist
相當于是 鏈表 和 壓縮列表 的結合
整體還是一個列表,鏈表的每個節點,是一個壓縮列表
每個壓縮列表都不太大,同時再把多個壓縮列表通過鏈表結構連起來
ziplist(壓縮列表)
把數據按照更緊湊的形式進行表示。
節省空間,但是數個數多了,操作效率會下降
linkedlist(鏈表)
應用場景
消息隊列
使用 lpush + brpop 組合實現 生產者-消費者?模型,在通過多個客戶端保證負載均衡和高可用性
如果列表為空,生產出的下個元素只有一個消費者可以“搶到”元素
分頻道的消息隊列
如果頻道為空,生產出的下個元素只有一個消費者可以“搶到”元素
多個頻道,可以在某種數據發生異常時,不會對其他數據造影響(解耦合)
微博 TimeLine
每個用戶都有屬于自己的 TimeLine(微博列表)
當需要分頁展示文章列表時,可以使用 list (list不僅有序,還支持按照索引范圍獲取元素)
1.)當前一頁中的有多少數據是不確定的,可能會導致下面的循環比較大,從而出發多次 hgetall(多次網絡請求)
pipeline (流水線\管道)把多個 Redis 命令合并成一次 網絡請求進行通信,降低服務器與客戶端的通信次數
2)分裂獲取文章時,lrange 在列表兩端表現比較好,獲取列表中間的元素表現比較差,可以將列表進行拆分