原文連接:深刻學習Redis(2):持久化html
Redis的5種對象類型(字符串、哈希、列表、集合、有序集合)redis
查看內存方法:info memory數據庫
內存碎片是Redis在分配、回收物理內存過程當中產生的。例如,若是對數據的更改頻繁,並且數據之間的大小相差很大,可能致使redis釋放的空間在物理內存中並無釋放,但redis又沒法有效利用,這就造成了內存碎片。內存碎片不會統計在used_memory中。安全
內存碎片的產生與對數據進行的操做、數據的特色等都有關;此外,與使用的內存分配器也有關係:若是內存分配器設計合理,能夠儘量的減小內存碎片的產生。後面將要說到的jemalloc便在控制內存碎片方面作的很好。服務器
解決內存碎片:若是Redis服務器中的內存碎片已經很大,能夠經過安全重啓的方式減少內存碎片:由於重啓以後,Redis從新從備份文件中讀取數據,在內存中進行重排,爲每一個數據從新選擇合適的內存dan元,減少內存碎片。網絡
jemalloc做爲Redis的默認內存分配器,在減少內存碎片方面作的相對比較好。jemalloc在64位系統中,將內存空間劃分爲小、大、巨大三個範圍;每一個範圍內又劃分了許多小的內存塊單位;當Redis存儲數據時,會選擇大小最合適的內存塊進行存儲。app
jemalloc劃分的內存dan元以下圖所示:負載均衡
在Redis中,實現高可用的技術主要包括持久化、複製、哨兵和集羣,下面分別說明它們的做用,以及解決了什麼樣的問題。函數
持久化的功能:Redis是內存數據庫,數據都是存儲在內存中,爲了不進程退出致使數據的永久丟失,須要按期將Redis中的數據以某種形式(數據或命令)從內存保存到硬盤;當下次Redis重啓時,利用持久化文件實現數據恢復。除此以外,爲了進行災難備份,能夠將持久化文件拷貝到一個遠程位置。性能
Redis持久化分爲RDB持久化和AOF持久化:前者將當前數據保存到硬盤,後者則是將每次執行的寫命令保存到硬盤(相似於MySQL的binlog);因爲AOF持久化的實時性更好,即當進程意外退出時丟失的數據更少,所以AOF是目前主流的持久化方式,不過RDB持久化仍然有其用武之地。
將當前進程中的數據生成快照保存到硬盤(所以也稱做快照持久化),保存的文件後綴是rdb;當Redis從新啓動時,能夠讀取快照文件恢復數據。
手動觸發:save命令和bgsave命令均可以生成RDB文件。
save命令會阻塞Redis服務器進程,直到RDB文件建立完畢爲止,在Redis服務器阻塞期間,服務器不能處理任何命令請求(save基本被廢棄)。而bgsave命令會建立一個子進程,由子進程來負責建立RDB文件,父進程(即Redis主進程)則繼續處理請求。
自動觸發:自動觸發最多見的狀況是在配置文件中經過save m n,指定當m秒內發生n次變化時,會觸發bgsave。
Redis的save m n,是經過serverCron函數、dirty計數器、和lastsave時間戳來實現的。
serverCron是Redis服務器的週期性操做函數,默認每隔100ms執行一次;該函數對服務器的狀態進行維護,其中一項工做就是檢查 save m n 配置的條件是否知足,若是知足就執行bgsave。
dirty計數器是Redis服務器維持的一個狀態,記錄了上一次執行bgsave/save命令後,服務器狀態進行了多少次修改(包括增刪改);而當save/bgsave執行完成後,會將dirty從新置爲0。
lastsave時間戳也是Redis服務器維持的一個狀態,記錄的是上一次成功執行save/bgsave的時間。
RDB載入:
RDB文件的載入工做是在服務器啓動時自動執行的,並無專門的命令。可是因爲AOF的優先級更高,所以當AOF開啓時,Redis會優先載入AOF文件來恢復數據;只有當AOF關閉時,纔會在Redis服務器啓動時檢測RDB文件,並自動載入。服務器載入RDB文件期間處於阻塞狀態,直到載入完成爲止。
因爲須要記錄Redis的每條寫命令,所以AOF不須要觸發,下面介紹AOF的執行流程。
AOF的執行流程包括:
文件重寫是指按期重寫AOF文件,減少AOF文件的體積。須要注意的是,AOF重寫是把Redis進程內的數據轉化爲寫命令,同步到新的AOF文件;不會對舊的AOF文件進行任何讀取、寫入操做!
文件重寫之因此可以壓縮AOF文件,緣由在於:
AOF重寫過程:
僞客戶端:由於Redis的命令只能在客戶端上下文中執行,而載入AOF文件時命令是直接從文件中讀取的,並非由客戶端發送;所以Redis服務器在載入AOF文件以前,會建立一個沒有網絡鏈接的客戶端,以後用它來執行AOF文件中的命令,命令執行的效果與帶網絡鏈接的客戶端徹底同樣。
RDB持久化
AOF持久化
父進程經過fork操做能夠建立子進程,子進程建立後,父子進程共享代碼段,不共享進程的數據空間,可是子進程會得到父進程的數據空間的副本。在操做系統fork的實際實現中,基本都採用了寫時複製技術,即在父/子進程試圖修改數據空間以前,父子進程實際上共享數據空間;可是當父/子進程的任何一個試圖修改數據空間時,操做系統會爲修改的那一部分(內存的一頁)製做一個副本。雖然fork時,子進程不會複製父進程的數據空間,可是會複製內存頁表(頁表至關於內存的索引、目錄);父進程的數據空間越大,內存頁表越大,fork時複製耗時也會越多。
若是Redis單機內存達到了10GB,fork時耗時可能會達到百毫秒級別