一. memcache和Redis的區別
二. 爲什麼Redis那麼快?
- 完全基於內存,絕對部分請求是純粹的內存操作。
- 數據結構結構簡單,對數據操作也簡單。不使用表,不需要對多個表進行關聯,存儲結構是鍵值對,查找速度比較快.
- redis採用單線程(並不是說redis server也是單線程!), 天然的不會出現同步問題,鎖競爭,線程切換等額外開銷。而之所以使用單線程是因爲,cpu並不是限制redis性能的瓶頸,真正的瓶頸依然是磁盤,網路的IO帶寬。並且,又多線程需求時,可以開啓多個redis來完成對應的需求。
- 使用多路IO複用模型,非阻塞IO
三. 數據類型
數據類型 | 可以存儲的值 | 操作 |
---|---|---|
STRING | 字符串、整數或者浮點數 | 對整個字符串或者字符串的其中一部分執行操作 對整數和浮點數執行自增或者自減操作 |
LIST | 列表 | 從兩端壓入或者彈出元素 對單個或者多個元素進行修剪, 只保留一個範圍內的元素 |
SET | 無序集合 | 添加、獲取、移除單個元素 檢查一個元素是否存在於集合中 計算交集、並集、差集 從集合裏面隨機獲取元素 |
HASH | 包含鍵值對的無序散列表 | 添加、獲取、移除單個鍵值對 獲取所有鍵值對 檢查某個鍵是否存在 |
ZSET | 有序集合 | 添加、獲取、刪除元素 根據分值範圍或者成員來獲取元素 計算一個鍵的排名 |
四. Redis的使用場景
4.1. 從海量Key裏查詢出某一固定前綴的Key
kyes pattern: 查找所有符合給定模式pattern的key
- 一次性返回所有匹配的key
- 鍵的數量過大會使服務卡頓
可以使用scan cursor [Match pattern][COUNT count]
:
- 基於遊標的迭代器,需要基於上一次的遊標延續之前的迭代過程。
- 以0作爲遊標開始一次新的迭代,直到命令返回遊標0完成一次遍歷。
- 不保證每次執行都返回給定數量的元素(count數大於key總數的時候)一次返回數量不可控,只能是大概率符合count。
- 支持模糊查詢,即能夠返回滿足pattern匹配的key
例如:scan 0 match k1* count 10
,注意,返回的值有可能的是重複的! 因此需要去重!(例如寫程序的時候用hashset)
blpop
4.2. 如何通過Redis實現分佈式鎖
即分佈式系統中,訪問共同資源時的一種鎖的實現。
在分佈式場景下,無法使用單機環境下的鎖來對多個節點上的進程進行同步。
可以使用 Redis 自帶的 SETNX 命令實現分佈式鎖,setnx key val 就是如果不存在key的話,那麼就設置key爲val。設置成功返回1, 失敗返回0
SET lock_key random_value NX PX 5000
一定要放到一個語句裏,保證“獲取鎖”和“設置超時時間”的原子性。如果設置完setnx以後,程序就掛掉了,那麼這個key(鎖)就一直被佔用!
4.3. 使用Redis做異步隊列
除了使用list的rpush, lpop, blpop 以外,可以用pub/sub:主題訂閱者模式,來做。
例子:
- 訂閱一個頻道:
- redis-cli1:
subscribe myTopic
,之後進入監聽狀態 - redis-cli2:
subscribe myTopic
,之後進入監聽狀態 - redis-cli3:
subscribe myTopic
,之後進入監聽狀態 - redis-cli4:
publish myTopic "hello!!"
:- 這條消息發送出去之後,監聽myTopic的3個客戶端都收到了“hello!!”這個字符串。
- redis-cli1:
缺點:
但需要注意的是,消息的發佈是無狀態的,也就是無法保證可達。對於發佈者來說,消息是即發即失的。 若想解決這個問題,需要用專業的消息隊列,如kafka,rocketmq等。
五、Redis如何做持久化
5.1. RDB ( 快照 ) 持久化:保存某一個時間點的全數據快照.
redis服務器加載時,會啓用reids.conf文件中的配置信息,裏面的:
....
save 900 1 # 就是900秒內如果有1條是寫入指令,那麼就觸發一次快照
save 300 10
save 60 10000
...
stop-writes-on-bgsave-error yes #當設置成yes,
# 就是備份進程若出錯了,則主進程就停止
# 接受新的寫入操作, 這是爲了保證數據一致性!
....
可以根據不同的情況來合理配置。 src
目錄下的dump.rdb
文件,就是redis系統定期備份的rdb文件. 它是一個二進制文件。
5.1.1 生成RDB備份文件的方式:
-
主動生成
- SAVE: 阻塞Redis的服務器進程,直到RDB文件被創建完畢。 很少被使用,因爲佔用了主線程!! 主線程是用來處理client的請求的!!
- BGSAVE:Fork一個子進程創建RBD文件,不阻塞服務器進程!此時,主進程依然繼續工作,子進程將內存中的數據寫入臨時文件中,因爲copy-on-write的機制,父子進程此時會共享相同的物理頁面,當(主)父進程處理寫請求時,os會爲父進程要寫的頁面創建一個副本(這個副本用於備份),而不是寫入共享的頁面! RDB文件的載入,一般情況下是自動的,redis服務器啓動時,若檢測到rdb文件的存在,那麼會載入這個文件
在fork時,子進程和父進程共享同一塊資源空間,只有當父進程對此空間進行修改時,纔會觸發給子進程的資源複製,這一機制爲copy-on-write. ,juc的copyOnWriteArrayList也是使用的這一原理。
-
被動生成
- 根據redis.conf裏的save m n 定時觸發 (用的是BGSAVE)
- 主從複製時,主節點自動觸發(主節點發送rdb文件給從結點,這時,主節點會觸發一次!)
- 執行debug reload
- 執行shutdown且沒有開啓AOF持久化,那麼會觸發一次RDB持久化
RDB持久化的缺點:
- 內存數據的全部同步! 數據量大的時候會因爲IO而嚴重影響性能!
- 可能會因爲redis掛掉而丟失從當前到最近一次備份期間的所有數據!
5.2 AOF ( Append-Only-File )持久化:保存寫狀態
- 記錄下除了查詢以外的所有變更數據庫狀態的指令
- 以append的形式追加保存到AOF文件中
- AOF持久化默認是關閉的,可以修改redis.conf來讓其生效:
- appendonly yes # 啓動 aof
- appendfsync everysec/always/no:
- always: 一旦緩存區發生改變,就立刻將內容寫到文件中!
- everysec: 每隔1s,寫入一次
- no: 什麼時候寫交給os判斷, 一般是等緩存區寫滿了就寫入一次。
日誌重寫解決AOF文件大小不斷增大的問題(例如100條incr 可以用一條add 100實現), 其原理如下:
- 調用fork(), 創建一個子進程。
- 子進程把新的AOF寫到一個臨時文件裏,新的AOF是根據內存數據生成對應的命令,並不需要區依賴原來的AOF文件。
- 主進程持續將新的變動寫到內存中,並更新到“舊”的AOF文件裏。
- 重寫結束之後,會給主進程一個信號,然後把內存的buff追加到新生成的AOF文件。
- 用新的AOF替換掉舊的AOF。
5.3 從Redis中恢復數據
其實只要重啓就可以了。。
- 檢查AOF是否存在,若存在則直接加載AOF,不再去找RDB
- 若不存在AOF,則嘗試加載RDB
5.4 RDB和AOF的優缺點
-
RDB優點:創建RDB那一瞬間的全部內存數據快照,文件小,恢復快
-
RDB缺點:無法保存最近一次快照之後的數據
-
AOF優點:可讀性高,適合保存增量數據,數據不易丟失
-
AOF缺點:文件體積大,恢復時間長
5.5 redis 4.0之後的備份就是混合模式,即RDB-AOF.
rdb用於全量備份,aof用於增量備份,爲redis4.0之後的默認備份方式。
bgsave做全量持久化,aof做增量持久化
六、Redis主從同步
主從同步原理
redis的一個Master用於寫操作,其他的Slave都是用於讀操作。每一個Master和Slave都是一個Redis server實例。期間只保證主從的最終一致性!
主從同步分爲全同步和增量同步。
-
全同步過程(上圖中的1,2,3,4)
- Salve發送sync命令給Master請求同步
- Master進行一次BGSAVE(注意,如果是diskless模式的話,可以不用在本地生成rdb,參考)
- 在進行BGSAVE期間,將所有寫操作命令保存至緩存區中。
- Slave得到Master發送的rdb文件之後進行數據載入。
- Master再將期間生成的增量寫命令發送給slave端。
-
增量同步(上圖中的5):
-
Master接受到用戶的操作命令,如果是寫命令,就先將操作記錄追加到AOF文件中;然後確定將此條寫命令傳給哪些Salve,然後往響應緩存中寫入這條指令。最後將緩存中的數據發送給Slave。(注意,這裏並不是收到一條就發送一條,因爲需要保證的是最終一致性!)
七、Redis哨兵
但Redis這種主從結構,如果Master服務器當機了,那就全完了。。因此,解決主從同步Master宕機後的主從切換問題: 哨兵模式(Redis Sential)
Redis Sential
Redis Sential是redis官方提供的集羣管理工具,其本身也是個獨立運行的進程,提供以下幾點服務:
- 監控:檢查主從服務器是否運行正常
- 提醒:當被監控的某個redis服務器出現問題時,sential通過API向管理員或其他應用程序發送故障通知
- 自動故障遷移:主從切換(主服務器掛了以後,將一個Salve服務器升級成Master服務器,做的事情包括:通知之前的Slave已經修改了Master並告訴新的Master是哪個,當用戶發送請求到來時,會返回一個通知,幷包括新的Master的地址,使得集羣能夠正常運行)