一起來聊聊Redis有什麼優勢和特點

2022-05-16 19:00:27
本篇文章給大家帶來了關於的相關知識,其中主要介紹了關於redis的一些優勢和特點,Redis 是一個開源的使用ANSI C語言編寫、遵守 BSD 協定、支援網路、可基於記憶體、分散式儲存資料庫,下面一起來看一下,希望對大家有幫助。

推薦學習:

什麼是redis

Remote DIctionary Server(Redis) 是一個由 Salvatore Sanfilippo 寫的 key-value 儲存系統,是跨平臺的非關係型資料庫。

Redis 是一個開源的使用 ANSI C 語言編寫、遵守 BSD 協定、支援網路、可基於記憶體、分散式、可選永續性的鍵值對(Key-Value)儲存資料庫,並提供多種語言的 API。

Redis 通常被稱為資料結構伺服器,因為值(value)可以是字串(String)、雜湊(Hash)、列表(list)、集合(sets)和有序集合(sorted sets)等型別。

Redis的特點:

  • 記憶體資料庫,速度快,也支援資料的持久化,可以將記憶體中的資料儲存在磁碟中,重新啟動的時候可以再次載入進行使用。
  • Redis不僅僅支援簡單的key-value型別的資料,同時還提供list,set,zset,hash等資料結構的儲存。
  • Redis支援資料的備份,即master-slave模式的資料備份。
  • 支援事務

Redis的優勢:

  • 效能極高 – Redis能讀的速度是110000次/s,寫的速度是81000次/s 。
  • 豐富的資料型別 – Redis支援二進位制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 資料型別操作。
  • 原子 – Redis的所有操作都是原子性的,同時Redis還支援對幾個操作合併後的原子性執行。(事務)
  • 豐富的特性 – Redis還支援 publish/subscribe, 通知, key 過期等等特性。

Redis與其他key-value儲存有什麼不同?

  • Redis有著更為複雜的資料結構並且提供對他們的原子性操作,這是一個不同於其他資料庫的進化路徑。Redis的資料型別都是基於基本資料結構的同時對程式設計師透明,無需進行額外的抽象。
  • Redis執行在記憶體中但是可以持久化到磁碟,所以在對不同資料集進行高速讀寫時需要權衡記憶體,因為資料量不能大於硬體記憶體。在記憶體資料庫方面的另一個優點是,相比在磁碟上相同的複雜的資料結構,在記憶體中操作起來非常簡單,這樣Redis可以做很多內部複雜性很強的事情。同時,在磁碟格式方面他們是緊湊的以追加的方式產生的,因為他們並不需要進行隨機存取。

Memcache與Redis的區別都有哪些

  1. 儲存方式 Memecache把資料全部存在記憶體之中,斷電後會掛掉,資料不能超過記憶體大小。 Redis有部份存在硬碟上,redis可以持久化其資料
  2. 資料支援型別 memcached所有的值均是簡單的字串,redis作為其替代者,支援更為豐富的資料型別 ,提供list,set,zset,hash等資料結構的儲存
  3. 使用底層模型不同 它們之間底層實現方式 以及與使用者端之間通訊的應用協定不一樣。 Redis直接自己構建了VM 機制 ,因為一般的系統呼叫系統函數的話,會浪費一定的時間去移動和請求。
  4. value 值大小不同:Redis 最大可以達到 512M;memcache 只有 1mb。
  5. redis的速度比memcached快很多
  6. Redis支援資料的備份,即master-slave模式的資料備份。

Redis為什麼這麼快

1、完全基於記憶體,絕大部分請求是純粹的記憶體操作,非常快速。資料存在記憶體中,類似於HashMap,HashMap的優勢就是查詢和操作的時間複雜度都是O(1);

2、資料結構簡單,對資料操作也簡單,Redis中的資料結構是專門進行設計的;

3、採用單執行緒,避免了不必要的上下文切換和競爭條件,也不存在多程序或者多執行緒導致的切換而消耗 CPU,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有因為可能出現死鎖而導致的效能消耗;

4、使用多路I/O複用模型,非阻塞IO;

5、使用底層模型不同,它們之間底層實現方式以及與使用者端之間通訊的應用協定不一樣,Redis直接自己構建了VM 機制 ,因為一般的系統呼叫系統函數的話,會浪費一定的時間去移動和請求;

6.多路 I/O 複用模型

