內存管理優化mysql
Redis Hash是value內部爲一個HashMap,若是該Map的成員數比較少,則會採用相似一維線性的緊湊格式來存儲該Map, 即省去了大量指針的內存開銷,這個參數控制對應在redis.conf配置文件中下面2項:redis
hash-max-zipmap-entries 64 hash-max-zipmap-value 512sql
當value這個Map內部不超過多少個成員時會採用線性緊湊格式存儲,默認是64,即value內部有64個如下的成員就是使用線性緊湊存儲,超過該值自動轉成真正的HashMap。數據庫
hash-max-zipmap-value 含義是當 value這個Map內部的每一個成員值長度不超過多少字節就會採用線性緊湊存儲來節省空間。緩存
以上2個條件任意一個條件超過設置值都會轉換成真正的HashMap,也就不會再節省內存了,那麼這個值是否是設置的越大越好呢,答案固然是否認的,HashMap的優點就是查找和操做的時間複雜度都是O(1)的,而放棄Hash採用一維存儲則是O(n)的時間複雜度,若是運維
成員數量不多,則影響不大,不然會嚴重影響性能,因此要權衡好這個值的設置,整體上仍是最根本的時間成本和空間成本上的權衡。性能
list-max-ziplist-value 64 list-max-ziplist-entries 512優化
list數據類型節點值大小小於多少字節會採用緊湊存儲格式、list數據類型多少節點如下會採用去指針的緊湊存儲格式。操作系統
內存預分配:設計
Redis內部實現沒有對內存分配方面作過多的優化(對比Memcache),在必定程度上會存在內存碎片,不過大多數狀況下這個不會成爲Redis的性能瓶頸,不過若是在Redis內部存儲的大部分數據是數值型的話,Redis內部採用了一個shared integer的 方式來省去分配內存的開銷,即在系統啓動時先分配一個從1~n 那麼多個數值對象放在一個池子中,若是存儲的數據剛好是這個數值範圍內的數據,則直接從池子裏取出該對象,而且經過引用計數的方式來共享,這樣在系統存儲 了大量數值下,也能必定程度上節省內存而且提升性能,這個參數值n的設置須要修改源代碼中的一行宏定義REDIS_SHARED_INTEGERS,該值 默認是10000,能夠根據本身的須要進行修改,修改後從新編譯就能夠了。
持久化機制:
定時快照方式(snapshot):
該持久化方式實際是在Redis內部一個定時器事件,每隔固定時間去檢查當前數據發生的改變次數與時間是否知足配置的持久化觸發的條件,若是知足則通 過操做系統fork調用來建立出一個子進程,這個子進程默認會與父進程共享相同的地址空間,這時就能夠經過子進程來遍歷整個內存來進行存儲操做,而主進程 則仍然能夠提供服務,當有寫入時由操做系統按照內存頁(page)爲單位來進行copy-on-write保證父子進程之間不會互相影響。
該持久化的主要缺點是定時快照只是表明一段時間內的內存映像,因此係統重啓會丟失上次快照與重啓之間全部的數據。
基於語句追加方式(aof):
aof方式實際相似mysql的基於語句的binlog方式,即每條會使Redis內存數據發生改變的命令都會追加到一個log文件中,也就是說這個log文件就是Redis的持久化數據。
aof的方式的主要缺點是追加log文件可能致使體積過大,當系統重啓恢復數據時若是是aof的方式則加載數據會很是慢,幾十G的數據可能須要幾小時才能加載完,固然這個耗時並非由於磁盤文件讀取速度慢,而是因爲讀取的全部命令都要在內存中執行一遍。另外因爲每條命令都要寫log,因此使用aof的方式,Redis的讀寫性能也會有所降低。
能夠考慮將數據保存到不一樣的Redis實例中,每一個實例的內存大小在2G左右,避免將雞蛋放到一個籃子裏,既能夠減小緩存失效給系統帶來的影響,又能夠加快數據恢復的速度,不過同時也給系統設計帶來了必定的複雜性。
Redis持久化崩潰問題:
有Redis線上運維經驗的人會發現Redis在物理內存使用比較多,但尚未超過實際物理內存總容量時就會發生不穩定甚至崩潰的 問題,有人認爲是基於快照方式持久化的fork系統調用形成內存佔用加倍而致使的,這種觀點是不許確的,由於fork 調用的copy-on-write機制是基於操做系統頁這個單位的,也就是隻有有寫入的髒頁會被複制,可是通常你的系統不會在短期內全部的頁都發生了寫 入而致使複製,那麼是什麼緣由致使Redis崩潰的呢?
答案是Redis的持久化使用了Buffer IO造 成的,所謂Buffer IO是指Redis對持久化文件的寫入和讀取操做都會使用物理內存的Page Cache,而大多數數據庫系統會使用Direct IO來繞過這層Page Cache並自行維護一個數據的Cache,而當Redis的持久化文件過大(尤爲是快照文件),並對其進行讀寫時,磁盤文件中的數據都會被加載到物理內 存中做爲操做系統對該文件的一層Cache,而這層Cache的數據與Redis內存中管理的數據實際是重複存儲的,雖然內核在物理內存緊張時會作 Page Cache的剔除工做,但內核極可能認爲某塊Page Cache更重要,而讓你的進程開始Swap ,這時你的系統就會開始出現不穩定或者崩潰了。咱們的經驗是當你的Redis物理內存使用超過內存總容量的3/5時就會開始比較危險了。
總結:
一、根據業務須要選擇合適的數據類型,併爲不一樣的應用場景設置相應的緊湊存儲參數。
二、當業務場景不須要數據持久化時,關閉全部的持久化方式能夠得到最佳的性能以及最大的內存使用量。
三、若是須要使用持久化,根據是否能夠容忍重啓丟失部分數據在快照方式與語句追加方式之間選擇其一,不要使用虛擬內存以及diskstore方式。
四、不要讓你的Redis所在機器物理內存使用超過實際內存總量的3/5。
redis.conf中的maxmemory選項,該選項是告訴Redis當使用了多少物理內存後就開始拒絕後續的寫入請求,該參數能很好的保護好你的Redis不會由於使用了過多的物理內存而致使swap,最終嚴重影響性能甚至崩潰。
redis.conf文件中 vm-enabled 爲 no