redis介紹
redis 是開源的,基于內存的數據存儲系統,可以用作數據庫、緩存和消息中間件。
redis支持多種數據存儲結構,包括string, hashes, lists, sets, sorted sets。
通過復制、持久化和數據分片等特性,可以很方便地將redis擴展成一個能夠包好數百GB、每秒處理上百萬次請求的系統。
持久化
對于基于內存存儲的數據庫,一個很重要的問題是,服務器關閉時,數據的安全性問題。redis有兩種持久化方案,保證了數據的安全性。
RDB
RDB是一種按照指定時間周期定期保存redis數據鏡像到一個單文件中的持久化方式。
非常適用于用作容災備份,因為RDB文件可以傳輸至不同地方備份,且服務器能夠很快地從RDB文件中恢復數據。
但是RDB方式不適用于對數據丟失方案容忍度很低的場景,因為按周期備份數據鏡像,盡管周期可以設置得很短,但是仍然有丟失數據的風險。AOF
該方式能夠以AOF文件的方式,保存每次對redis的數據修改。AOF文件是一個只允許追加的log文件,所以沒有查找帶來的性能消耗。當文件過大時,redis能夠自動重新AOF文件(合并部分同類操作INCR A 1, INCR A 1 --> INCR A 2).
redis的基本數據結構簡介
1. string
redis的string可以存儲以下三種類型的值:
- 字節串(byte string)
- 整數
- 浮點數
當執行set key value命令時,redis檢測到value值可以轉化為整數或者浮點數,會更改其數據類型,使其支持對整數和浮點數的特殊操作,如自增和自減INCR, INCRBY
等操作,redis的強大之處還在于其支持對字符串的截取和二進制為操作。
命令 | 行為 |
---|---|
GET | 獲取存儲在給定間中的值 |
SET | 設置存儲在給定鍵中的值 |
DEL | 刪除 |
APPEND | 在指定鍵末尾追加 |
INCR | 增加1(對于int類型) |
2. list
Redis的列表允許用戶從序列的==兩端==推入或者彈出元素、獲取元素,執行各種常見的列表操作,如獲取子列表。
3. set
集合以==無序==的方式來存儲多個各不相同的元素,用戶可以快速地對集合執行添加元素、移除元素以及檢查一個元素是否存在于集合里的操作。
并且可以對多個set進行差集、交集、并集計算。
4. hash
散列可以讓用戶將多個鍵值對存儲到一個Redis鍵里面。從功能上來說,Redis為散列值提供了一些和字符串值相同的特性,使得散列非常適用于將一些相關的數據存儲在一起。我們可以把這種數據聚集看作是關系==數據庫中的行==,或者==文檔存儲中的文檔==。
5. sort set
有序集合存儲著==成員與分值之間的映射==,并且提供了分值處理命令,以及根據分值大小有序地獲取(fetch)或掃描(scan)成員和分值的命令。
6. 發布&訂閱
訂閱者(listener)訂閱頻道(channel),發送者(sender)想頻道發送二進制字符串消息。每當有消息發送至指定頻道時,頻道的所有訂閱者都會收到消息。
命令 | 行為 |
---|---|
SUBSCRIBE | SUBSCRIBE channel [channel ...] ——訂閱給定的一個或多個頻道 |
UNSUBSCRIBE | UNSUBSCRIBE [channel [channel ...]]——退訂給定的一個或多個頻道,如果未指定頻道,則退訂所以頻道 |
publis | PUBLISH channel message ——向給定頻道發送消息 |
PSUBSCRIBE | PSUBSCRIBE pattern [pattern ...] ——訂閱與給定模式想匹配的所有頻道 |
PUNSUBSCRIBE | PUNSUBSCRIBE [pattern ...]——退訂給定模式 |
事務
MULTI, EXEC, DISCARD & WATCH作為redis事務的基本命令,允許原子性地執行一組redis操作。
- 保證所有事務內的命令將會串行順序執行,保證不會在事務的執行過程中被其他客戶端打斷。不同于關系型數據庫的事務概念,redis保證會在執行完畢上一個事務的所有命令后才會處理其他客戶端的命令。
- 事務內的命令全部執行或一個都不執行。
> MULTI
OK
> INCR foo
QUEUED
> INCR bar
QUEUED
> EXEC
1) (integer) 1
2) (integer) 1
-
事務運行中出錯
- 在執行EXEC調用前出錯,如語法錯誤、out of memmeroy錯誤。如果命令入隊是返回QUEUED,則入隊成功;否則入隊失敗,客戶端會停止并取消該事務。
- 執行EXEC調用后出錯,如對string類型的鍵調用了list類型的操作。==對于此類錯誤,redis并未進行特殊處理,即使事務中某些命令產生了此類錯誤,事務中的其他命令仍會繼續執行下去。此特性有別于傳統關系型數據庫的事務概念。== 簡而言之,redis不支持事務回滾。
MULTI
+OK
SET a 3
abc
+QUEUED
LPOP a
+QUEUED
INCR a
EXEC
*3
+OK
-ERR Operation against a key holding the wrong kind of value
(integer) 4
為什么redis不支持事務回滾
redis命令只會因為語法錯誤而失敗,在事務命令入隊時就能檢查到該錯誤;或者錯誤運用了鍵的命令。這就是說,失敗的命令是有編程錯誤造成的,這些錯誤應該在開發過程中被發現,不應該出現在生產環境中。
因此不需要支持回滾,是redis內部保持了簡單和快速高效。
PS: 使用事務主要是為了:移除競爭條件。從事務的特性我們知道,redis的事務能夠保證事務內的所有命令在不被其他客戶端打斷的情況下順序執行。
redis沒有實現傳統關系型數據庫的select ... for update的悲觀鎖
悲觀鎖加鎖會造成客戶端競爭條件的長時間等待,所以為了盡可能減少客戶端等待時間,redis未實現for update的悲觀鎖機制。
而是通過watch命令,檢測某值是否被搶先修改,并在發生時給客戶端返回錯誤。該機制類似于關系型數據庫中根據版本號實現的樂觀鎖機制。
通過配置主從復制來提升redis的讀性能
redis復制
復制可以讓其他服務器擁有一個不斷更新的數據副本,擴展系統的讀請求處理能力。
從服務器連接住服務器時的步驟
步驟序列 | 主服務器操作 | 從服務器操作 |
---|---|---|
1 | 等待命令進入 | 連接主服務器,發送SYNC同步命令 |
2 | 開始I執行BGSAVE,備份數據副本,在此期間使用緩沖區記錄BGSAVE之后執行的所以命令 | 根據配置選項決定是繼續使用現有數據(if has)來處理客戶端的命令請求,還是想發送請求的客戶端返回錯誤 |
3 | BGSAVE執行完畢,想從服務器發送快照文件,并在發送期間繼續使用緩沖區記錄被執行的命令 | 丟棄所有舊數據(if has),開始載入主服務器發來的快照 |
4 | 快照文件發送完畢,開始想從服務器發送存儲在緩沖區里面的寫命令 | 完成對快照文件的解釋,開始正常接受命令請求 |
5 | 緩沖區存儲的寫命令發送完畢,此后每執行一個寫命令,就行從服務器發送相同的寫命令 | 執行主服務器發來的所有存儲在緩沖區的寫命令;此后,接收并執行主服務器傳來的每個寫命令 |
從服務器在進行同步是,會清空自身原本數據。
redis不支持主主復制
當多個從服務器嘗試鏈接同一個主服務器的時候:
- 當上表步驟3尚未執行時,所有服務器都會接受到相同的快照文件和相同的緩沖區寫命令
- 當步驟3正在執行或者已經執行完畢,新連接的從服務器會重新執行一遍步驟1-5
主從鏈
redis可以組成如下圖所示的主從鏈。
因為redis的復制會占用主服務器的網絡和其他開銷,如果一個主服務器需要同步太多的從服務器時,可能會造成主服務器不可用,所以可以組成如下所示的主從鏈樹狀結構,用以在提升整體讀性能的前提下,減輕主服務器的同步開銷。
redis集群
參考資料
https://redis.io/
http://redisdoc.com
《Redis實戰》