標籤:共用 log 模式 count key 效能 事件 圖片 內部使用
1 Redis儲存機制:
redis儲存的資料類型包括,String,Hash,List,Set,Sorted Set,它內部使用一個redisObject對象來表示所有的key和value,這個對象基本結構見下:
typedef struct redisObject {
unsigned type, // 4位元組,資料類型
unsigned encoding, // 4位元組,編碼方式
unsigned lru, // 24位元組,置換演算法
int refcount, // 對象引用計數
void *ptr // 資料具體儲存的指向
} robj;
type代表一個value對象具體是何種資料類型,encoding是不同資料類型在redis內部的儲存方式,這麼表示主要是為了給Redis不同資料類型提供一個統一的管理介面。
String是最常用的一種類型,是最普通的key/value的hash儲存,讀寫的時間複雜度都是O(1)。
Hash儲存會在基本kv的hash裡再建立一層hash,兩層hash結構,取值時可以直接通過ID+key的方式取到value,讀寫的時間複雜度都是O(1)。
List儲存的是一個雙向鏈表,即可以支援反向尋找和遍曆,查詢插入一個資料的時間複雜度為O(n),如果是在最後添加或彈出則為O(1)。
Set儲存的是一個自動去重的List,內部實現Set儲存的是一個值為null的map,所以Set支援直接判定值的存在性,Set讀寫的時間複雜度都是O(1)。
Sorted Set儲存的是按使用者的指定的分數排序的Set,Sorted Set儲存採用了一個跳錶,和一個hash,跳錶儲存了所有資料,hash儲存資料和分數的關係。Sorted Set讀寫主要是從跳錶中查詢資料或位置的複雜度,為O(log(n))。
8.2 Redis記憶體管理機制:
記憶體控制:
Redis通過控制記憶體上限和回收策略實現記憶體管理,使用maxmemory參數限制最大可用記憶體,比如我們的nfvo就是設定的512mb,代表我們最大不能儲存超過512mb的資料。
對於到期的資料,redis有兩種方式釋放記憶體,一個是惰性刪除,在下次查詢某key的時候先檢查逾時時間,如果已逾時則刪除資料並返回空;另一個是定時任務,預設每10秒一次(可以同hz參數配置,我們使用的預設配置10),檢查逾時時間,逾時則刪除。
對於溢出的資料,有幾種處理方式,可通過maxmemory-policy配置。
1、noeviction,不刪除,拒絕新插入的訊息。
2、volatile-lru,根據LRU(最近最少使用)置換演算法,對於配置了逾時時間的資料進行清理,這個也是我們目前配置的清理策略,巴展時期經常出現資料丟失的情況就是由於這個策略的存在,所以在使用時因小心。
3、allkeys-lru,根據LRU(最近最少使用)置換演算法,對於所有資料進行清理,直到記憶體滿足需要。
4、allkeys-random,隨機刪除所有key,直到滿足記憶體需要。
5、volatile-random,隨機刪除配置了逾時時間的key,直到滿足記憶體需要。
6、volatile-ttl,根據鍵對象的存留時間屬性,刪除最近將要到期的資料。
當用戶端執行一條新命令,導致資料庫需要增加資料(比如set key value),Redis會檢查記憶體使用量,如果記憶體使用量超過maxmemory,就會按照置換策略刪除一些key來給新資料準備儲存區。
Redis還會通過對大小資料的不同處理來節約記憶體,比如上面提到的redis的幾個類型,list,set,map,在資料量小的時候Redis會採用線性緊湊儲存來節省空間的,資料量多大這個是可配置的:
entries含義是當value這個Map內部不超過多少個成員時會採用線性緊湊格式儲存,預設是64,value含義是當value這個Map內部的每個成員值長度不超過多少位元組就會採用線性緊湊儲存來節省空間的,這個值不能無限擴大,因為線性儲存意味著線性尋找,資料少是效率沒問題,資料量大的時候如果採用這種方式會降低查詢效率。
8.3 Redis持久化機制:
Redis一共支援四種持久化方式,分別是:定時快照方式(snapshot),基於語句追加檔案的方式(aof),虛擬記憶體(vm),Diskstore方式。主要使用的是前兩種,vm方式甚至已經被廢棄掉了,而Diskstore也只是在實驗階段,也就是說,Redis目前還是作為記憶體資料庫使用,資料量不允許很大。
定時快照方式實際是在 Redis 內部一個定時器事件,每隔固定時間去檢查當前資料發生的改變次數與時間是否滿足配置的持久化觸發的條件,如果滿足則通過作業系統 fork 調用來建立出一個子進程,這個子進程預設會與父進程共用相同的地址空間,這時就可以通過子進程來遍曆整個記憶體來進行儲存操作,而主進程則仍然可以提供服務,當有寫入時由作業系統按照記憶體頁(page)為單位來進行copy-on-write保證父子進程之間不會互相影響。該持久化的主要缺點是定時快照只是代表一段時間內的記憶體映像,所以系統重啟會丟失上次快照與重啟之間所有的資料。定時快照方式根據redis.conf中配置的save的時間間隔去檢查當前資料改變次數和時間是否滿足配置,如果滿足則從父進程fork(copy-on-write機制)出一個子進程,通過該子進程遍曆記憶體來轉換成rdb檔案,在redis.conf裡見下:
分別代表900秒內1個key變化,300秒內10個key,60秒內10000個key觸發,由於我們的nfvo和vnfm由於每次都會清理Redis,並未用到其持久化機制,所以配置被注掉了。
aof方式每條會使Redis記憶體資料發生改變的命令都會追加到一個log檔案中,也就是說這個log檔案就是Redis的持久化資料,aof的方式的主要缺點是追加log檔案可能導致體積過大,當系統重啟恢複資料時如果是aof的方式則載入資料會非常慢,因為讀取的所有命令都要在記憶體中執行一遍。另外由於每條命令都要寫log,所以使用aof的方式,Redis的讀寫效能也會有所下降。aof有三種模式調用fsync寫入磁碟,fsync函數可以同步記憶體中所有已修改的檔案資料到儲存裝置,1、總是寫入,即每次有變更都調用fsync寫入;2、每秒調用fsync寫入一次;3、不主動調用fsync同步資料到磁碟,而是依賴os的定時fsync寫入,一般為30秒,不推薦。aof方式在redis.conf內配置見下:
appendonly代表是否開啟AOF,我們並未開啟,appendfilename是檔案名稱,appendfsync是寫入模式。
基於Redis做記憶體管理