理解內存
為什么要理解內存呢?redis所有的數據都存在內存中如何高效利用內存,實現用更少的內存存更多的數據,從而降低成本
如何統計內存使用?info memory可以獲取內存相關指標,如下:used_memory:redis分配器分配的內存總量used_memory_human:以可讀格式返回used_memoryused_memory_rss:從操作系統的角度顯示redis占用的物理內存總量used_memory_peak:內存使用的最大值,表示used_memory的峰值used_memory_peak_human:以可讀格式返回used_memory_peakused_memory_lua:Lua引擎所消耗的內存大小mem_fragmentation_ratio:used_memory_rss/used_memory比值,表示內存碎片率mem_allocator:redis所使用的內存分配器,默認為jemalloc(注:mem_fragmentation_ratio>1出現內存碎片,mem_fragmentation_ratio<1出現操作系統把redis內存Swap到硬盤現象)
內存消耗自身內存對象內存(sizeof(keys)+sizeof(values))緩沖內存客戶端緩沖(所有接入到redis服務器TCP連接的輸入輸出緩沖,輸入緩沖無法控制,最大空間1G,超過將斷開連接。輸出緩沖通過參數client-output-buffer-limit控制)普通客戶端(除了復制和訂閱的客戶端之外的所有連接)從客戶端(主節點會為每個從節點單獨建立一條連接用于命令復制)訂閱客戶端(當使用發布訂閱功能時,連接客戶端使用單獨的輸出緩沖區)復制積壓緩沖區(一個可重用的固定大小緩沖區用于實現部分復制功能,repl-backlog-size)AOF緩沖區(用于redis重寫期間保存最近的寫入命令)內存碎片內存分配策略(小,大,巨大)容易出現內存碎片的場景(頻繁做更新操作、大量過期鍵刪除)如何解決(數據對齊、安全重啟)子進程消耗(執行AOF/RDB重寫時redis創建的子進程內存消耗)
內存管理設置內存上限(maxmemory)動態調整內存上限(config set maxmemory 6GB)內存回收策略刪除到達過期時間的鍵對象惰性刪除(當客戶端讀取帶有超時屬性的鍵時,如果已經超過鍵設置的過期時間,會執行刪除操作并返回空,節省CPU,存在內存泄漏問題)定時任務刪除(自適應算法,鍵的過期比例、使用快慢兩種模式)內存使用達到maxmemory上限時觸發內存溢出控制策略(maxmemory-policy控制)noeviction:不會刪除任何數據,拒絕所有寫入操作并返回客戶端錯誤信息volatile-lru:根據LRU算法刪除設置了超時屬性的鍵,直到騰出足夠空間為止,如果沒有刪除的鍵,回退到noevictionallkeys-lru:根據LRU算法刪除所有鍵,直到騰出足夠空間為止allkeys-random:隨機刪除所有鍵,直到騰出足夠空間為止volatile-random:隨機刪除過期鍵,直到騰出足夠空間為止volatile-ttl:根據鍵值對象的ttl屬性,刪除最近將要過期數據,如果沒有,回退到noeviction
內存優化首先了解一下RedisObject對象type字段:表示當前對象使用的數據類型encoding字段:表示redis內部編碼類型lru字段:記錄對象最后一次被訪問的時間(object idletime {key}查看鍵的空閑時間)refcount字段:記錄當前對象被引用的次數(object refcount {key}獲取當前對象的引用)*ptr字段:與對象的數據內容有關,如果是整數,直接存儲數據,否則表示指向數據的指針有哪些具體優化手段?縮減鍵值對象(key盡可能短,value采用序列化或者壓縮算法)共享對象池(redis內部維護[0-9999]的整數對象池)注意:當設置maxmemory并啟用LRU相關淘汰策略時,redis禁止使用共享對象池;對于ziplist編碼的值對象,即使內部數據為整數也無法使用共享對象池字符串優化SDS(字符串長度、已用長度、未用長度)預分配機制(減少字符串頻繁修改操作)字符串重構編碼優化什么是編碼?具體使用哪種底層數據結構來實現string--rawembstrinthash----hashtableziplist(value<=hash-max-ziplist-value and count(field)<=hash-max-ziplist-entries)list----linkedlistziplist(value<=list-max-ziplist-value and 鏈表長度<=list-max-ziplist-entries)quicklistset-----hashtableintset(元素為整數 and 集合長度<=set-max-intset-entries)zset----skiplistziplist(value<=zset-max-ziplist-value and 有序集合長度<=zset-max-ziplist-entries)(hashtable、ziplist、linkedlist、quicklist、intset、skiplist)注意:小編碼可以轉大編碼,大不能轉小ziplist(所有數據采用線性連續的內存結構,節約內存)zlbytes:記錄整個壓縮列表所占字節長度,方便重新調整ziplist空間。類型是int-32,長度為4字節zltail:記錄距離尾節點的偏移量,方便尾節點彈出操作。類型int-32,4字節zllen:記錄壓縮鏈表節點數量,類型是int-16,2字節entry:記錄具體的節點prev_entry_bytes_length:記錄前一個節點所占空間,用于快速定位上一個節點,可實現列表反向迭代encoding:當前節點編碼和長度,前兩位表示類型,其余表示長度contents:節點的值zlend:記錄列表結尾,1字節intset(存儲有序、不重復的整數集)encoding:表示類型length:集合元素個數contents:整數數組,從小到大順序保存控制鍵的數量針對自己現在使用的模式,分析其內存消耗和可優化的地方。復制代碼