精通Redis之路(一)數據結構——String原理介紹及使用場景

爲什麼編撰這個系列

1.在無數的簡歷中見過「精通Redis」的技能描述,當問其一些原理性的東西時候都是磕磕絆絆毫無頭緒及思路,
  大部分面試者停留在使用的階段,可是若是單純的使用,不知其原理,
  在某些逼死麪試者的面試場景中就會真的被逼死~
3.鞏固自身姿式~
複製代碼

接下來將直入主題html

Redis 數據結構

1、String

能夠簡單的認爲底層實現就是SDS(Simple Dynamic String)。Redis中,默認以SDS做爲本身的字符串表示,
只有在一些字符串不可能出現變化的地方使用C字符串。
複製代碼
SDS 與 C字符串 比較
SDS C字符串
獲取字符串長度的複雜度爲O(1) 獲取字符串長度的複雜度爲O(N)
API是安全的,不會形成緩衝區溢出 API是不安全的,可能會形成緩衝區溢出
修改字符串長度N次最多須要執行N次內存重分配 修改字符串長度N次必然須要執行N次內存重分配
能夠保存文本或者二進制數據 只能保存文本數據
可使用一部分庫的函數 可使用全部庫中的函數

接下來是比較結果的原理介紹面試

SDS定義以下:
struct sdshdr {    
  // 用於記錄buf數組中使用的字節的數目
  // 和SDS存儲的字符串的長度相等 
	int len;    
  // 用於記錄buf數組中沒有使用的字節的數目 
	int free;    
  // 字節數組,用於儲存字符串
	char buf[];   //buf的大小等於len+free+1,其中多餘的1個字節是用來存儲’\0’的。
};
複製代碼
  • SDS除了用來保存數據庫中的字符串以外,SDS還被用做緩衝區(buffer),如AOF模塊中的AOF緩衝區,以及客戶端狀態中的輸入緩衝區
SDS存儲示例:

SDS 存儲示例

1.獲取字符串長度的複雜度redis

C語言中: 字符串只是簡單的字符的數組,當使用strlen獲取字符串長度的時候,
         內部實際上是直接順序遍歷數組的內容,找到對應的’\0’對應的字符,從而計算出字符串的長度。
         即O(N)
S D S : 只須要訪問SDS的len屬性就能獲得字符串的長度,複雜度爲O(1)。
複製代碼

2.杜絕緩衝區溢出數據庫

Redis是C語言編寫的,並無方便的數據類型來進行內存的分配和釋放(C++ STL String),
必須手動進行內存分配和釋放。
對於字符串的拼接、複製等操做,C語言開發者必須確保目標字符串的空間足夠大,否則就會出現溢出的狀況。
當使用SDS的API對字符串進行修改的時候,

1. API內部第一步會檢測字符串的大小是否知足。
    若是空間已經知足要求,那麼就像C語言同樣操做便可。若是不知足,則拓展buf的空間
2. 以後再進行操做。每次操做以後,len和free的值會作相應的修改。

擴展buf空間策略:
1. 修改以後總長度len<1MB: 總空間爲2*len+1;
2. 修改以後總長度len>=1MB: 總空間爲len+1MB+1。
換句話說,預分配的空間上限是1MB,儘可能爲len。
複製代碼

3.減小修改字符串時帶來的內存重分配次數segmentfault

Redis主要經過如下兩種策略來處理內存問題。
    字符串長度增長操做時,進行空間預分配
    字符串長度減小操做時,惰性空間釋放
        當執行字符串長度縮短的操做的時候,SDS並不直接從新分配多出來的字節,
        而是修改len和free的值(len相應減少,free相應增大,buf的空間大小不變化),避免內存重分配。
        SDS也提供直接釋放未使用空間的API,在須要的時候,也能真正的釋放掉多餘的空間。
複製代碼

4.二進制安全數組

C字符串除了末尾以外不能出現空字符,不然會被程序認爲是字符串的結尾。
這就使得C字符串只能存儲文本數據,而不能保存圖像,音頻等二進制數據。
使用SDS就不須要依賴控制符,而是用len來指定存儲數據的大小,
全部的SDS API都會以處理二進制的方式來處理SDS的buf的數據。
程序不會對buf的數據作任何限制、過濾或假設,數據寫入的時候是什麼,讀取的時候依然不變。
複製代碼

5.兼容部分C字符串函數緩存

SDS的buf的定義(字符串末尾爲’\0’)和C字符串徹底相同,所以不少的C字符串的操做都是適用於SDS->buf的。
好比當buf裏面存的是文本字符串的時候,大多數經過調用C語言的函數就能夠。
複製代碼
參考

喵耳朵 redis基本操做-string原理 (原文地址404)安全

SDS底層結構 segmentfault.com/p/121000000…session

使用場景:

1.緩存
string類型爲基本簡單類型也是最經常使用的緩存數據類型,字符串單key長度最長爲512MB,
一般作法是能夠將簡單對象序列化後存入。但建議根據業務及業務數據選擇最優的數據結構,
不建議全部數據均序列化存入string,固然這樣開發很快,可是有一點點low。智者見智。
複製代碼
2.計數器
當string結構中存儲的是數字時,可進行incr、decr操做,可是注意:此時string內部存儲的便再也不是SDS了,同時string方法中setBit及getRange的實現也會有所不一樣(TODO)
複製代碼
3.共享session
用戶從新刷新一次界面,可能須要訪問一下數據進行從新登陸,或者訪問頁面緩存Cookie,
可是能夠利用Redis將用戶的Session集中管理,在這種模式只須要保證Redis的高可用,
每次用戶Session的更新和獲取均可以快速完成。大大提升效率。(這段是抄的)
複製代碼

相關命令整理:

copy from www.cnblogs.com/DswCnblog/p…數據結構

命令原型 時間複雜度 命令描述
APPEND O(1) 若是該Key已經存在,APPEND命令將參數Value的數據追加到已存在Value的末尾。若是該Key不存在,APPEND命令將會建立一個新的Key/Value。
DECR O(1) 將指定Key的Value原子性的遞減1。若是該Key不存在,其初始值爲0,在decr以後其值爲-1。若是Value的值不能轉換爲整型值,如Hello,該操做將執行失敗並返回相應的錯誤信息。注意:該操做的取值範圍是64位有符號整型。
相關文章
相關標籤/搜索