多路I/O複用模型是利用 select、poll、epoll 可以同時監察多個流的 I/O 事件的能力,在空閒的時候,會把當前執行緒阻塞掉,當有一個或多個流有 I/O 事件時,就從阻塞態中喚醒,於是程式就會輪詢一遍所有的流(epoll 是隻輪詢那些真正發出了事件的流),並且只依次順序的處理就緒的流,這種做法就避免了大量的無用操作。

**這裡「多路」指的是多個網路連線,「複用」指的是複用同一個執行緒。**採用多路 I/O 複用技術可以讓單個執行緒高效的處理多個連線請求(儘量減少網路 IO 的時間消耗),且 Redis 在記憶體中運算元據的速度非常快,也就是說記憶體內的操作不會成為影響Redis效能的瓶頸,主要由以上幾點造就了 Redis 具有很高的吞吐量。

那麼為什麼Redis是單執行緒的

我們首先要明白,上邊的種種分析,都是為了營造一個Redis很快的氛圍!官方FAQ表示,因為Redis是基於記憶體的操作,CPU不是Redis的瓶頸,Redis的瓶頸最有可能是機器記憶體的大小或者網路頻寬。既然單執行緒容易實現,而且CPU不會成為瓶頸,那就順理成章地採用單執行緒的方案了(畢竟採用多執行緒會有很多麻煩!)。

Redis 資料型別及命令

Redis 資料類型

1.字串(String)

redis 127.0.0.1:6379> SET rediskey redis
OK
redis 127.0.0.1:6379> GET rediskey
"redis"

2. 雜湊(Hash)

Redis hash 是一個 string 型別的 field(欄位) 和 value(值) 的對映表,hash 特別適合用於儲存物件。

Redis 中每個 hash 可以儲存 232 - 1 鍵值對(40多億)

3. 列表(List)

Redis列表是簡單的字串列表,按照插入順序排序。你可以新增一個元素到列表的頭部(左邊)或者尾部(右邊)

一個列表最多可以包含 232 - 1 個元素 (4294967295, 每個列表超過40億個元素)。

redis 127.0.0.1:6379> LPUSH rediskey redis
(integer) 1
redis 127.0.0.1:6379> LPUSH rediskey mongodb
(integer) 2
redis 127.0.0.1:6379> LPUSH rediskey mysql
(integer) 3
redis 127.0.0.1:6379> LRANGE rediskey 0 10

1) "mysql"
2) "mongodb"
3) "redis"

4. 集合(Set)

Redis 的 Set 是 String 型別的無序集合。集合成員是唯一的,這就意味著集合中不能出現重複的資料。

集合物件的編碼可以是 intset 或者 hashtable。

Redis 中集合是通過雜湊表實現的,所以新增,刪除,查詢的複雜度都是 O(1)。

集合中最大的成員數為 232 - 1 (4294967295, 每個集合可儲存40多億個成員)。

redis 127.0.0.1:6379> SADD rediskey redis
(integer) 1
redis 127.0.0.1:6379> SADD rediskey mongodb
(integer) 1
redis 127.0.0.1:6379> SADD rediskey mysql
(integer) 1
redis 127.0.0.1:6379> SADD rediskey mysql
(integer) 0
redis 127.0.0.1:6379> SMEMBERS rediskey

1) "mysql"
2) "mongodb"
3) "redis"

5. 有序集合(sorted set)

Redis 有序集合和集合一樣也是 string 型別元素的集合,且不允許重複的成員。

不同的是每個元素都會關聯一個 double 型別的分數。redis 正是通過分數來為集合中的成員進行從小到大的排序。

有序集合的成員是唯一的,但分數(score)卻可以重複。

集合是通過雜湊表實現的,所以新增,刪除,查詢的複雜度都是 O(1)。 集合中最大的成員數為 232 - 1 (4294967295, 每個集合可儲存40多億個成員)。

6. HyperLogLog

Redis 在 2.8.9 版本新增了 HyperLogLog 結構。

Redis HyperLogLog 是用來做基數統計的演演算法,HyperLogLog 的優點是,在輸入元素的數量或者體積非常非常大時,計算基數所需的空間總是固定 的、並且是很小的。

在 Redis 裡面,每個 HyperLogLog 鍵只需要花費 12 KB 記憶體,就可以計算接近 2^64 個不同元素的基 數。這和計算基數時,元素越多耗費記憶體就越多的集合形成鮮明對比。

