關於空間預分配和空間惰性釋放redis
- 字符串增加操做時,若是修改後長度小於1M則分配該字符串長度2倍的內存空間,若是修改後長度大於等於1M則分配該字符串長度+1M的內存空間。(預分配,避免每次增加操做都須要進行內存重分配執行系統調用)
- 字符串縮短操做時,程序不會當即釋放縮短後多出來的字節,而是在須要時再釋放。(惰性釋放,避免之後須要增加操做時重分配內存,會在較短的時間內形成內存浪費,文中未說起什麼時候是「須要時」)
最佳實踐:由於對字符串的增加或縮短操做都有可能須要執行內存重分配,因此修改相同鍵使用SDS類型保存的值時保持修改先後長度一致。
rehash步驟算法
- 擴展操做(沒有執行BGSAVE或BGREWRITEAOF且負載因子大於等於1;正在執行BGSAVE或BGREWRITEAOF且負載因子大於等於5),爲ht[1]分配第一個大於等於當前包含鍵值對數量(ht[0].used)*2的2n內存空間
- 收縮操做(負載因子小於0.1時),爲ht[1]分配第一個大於等於當前包含鍵值對數量的2n內存空間
- 將保存在ht[0]中的全部鍵值對rehash到ht[1]
- 釋放ht[0],將ht[1]設置爲ht[0],建立新的空白哈希表ht[1]
負載因子=哈希表已保存節點數量/哈希表大小sql
Redis使用MurmurHash2算法來計算鍵的哈希值
升級步驟數據庫
- 根據新元素的類型擴展底層數組空間,併爲新元素分配空間
- 轉換現有元素至新的類型,保持有序性放置元素
- 添加新元素,當新元素小於全部先有元素時放置在索引0,當新元素大於全部先有元素師放置在索引length-1
最佳實踐:爲了不添加新元素時產生升級操做,應向同一整數集合添加相同類型的整數
不一樣類型和編碼的對象數組
類型 | 編碼 | 對象 |
---|---|---|
REDIS_STRING | REDIS_ENCODING_INT(整數值) | 使用整數值實現的字符串對象 |
REDIS_STRING | REDIS_ENCODING_EMBSTR(小於32字節字符串) | 使用embstr編碼的簡單動態字符串實現的字符串對象 |
REDIS_STRING | REDIS_ENCODING_RAW(大於32字節字符串) | 使用簡單字動態字符串實現的字符串對象 |
REDIS_LIST | REDIS_ENCODING_ZIPLIST(默認配置下,全部元素長度小於64字節且元素數量小於513,查看命令:CONFIG GET list-max-ziplist*) | 使用壓縮列表實現的列表對象 |
REDIS_LIST | REDIS_ENCODING_LINKEDLIST | 使用雙端鏈表實現的列表對象 |
REDIS_HASH | REDIS_ENCODING_ZIPLIST (默認配置下,全部元素長度小於64字節且元素數量小於513,查看命令:CONFIG GET hash-max-ziplist*) | 使用壓縮列表實現的列表對象 |
REDIS_HASH | REDIS_ENCODING_HT | 使用字典實現的哈希對象 |
REDIS_SET | REDIS_ENCODING_INTSET(默認配置下,全部元素都是整數值且元素數量小於513,查看命令:CONFIG GET set-max-intset-entries) | 使用整數集合實現的集合對象 |
REDIS_SET | REDIS_ENCODING_HT | 使用字典實現的集合對象 |
REDIS_ZSET | REDIS_ENCODING_ZIPLIST(默認配置下,全部元素長度小於64字節且元素數量小於128,查看命令:CONFIG GET zset-max-ziplist*) | 使用壓縮列表實現的有序集合對象 |
REDIS_ZSET | REDIS_ENCODING_SKIPLIST | 使用跳躍鏈表和字典實現的有序集合對象 |
備註安全
- TYPE KEY(獲取鍵的對應值對象類型)
- OBJECT ENCODING KEY(獲取鍵的對應值對象編碼)
最佳實踐:爲了最大程度的節省內存,應將簡單字符或重複率較高的字符串對應成0-9999範圍內的數字。
惰性刪除:當讀取的鍵是一個過時鍵時纔會將該鍵刪除並返回空。服務器
按期刪除:在規定的時間內分屢次遍歷每一個數據庫,從expires字典中隨機檢查一部分鍵的過時時間(也即每次執行按期刪除並不必定能把全部的過時鍵都刪除)。網絡
最佳實踐:主從模式下從服務器在讀取到過時鍵時不會主動刪除且會當成正常鍵返回數據,當數據中包含較多 的過時鍵時主服務器的按期刪除策略可能須要較長時間才能將該過時鍵刪除,所以Redis的主從模式不一樣於Mysql的主從模式(主寫從讀),若是使用相似 Mysql主從的用法時需注意過時數據在必定時間內多是髒數據。
- 可變輸出緩衝區分普通客戶端、pubsub(發佈/訂閱模式)、slave三種客戶端限制。默認狀況下,普通客戶端無限制(阻塞 式的消息應答模式一般不會形成輸出緩衝區堆積),pubsub客戶端超過32m或持續60s超高8m,slave客戶端超高256m或持續60s超過 64m,對於超過限制的客戶端Redis將關閉鏈接。
- 最大鏈接數受系統當前文件描述符數量限制,最大隻能取文件描述符數量限制-32(Redis最多會佔用32個文件描述符)。
- 若是客戶端是主服務器、從服務器、被BLPOP等命令阻塞、正在執行SUBSCRIBE等訂閱命令,將不受timeout設置影響。
命令請求步驟數據結構
- 客戶端將命令請求發送給服務器
- 服務器讀取命令請求並解析出命令參數
- 命令執行器根據參數查找命令的實現函數,執行實現函數並得出命令回覆
- 服務器將命令回覆返回給客戶端
服務器啓動步驟dom
- 初始化服務器狀態
- 載入服務器配置
- 初始化服務器數據結構
- 還原數據庫狀態
- 執行事件循環
MOVED錯誤表示所請求的鍵負責權已經轉移到另外一節點,ASK錯誤則只是槽正在轉移時的一種臨時性錯誤
Redis建立Lua執行環境步驟
- 建立基礎Lua環境
- 載入函數庫到Lua環境中
- 建立包含對Redis進行操做的函數的全局表格
- 使用自制隨機函數替代Lua原有帶反作用的隨機函數(自制隨機函數具備如下特徵:①對於相同seed,math.random總 產生相同的隨機數序列;②除非顯示修改math.randomseed中的seed,不然均使用math.randomseed(0)初始化seed)
- 建立排序輔助函數,Lua環境使用該函數對一部分Redis命令的結果進行排序
- 建立能夠提供更多詳細錯誤信息的錯誤報告輔助函數redis.pcall
- 保護Lua環境的全局變量,防止執行腳本過程當中修改全局變量
- 將修改完成後的Lua環境保存到服務器狀態的Lua屬性中