若是想要運行一個內存高效的redis數據庫,首先要理解那些在 redis.conf 配置文件中全部內存相關的指令。node
redis.conf 爲大多數指令提供了豐富的內聯文檔,大多數redis配置指令能夠在運行時經過CONFIG SET進行設置。redis
rdbchecksum ,默認是yes,將65位循環冗餘校驗碼(CRC64)放置在RDB快照文件的末尾,做爲防止文件損壞的一種手段。當redis產生一個子進程將快照保存至磁盤時,對RDB快照進行CRC64校驗會增長10%的內存使用。算法
redis中的主哈希表將主鍵與對應的值進行關聯,若activerehashing=yes,那麼該主哈希表每一個100毫秒會從新哈希。從新哈希的過程將釋放刪除了的鍵佔用的操做系統內存。activerehashing 發生在非工做時間,對客戶端鏈接額影響最小。數據庫
採用主從複製的方式提供高度可靠性、可伸縮性。在集羣環境中,經過slave-of 指令將redis實例切換到從模式,此時 從實例 被容許從另外一個被指派爲主實例的redis中複製數據。內存 和 來自硬件和網絡的延遲會直接影響主從實例的性能。數組
repl-disable-tcp-nodelay 指令能夠用來更好地處理redis主從實例間的網絡流量擁塞。經過對主從間的密集數據同步和更少的網絡流量之間進行權衡,這種複製可以改善高流量狀況下的網絡性能。緩存
在redis.io網站上的官方文檔內存優化中,其中有一條建議是在32位模式下編譯redis替代默認的64位實例。對於一樣小於3GB的數據集,其在32位redis實例中要比在64位版本中的redis中小。網絡
若是應用程序使用整數集合,只要總內存不超過4GB的最大限制,那麼32位版本節省的內存是至關可觀的。當存入不一樣大小和類型的值時,redis的32位和64位版本之間的百分比差別意味着節省的內存數量顯著下降。對於那些使用集合的應用程序來講,它們較多的使用了字符串,由於64位的redis多是更好的選擇。這是由於在64位版本中的字符串擁有額外的空間及更高效的編碼。數據結構
對於哈希數據結構來講,32位和64位redis實例並無特別大的差別:app
對於32位版本的redis列表來講,在32位限制之下,列表很是適合存儲整數和浮點數:dom
對於redis集合的測試以下:
1) 32位的redis並未在redis用戶羣中進行普遍部署和測試,所以相較於64位版本可能會有未發現的bug。
2) 諸如bittop、bitcount這樣的位操做基於redis的64位版本進行了優化,所以相較於32位則沒有那麼高效。
3) 在32位redis中設置maxmemory參數更加困難,若是在32位版本的redis中的maxmemory值設置的過於靠近最大值4GB,那麼通訊、主從複製、I/O緩存都有可能隨時致使redis崩潰。
10.143.128.165:6379> info memory # Memory used_memory:819312 used_memory_human:800.11K used_memory_rss:1904640 used_memory_peak:2282784 used_memory_peak_human:2.18M used_memory_lua:36864 mem_fragmentation_ratio:2.32 mem_allocator:jemalloc-3.6.0
used_memory 分配的字節數大小
used_memory_human 將used_memory格式化爲人類可讀的值
used_memory_rss 常駐集大小(resident set size) 操做系統中看到的內存分配,
以及top顯示的結果
used_memory_peak redis使用的峯值內存
used_memory_peak_human 將used_memory_peak可視化
used_memory_lua redis的lua子系統使用的字節數
mem_fragmentation_ratio used_memory_rss與used_memory的比率
mem_allocator 在編譯器redis使用的分配器
保證redis數據庫不會超過可用內存---爲鍵設置超時時間,一旦過了鍵的超時時限,鍵就會被自動驅逐。
當在鍵上調用EXPIRE命令設置過時時間時,該超時只能經過刪除或者替換鍵的方式清除。以後,任何改變值的命令都是沒法更改或者清楚以前設置的超時的。
10.143.128.165:6379> set name yinn OK 10.143.128.165:6379> expire name 60 (integer) 1 10.143.128.165:6379> get name "yinn" 10.143.128.165:6379> ttl name (integer) 53 10.143.128.165:6379> append name nana (integer) 8 10.143.128.165:6379> get name "yinnnana" 10.143.128.165:6379> get name (nil)
若是在設置了超時的鍵上調用set或者getset(鍵過時以前),那麼超時會被清除,鍵不會從數據庫中驅逐:
10.143.128.165:6379> set name yin OK 10.143.128.165:6379> expire name 30 (integer) 1 10.143.128.165:6379> set name xian OK 10.143.128.165:6379> ttl name (integer) -1
也可使用 persist 命令清楚鍵上的超時設定:
10.143.128.165:6379> set name yinn OK 10.143.128.165:6379> expire name 60 (integer) 1 10.143.128.165:6379> ttl name (integer) 51 10.143.128.165:6379> persist name (integer) 1 10.143.128.165:6379> ttl name (integer) -1
在一個已經設置過超時的鍵上調用expire命令將會清楚並從新設定超時:
10.143.128.165:6379> expire name 90 (integer) 1 10.143.128.165:6379> ttl name (integer) 87 10.143.128.165:6379> expire name 20 (integer) 1 10.143.128.165:6379> ttl name (integer) 17 10.143.128.165:6379> get name (nil)
經過maxmemory指令將最大內存設置爲1MB以建立一個小內存的redis實例。maxmemory指令容許設定內存大小的硬性上限,運行時的redis實例受限於此。
10.143.128.165:6379> flushall ##清楚數據庫 OK 10.143.128.165:6379>config set maxmemory 1024 OK
當redis內存耗盡時,默認生效的是永不過時策略(noeviction policy):
默認的maxmemory-policy策略是永不過時。在noeviction策略中,沒有鍵設置爲過時。若是redis沒有可用內存,任何寫操做都會致使redis錯誤。
10.143.128.165:6379> config get maxmemory 1) "maxmemory" 2) "1024 10.143.128.165:6379>config get maxmemory-policy 1) "maxmemory-policy" 2) "noeviction"
第一種過時LRU策略名爲 volatile-lru,它將最近較少使用的鍵驅逐出去。這些鍵必須經過 expire set 命令設置了超時的。當redis內存耗盡時,redis開始刪除那些設置了過時時間的鍵,即使該鍵仍然有剩餘時間。
下一個策略是 allkeys-lru ,會刪除redis中任何一個鍵,並且沒有辦法限制哪些鍵被刪除。
redis的LRU算法是不許確的,由於redis並不會自動選擇最佳的候選鍵來驅逐,例如最少使用的鍵或者最先訪問的鍵。相反,redis默認行爲是選取5個鍵的samples,並驅逐當中最少使用的那個。若是想要增長LRU算法的精確性,能夠更改redis.conf文件中的maxmemory-samples指令,或者在運行時經過config set maxmemory-samples命令進行設置。
將maxmemory-samples增長到10,從而提高redisLRU算法的性能,效果接近真實LRU算法,可是反作用就是消耗更多的CPU計算能力。將maxmemory-samples降至3,從而減小了redisLRU算法的精確性,不過相應地加快了處理速度。
接下來是兩種最大內存驅逐策略:volatile-random和allkeys-random。它們與volatile-lru和allkeys-lru類似,可是不採用LRU算法。volatile-random 基於鍵上設置的過時狀態隨機驅逐一個鍵,須要O(n)時間複雜度的操做來計算建立的這些鍵是否已被驅逐。對於allkeys-random,整個鍵空間都是開放的。
最後一個最大內存策略是volatile-ttl,redis會嘗試根據鍵的剩餘時間(TTL)清除鍵。
對於哈希、列表、有序集合來講,這種特殊編碼方法基於ziplist(壓縮列表):
壓縮列表是一種特殊的雙向鏈表,專爲內存高效進行設計的。它存儲了字符串和整數值,其中整數是以真正的整數值而非字符串形式進行存儲的。它容許在列表的任意一端以O(1)時間複雜度進行push和pop操做。可是,因爲每次操做都須要爲ziplist使用的內存進行從新分配,實際上的複雜度與ziplist所使用的內存大小有關。
根據大小、類型以及數據結構的內容,ziplist編碼方式爲redis數據庫極大地節約了內存使用。
redis中ziplist的實現經過爲每一個節點只存儲3份數據實現較小的內存佔用:第一份是前一個節點的長度,第二份是當前節點的長度,第三份是存儲的值。
對於哈希表來講,hash-max-ziplist-entries 指令設置了總共有多少字段是能夠被特殊編碼爲ziplist,默認是512。hash-max-ziplist-value指令設置了從ziplist轉變爲哈希表所要達到的最大大小,默認64.
在集合中經過使用整數代替字符串,能夠將集合的大小顯著地下降,可是 位圖仍然要比集合小一個數量級、更節省內存。
待續P90