深入剖析Redis系列(四) - Redis数据结构与全局命令概述
前言
Redis 提供了 5 種數據結構。理解每種數據結構的特點,對于 Redis 的 開發運維 非常重要,同時掌握 Redis 的 單線程命令處理 機制,會使 數據結構 和 命令 的選擇事半功倍。
接下來的幾篇文章,將從如下幾個方面介紹 Redis 的幾種數據結構,命令使用及其應用場景。
預備知識:幾個簡單的 全局命令,數據結構 和 內部編碼,單線程命令 處理機制分析。
數據結構特性:5 種 數據結構 的特點、命令使用、應用場景。
數據管理:鍵管理、遍歷鍵、數據庫管理。
正文
1. 預備知識
在介紹 5 種 數據結構 之前,需要先了解 Redis 的一些 全局命令、數據結構 和 內部編碼、單線程命令處理機制。
Redis 的命令有 上百個,理解 Redis 的一些機制,會發現這些命令有很強的 通用性。
Redis 不是萬金油,有些 數據結構 和 命令 必須在 特定場景 下使用,一旦 使用不當 可能對 Redis 本身 或者 應用本身 造成致命傷害。
2. 全局命令
Redis 有 5 種 數據結構,它們是 鍵值對 中的 值,對于 鍵 來說有一些通用的命令。
2.1. 查看所有鍵
keys *
下面插入了 3 對字符串類型的鍵值對:
127.0.0.1:6379>?set?hello?world?OK?127.0.0.1:6379>?set?java?jedis?OK?127.0.0.1:6379>?set?python?redis-py?OK?復制代碼命令會將所有的鍵輸出:
127.0.0.1:6379>?keys?*?1)?"python"?2)?"java"?3)?"hello"?復制代碼2.2. 鍵總數
dbsize
下面插入一個 列表類型 的 鍵值對(值是 多個元素 組成):
127.0.0.1:6379>?rpush?mylist?a?b?c?d?e?f?g?(integer)?7?復制代碼dbsize 命令會返回當前數據庫中 鍵的總數。
127.0.0.1:6379>?dbsize?(integer)?4?復制代碼dbsize 命令在 計算鍵總數 時 不會遍歷 所有鍵,而是直接獲取 Redis 內置的鍵總數變量,所以 dbsize 命令的 時間復雜度 是 O(1)。而 keys 命令會 遍歷 所有鍵,所以它的 時間復雜度 是 O(n),當 Redis 保存了 大量鍵 時,線上環境 禁止 使用。
2.3. 檢查鍵是否存在
exists key
如果鍵存在則返回 1,不存在則返回 0:
127.0.0.1:6379>?exists?java?(integer)?1?127.0.0.1:6379>?exists?not_exist_key?(integer)?0?復制代碼2.4. 刪除鍵
del key
del 是一個 通用命令,無論值是什么 數據結構 類型,del 命令都可以將其 刪除。
127.0.0.1:6379>?del?java?(integer)?1?127.0.0.1:6379>?exists?java?(integer)?0?127.0.0.1:6379>?del?not_exist_key?(integer)?0?127.0.0.1:6379>?exists?not_exist_key?(integer)?0?復制代碼返回結果為 成功刪除 的 鍵的個數,假設刪除一個 不存在 的鍵,就會返回 0。
2.5. 鍵過期
expire key seconds
Redis 支持對 鍵 添加 過期時間,當超過過期時間后,會 自動刪除鍵,例如為鍵 hello 設置 10 秒過期時間:
127.0.0.1:6379>?set?hello?world?OK?127.0.0.1:6379>?expire?hello?10??(integer)?0?復制代碼ttl 命令會返回鍵的 剩余過期時間,它有 3 種返回值:
大于等于 0 的整數:表示鍵 剩余 的 過期時間。
返回 -1:鍵 沒設置 過期時間。
返回 -2:鍵 不存在。
可以通過 ttl 命令觀察 鍵 hello 的 剩余過期時間:
#?還剩7秒?127.0.0.1:6379>?ttl?hello(integer)??(integer)?7?...?#?還剩1秒?127.0.0.1:6379>?ttl?hello(integer)??(integer)?1?#?返回結果為-2,說明鍵hello已經被刪除?127.0.0.1:6379>?ttl?hello(integer)??(integer)?-2?127.0.0.1:6379>?get?hello?(nil)?復制代碼2.6. 鍵的數據結構類型
type key
例如鍵 hello 是的值 字符串類型,返回結果為 string。鍵 mylist 的值是 列表類型,返回結果為 list。如果鍵不存在,則返回 none。
127.0.0.1:6379>?set?a?b?OK?127.0.0.1:6379>?type?a?string?127.0.0.1:6379>?rpush?mylist?a?b?c?d?e?f?g?(integer)?7?127.0.0.1:6379>?type?mylist?list?復制代碼3. 數據結構和內部編碼
type 命令實際返回的就是當前 鍵 的 數據結構類型,它們分別是:string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合),但這些只是 Redis 對外的 數據結構。如圖所示:
對于每種 數據結構,實際上都有自己底層的 內部編碼 實現,而且是 多種實現。這樣 Redis 會在合適的 場景 選擇合適的 內部編碼,如圖所示:
可以看到,每種 數據結構 都有 兩種以上 的 內部編碼實現。例如 list 數據結構 包含了 linkedlist 和 ziplist 兩種 內部編碼。同時有些 內部編碼,例如 ziplist,可以作為 多種外部數據結構 的內部實現,可以通過 object encoding 命令查詢 內部編碼:
127.0.0.1:6379>?object?encoding?hello?"embstr"?127.0.0.1:6379>?object?encoding?mylist?"quicklist"?復制代碼可以看到鍵 hello 對應值的 內部編碼 是 embstr,鍵 mylist 對應值的 內部編碼 是 ziplist。
Redis 這樣設計有兩個好處:
其一:可以改進 內部編碼,而對外的 數據結構 和 命令 沒有影響。例如 Redis3.2 提供的 quicklist,結合了 ziplist 和 linkedlist 兩者的優勢,為 列表類型 提供了一種 更加高效 的 內部編碼實現。
其二:不同 內部編碼 可以在 不同場景 下發揮各自的 優勢。例如 ziplist 比較 節省內存,但是在列表 元素比較多 的情況下,性能 會有所 下降,這時候 Redis 會根據 配置,將列表類型的 內部實現 轉換為 linkedlist。
4. 單線程架構
Redis 使用了 單線程架構 和 I/O 多路復用模型 來實現 高性能 的 內存數據庫服務。那為什么 單線程 還能這么快,下面分析原因:
4.1. 純內存訪問
Redis 將所有數據放在 內存 中,內存的 響應時長 大約為 100 納秒,這是 Redis 達到 每秒萬級別 訪問的重要基礎。
4.2. 非阻塞I/O
Redis 使用 epoll 作為 I/O 多路復用技術 的實現,再加上 Redis 自身的 事件處理模型 將 epoll 中的 連接、讀寫、關閉 都轉換為 事件,從而不用不在 網絡 I/O 上浪費過多的時間,如圖所示:
4.3. 單線程避免線程切換和競態產生的消耗
采用 單線程 就能達到如此 高的性能,那么不失為一種不錯的選擇,因為 單線程 能帶來幾個好處:
單線程 可以簡化 數據結構和算法 的實現,開發人員不需要了解復雜的 并發數據結構。
單線程 避免了 線程切換 和 競態 產生的消耗,對于服務端開發來說,鎖和線程切換 通常是性能殺手。
單線程 的問題:對于 每個命令 的 執行時間 是有要求的。如果某個命令 執行過長,會造成其他命令的 阻塞,對于 Redis 這種 高性能 的服務來說是致命的,所以 Redis 是面向 快速執行 場景的數據庫。
小結
本文堆 Redis 的幾種 數據結構 進行了概述,介紹了幾個簡單的 全局命令,數據結構 和 內部編碼 以及 單線程命令 處理機制分析。
歡迎工作一到五年的Java工程師朋友們加入Java架構開發:760940986
群內提供免費的Java架構學習資料(里面有高可用、高并發、高性能及分布式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!
轉載于:https://blog.51cto.com/13883927/2294302
總結
以上是生活随笔為你收集整理的深入剖析Redis系列(四) - Redis数据结构与全局命令概述的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: React开发(215):React中的
- 下一篇: Redis 事务 实例