但是,因為 HyperLogLog 只會根據輸入元素來計算基數,而不會儲存輸入元素本身,所以 HyperLogLog 不能像集合那樣,返回輸入的各個元素。

什麼是基數?

比如資料集 {1, 3, 5, 7, 5, 7, 8}, 那麼這個資料集的基數集為 {1, 3, 5 ,7, 8}, 基數(不重複元素)為5。 基數估計就是在誤差可接受的範圍內,快速計算基數。

範例

以下範例演示了 HyperLogLog 的工作過程:

//新增指定元素到 HyperLogLog 中。
redis 127.0.0.1:6379> PFADD rediskey "redis" 

1) (integer) 1

redis 127.0.0.1:6379> PFADD rediskey "mongodb"

1) (integer) 1

redis 127.0.0.1:6379> PFADD rediskey "mysql"

1) (integer) 1
//新增指定元素到 HyperLogLog 中。
redis 127.0.0.1:6379> PFCOUNT rediskey

(integer) 3

7. 釋出訂閱

Redis 釋出訂閱 (pub/sub) 是一種訊息通訊模式:傳送者 (pub) 傳送訊息,訂閱者 (sub) 接收訊息。

Redis 使用者端可以訂閱任意數量的頻道。

下圖展示了頻道 channel1 , 以及訂閱這個頻道的三個使用者端 —— client2 、 client5 和 client1 之間的關係:

imgimg

範例

以下範例演示了釋出訂閱是如何工作的,需要開啟兩個 redis-cli 使用者端。

在我們範例中我們建立了訂閱頻道名為 runoobChat:

第一個 redis-cli 使用者端

redis 127.0.0.1:6379> SUBSCRIBE runoobChat

Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "runoobChat"
3) (integer) 1

現在,我們先重新開啟個 redis 使用者端,然後在同一個頻道 runoobChat 釋出兩次訊息,訂閱者就能接收到訊息。

第二個 redis-cli 使用者端

redis 127.0.0.1:6379> PUBLISH runoobChat "Redis PUBLISH test"
(integer) 1

redis 127.0.0.1:6379> PUBLISH runoobChat "Learn redis by runoob.com"
(integer) 1

# 訂閱者的使用者端會顯示如下訊息
 1) "message"
2) "runoobChat"
3) "Redis PUBLISH test"
 1) "message"
2) "runoobChat"
3) "Learn redis by runoob.com"

gif 演示如下:

  • 開啟本地 Redis 服務,開啟兩個 redis-cli 使用者端。
  • 第一個 redis-cli 使用者端輸入 SUBSCRIBE runoobChat,意思是訂閱 runoobChat 頻道。
  • 第二個 redis-cli 使用者端輸入 PUBLISH runoobChat 「Redis PUBLISH test」 往 runoobChat 頻道傳送訊息,這個時候在第一個 redis-cli 使用者端就會看到由第二個 redis-cli 使用者端傳送的測試訊息。

img

8. 事務

Redis 事務可以一次執行多個命令, 並且帶有以下三個重要的保證:

  • 批次操作在傳送 EXEC 命令前被放入佇列快取。
  • 收到 EXEC 命令後進入事務執行,事務中任意命令執行失敗,其餘的命令依然被執行。
  • 在事務執行過程,其他使用者端提交的命令請求不會插入到事務執行命令序列中。

一個事務從開始到執行會經歷以下三個階段:

  • 開始事務。
  • 命令入隊。
  • 執行事務。

範例

以下是一個事務的例子, 它先以 MULTI 開始一個事務, 然後將多個命令入隊到事務中, 最後由 EXEC 命令觸發事務, 一併執行事務中的所有命令:

redis 127.0.0.1:6379> MULTI
OK

redis 127.0.0.1:6379> SET book-name "Mastering C++ in 21 days"
QUEUED

redis 127.0.0.1:6379> GET book-name
QUEUED

redis 127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series"
QUEUED

redis 127.0.0.1:6379> SMEMBERS tag
QUEUED

redis 127.0.0.1:6379> EXEC
1) OK
2) "Mastering C++ in 21 days"
3) (integer) 3
4) 1) "Mastering Series"
   2) "C++"
   3) "Programming"

