一、Redis數據庫
我們都知道Redis是基於內存的數據庫,數據是以key-value鍵值對的方式存儲的,那么key-value鍵值對是隨意放在內存中的么,其實Redis的服務會創建很多的數據庫空間,這些key-value鍵值對都是在各個數據庫空間中存儲的。
當我們使用客戶端工具鏈接Redis服務時,會在客戶端中看到一系列的db*命名的項(如圖),這些就是一個個數據庫,Redis初始化創建16個數據庫,數據庫創建個數可以在配置文件中修改。
而在命令行模式中是看不到這些數據庫的具體數量的,但在命令行提示符的右側會提示我們當前處於哪個數據庫(如圖),並且可以用上一章說到的SELECT命令進行數據庫的切換;客戶端默認連接第一個數據庫,即0號數據庫。
(1)數據庫鍵空間
key-value鍵值對存儲在各個數據庫中,而每個數據庫內部都是由一個redisDb結構,結構中有若干個屬性,最主要的有兩個屬性dict、expires。
1 typedef struct redisDb { 2 // ... 3 // 數據庫鍵空間,保存着數據庫中的所有鍵值對 4 dict *dict; 5 6 // 過期字典,保存着鍵的過期時間 7 dict *expires; 8 // ... 9 } redisDb;
-
- dict 是字典結構,存儲我們的key-value鍵值對,這個字典稱為數據庫鍵空間,字典的鍵就是數據庫的鍵,每個鍵都是一個字符串,存儲key值;字典的值就是數據庫的值,每個值都可以是五大對象中任意一種,存儲value值;所以我們存儲的key-value最終是在數據庫中以字典的結構存儲的。
- expires 同樣是字典結構,但其存儲的是key-value過期時間;當我們設置了key-value的過期時間,那么key-value存儲在dict字典中,而過期時間則存儲在expires中;字典的鍵存儲key,字典的值存儲過期時間;這里需要注意的是,無論設置的過期時間是秒還是毫秒,最終存儲時都會轉換為unix毫秒時間戳。
圖中是帶有過期字典的數據庫例子
(2)持久化
上面說道的無論是數據庫還是期內的數據都是存儲在服務器內內存中的,如果服務器一旦發生掉電,進程退出等情況,那么其內存中的數據就都消失不見了,在我們大規模並發的項目下,顯然這是災難性的,所以應對這種情況的辦法之一,就是持久化,把內存中的數放到磁盤中,意外發生后,能夠從磁盤上進行數據恢復到內存中,這樣就避免了數據丟失。
Redis提供了兩種持久化方式RDB持久化和AOF持久化。
2、RDB持久化
RDB持久化是最直接的持久化方式,直接將內存中的數據保存到RDB文件中,當恢復時也是直接從RDB文件中恢復;
- RDB文件是經過壓縮的二進制文件,這里對文件結構不做詳解。
- RDB持久化可以手動執行,也可以設置定期執行。
- RDB持久化命令有兩個SAVE(同步)和BGSAVE(異步),同步持久化過程中,會拒絕客戶端的所有請求;異步則是創建子進程執行,不會對客戶端產生影響,具體可以看上一章的命令介紹。
自動間隔性保存
因為BGSAVE命令是異步執行,不會阻塞服務器,所以Redis允許用戶自行配置SAVE選項,當選項觸發時自動執行BGSAVE命令。
當用戶開啟了觸發自動BGSAVE后,如果不配置save選項,服務器會使用默認設置,如下:
(1)在900秒內,對數據庫進行了至少1次修改。
(2)在300秒內,對數據庫進行了至少10次修改。
(3)在60秒內,對數據庫進行了至少10000次修改。
以上三個條件,滿足任意一條,就會進行BGSAVE操作
3、AOF持久化
AOF持久化與RDB不同,AOF持久化是通過記錄服務器所執行的命令來保存數據的。
-
- 被寫入AOF文件的所有命令都是以Redis請求協議格式保存的。
- 數據的還原,就是通過讀取AOF文件的這些命令進行的。
- 執行的命名並不是直接寫入AOF文件的,而是先寫入緩沖區,沒執行一條命令就會追加到緩沖區的末尾,當一條命令執行完成后,返回數據前,會將緩沖區的數據寫入到AOF文件中。
AOF文件的載入與還原
AOF持久化的數據還原過程就是讀取AOF中命令重新執行命令的過程。
(1)Redis會創建一個偽客戶端,偽客戶端與真實的客戶端執行命令的效果是一樣的,只是不帶網絡連接。
(2)從AOF文件分析並讀取一條命令。
(3)偽客戶端執行這條命令。
(4)重復2和3過程,知道AOF文件中的所有命令處理完成。
AOF文件重寫
AOF文件的持久化是記錄被執行對的命令,這樣隨着時間越來越長,AOF文件中的內容會越來越多,體積也會越來越大,文件越大恢復數據的時間也越多。
在命令執行的過程中有些鍵值對被刪除了,有些被修改了,而這些過程命令是完全沒有必要再執行一遍的,所以Redis提供了AOF文件的重寫功能對AOF進行重建,使用重建后的文件要比元AOF文件體積小很多。
-
- AOF文件重寫,並不需要對原AOF文件進行任何訪問改動,他是通過對數據庫內的數據讀取來操作的,即查看數據庫內有什么數據,然后根據數據類型進行創建這些數據的寫入命令。
- AOF文件重寫過程中,創建寫入命令時會先檢查元素數量,如果數量超過了redis.h/REDIS_AOF_REWRITE_ITEMS_PER_CMD=64常量的值,就會分成多條命令,
- AOF文件重寫是有子進程進行的,並不影響主進程處理命令;子進程而不是線程,因為進程帶有數據副本,不鎖數據的情況下,能保證安全。
- AOF文件子進程重寫過程中,主進程仍然在處理數據,這樣造成了子進程和主進程的數據不一致,子進程數據少了一部分,這種情況下Redis會創建一個AOF重寫緩沖區;這樣少的那部分命令會寫到AOF重寫緩沖區中,重寫完成后,再把緩沖區這些命令寫進新的AOF文件中,然后用新的AOF文件替換就得AOF文件。
4、總結
- Redis初始化會創建一批數據庫,每個數據庫的內部數據結構都是字典,key-value的最終存儲也會落到字典上。
- AOF持久化比RDB持久化頻率更高、速度更快;當有AOF持久化時,RDB持久化命令不會再執行;但當RDB持久化命令執行時,AOF命令會等待其執行完成后再執行,而其他RDB命令不會執行。
- AOF文件重寫過程不會影響舊的AOF文件,即便AOF重寫過程失敗,也不會干擾原來的AOF恢復數據,只有在成功之后才會替換原來的文件。
參考:
《Redis設計與實現》黃健宏著,網上對Redis的詳解等
此博客為筆者使用redis很久之后,參考網絡上各類文章總結性書寫,原創手打,如有錯誤歡迎指正。