單個 Redis 命令的執行是原子性的,但 Redis 沒有在事務上增加任何維持原子性的機制,所以 Redis 事務的執行並不是原子性的。

事務可以理解為一個打包的批次執行指令碼,但批次指令並非原子化的操作,中間某條指令的失敗不會導致前面已做指令的回滾,也不會造成後續的指令不做。

這是官網上的說明 From redis docs on transactions:

It’s important to note that even when a command fails, all the other commands in the queue are processed – Redis will not stop the processing of commands.

比如:

redis 127.0.0.1:7000> multi
OK
redis 127.0.0.1:7000> set a aaa
QUEUED
redis 127.0.0.1:7000> set b bbb
QUEUED
redis 127.0.0.1:7000> set c ccc
QUEUED
redis 127.0.0.1:7000> exec
1) OK
2) OK
3) OK

如果在 set b bbb 處失敗,set a 已成功不會回滾,set c 還會繼續執行。

9. 指令碼

Redis 指令碼使用 Lua 直譯器來執行指令碼。 Redis 2.6 版本通過內嵌支援 Lua 環境。執行指令碼的常用命令為 EVAL

redis 127.0.0.1:6379> EVAL "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second

1) "key1"
2) "key2"
3) "first"
4) "second"

10 GEO

Redis GEO 主要用於儲存地理位置資訊,並對儲存的資訊進行操作,該功能在 Redis 3.2 版本新增。

Redis GEO 操作方法有:

  • geoadd:新增地理位置的座標。
  • geopos:獲取地理位置的座標。
  • geodist:計算兩個位置之間的距離。
  • georadius:根據使用者給定的經緯度座標來獲取指定範圍內的地理位置集合。
  • georadiusbymember:根據儲存在位置集合裡面的某個地點獲取指定範圍內的地理位置集合。
  • geohash:返回一個或多個位置物件的 geohash 值。
redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
redis> GEODIST Sicily Palermo Catania
"166274.1516"
redis> GEORADIUS Sicily 15 37 100 km
1) "Catania"
redis> GEORADIUS Sicily 15 37 200 km
1) "Palermo"
2) "Catania"
redis>

11 Redis Stream

Redis Stream 是 Redis 5.0 版本新增加的資料結構。

Redis Stream 主要用於訊息佇列(MQ,Message Queue),Redis 本身是有一個 Redis 釋出訂閱 (pub/sub) 來實現訊息佇列的功能,但它有個缺點就是訊息無法持久化,如果出現網路斷開、Redis 宕機等,訊息就會被丟棄。

簡單來說釋出訂閱 (pub/sub) 可以分發訊息,但無法記錄歷史訊息。

而 Redis Stream 提供了訊息的持久化和主備複製功能,可以讓任何使用者端存取任何時刻的資料,並且能記住每一個使用者端的存取位置,還能保證訊息不丟失。

Redis Stream 的結構如下所示,它有一個訊息連結串列,將所有加入的訊息都串起來,每個訊息都有一個唯一的 ID 和對應的內容:

img

每個 Stream 都有唯一的名稱,它就是 Redis 的 key,在我們首次使用 xadd 指令追加訊息時自動建立。

上圖解析:

  • Consumer Group :消費組,使用 XGROUP CREATE 命令建立,一個消費組有多個消費者(Consumer)。
  • last_delivered_id :遊標,每個消費組會有個遊標 last_delivered_id,任意一個消費者讀取了訊息都會使遊標 last_delivered_id 往前移動。
  • pending_ids :消費者(Consumer)的狀態變數,作用是維護消費者的未確認的 id。 pending_ids 記錄了當前已經被使用者端讀取的訊息,但是還沒有 ack (Acknowledge character:確認字元)。

Redis 管道技術

Redis是一種基於使用者端-伺服器端模型以及請求/響應協定的TCP服務。這意味著通常情況下一個請求會遵循以下步驟:

  • 使用者端向伺服器端傳送一個查詢請求,並監聽Socket返回,通常是以阻塞模式,等待伺服器端響應。
  • 伺服器端處理命令,並將結果返回給使用者端。

Redis 管道技術

Redis 管道技術可以在伺服器端未響應時,使用者端可以繼續向伺服器端傳送請求,並最終一次性讀取所有伺服器端的響應。

推薦學習:

以上就是一起來聊聊Redis有什麼優勢和特點的詳細內容,更多請關注TW511.COM其它相關文章!