日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

Redis底层实现--字符串

發布時間:2023/12/4 数据库 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis底层实现--字符串 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Redis字符串存儲實現原理

  • Redis 中的字符串是可以修改的字符串,在內存中他是以字節數組的形式存在的。我們在入門語言C語言里面的字符串標準形式是以NULL(即0x\0)作為結束符,但是Redis里面,字符串表示方法不是這樣,因為,要獲取以null結尾的字符串需要遍歷整個字符串,時間復雜度是O(n),對應單線程對外服務的Redis來說是無法承受的。
  • Redis的字符串結構叫做SDS,Simple Dynamic String。他的結構是一個帶上長度信息的字節數組,類似C語言中的結構體。
struct SDS<T>{T capacity; //數組容量T len; //已有數據長度byte flags; //特殊標志位byte[] content; //數組主體內容 }
  • Redis中SDS存儲結構的設計類似于ArrayList機構,因為Redis允許字符串的修改,因此初始申請可以有一部分的冗余空間。
    • capacity 標識所有分配數組的長度,包括未存儲數據的部分空間
    • len標識字符串的實際長度
    • 當冗余的空間不夠時候,先擴容,在復制舊的內容,然后在添加新內容,如果字符串長度非常長,內存的分配和復制開銷會特別大。
  • 以上結構體中,使用的泛型T,其中Capacity和len的類型是T,因為Redis對存儲的壓縮優化
    • 當存儲字符串比較短的時候,了你和capacity可以使用byte和short來表示,
  • Redis規定字符串長度不超過512M,創建字符串時候len和capacity一樣長,不會多分配冗余空間,這是因為絕大多數場景下我們不會去修改字符串。
embstr OR raw
  • Redis字符串有兩種存儲方式,在長度短的時候,使用embstr形式存儲,長度超過44 字節時候,使用raw形式存儲,如下實驗:
新docker-redis:0>set codehole aaaaaaaabbbjjbjbdjjskjkjsdeuiopoiioioioioioi "OK" 新docker-redis:0>debug object codehole "Value at:0x7f0a3b3c22c0 refcount:1 encoding:embstr serializedlength:41 lru:12955894 lru_seconds_idle:8" 新docker-redis:0>set codehole aaaaaaaabbbjjbjbdjjskjkjsdeuiopoiioioioioioi1111 "OK" 新docker-redis:0>debug object codehole "Value at:0x7f0a3d6d66a0 refcount:1 encoding:raw serializedlength:43 lru:12955928 lru_seconds_idle:2"
  • 一下我們通過分析Redis字符串對象存儲結構來說明兩個問題

    • 問題一:為什么是44個字節作為界限
    • 問題二:embstr 和raw存儲的區別
  • Redis對象存儲都會有一個頭部結構,如下形式

struct RedisObject{int4 type; //4bitint4 encoding; //4bitint24 lru; //24bit 3byteint32 refcount; //32bit 4bytevoid *ptr; //8byte, 64bit system } robj;
  • 不同的對象具有不同的type 類型(4bit)。

  • 同一個類型的type也會有不同的存儲方式encoding(4bit)。

  • 為了記錄對象的lru信息,使用了24bit來記錄lru信息

  • 每個對象都有一個引用計數,refcount,當他歸零時候,對象不被任何地方使用,對象將被銷毀,內存被回收

  • ptr指針結構將指向對象的具體存儲位置(body)

  • 以上所有的綜合一起 4bit+ 4bit+ 24bit + 32 bit + 64bit = 128bit = 16byte,所有Redis對象的對象頭結構都需要占據16字節存儲空間。

  • 接著我們在分享SDS結構體大小,在字符串比較小的時候,SDS對象頭結構的大小如下:

struct SDS{int8 capacity; //1byteint8 len; //1byteint8 flags; //1bytebyte[] content; //存儲數據的數組,長度capacity }
  • 如上結構中 capacity ,len, flags 三個都占用1byte的內存,其他的就是 capacity長度的數組,用來存儲具體數據。也就是最少也要3 個字節的存儲空間。加上上面的16byte,我們一個沒有存儲字符串的Redis字符串對象,已經有19 byte的空間被系統各種屬性占用。

  • 我們在內存分配的時候,使用jemalloc, tcmalloc等分配內存大小的單元都是2/4/4/8/16/32/64 byte,

  • 為了容納完整的embstr對象,jemalloc最少分配32byte空間,如果字符串稍微長點,那就是64byte,如果字符串超過64byte,Redis會認為是一個大字符串,不在適合emdstr存儲的形式,而使用raw形式

  • 我們用最大內存空間64 來計算最大字符串長度, 64 - 19 = 45 ,但是之前實驗得到的是44

  • SDS結構中content中字符串是以null結尾,多出這個字節,便于直接使用glbc的字符串處理函數,以及便于字符串的調試打印輸出。最終得出了44 的長度。如下圖:

  • 問題二中embstr存儲形式與 raw的存儲形式如下

    • embst存儲將RedisObject對象頭結構和SDS對象連續存儲在一起,使用malloc方法一次性分配內存
    • raw存儲形式不一樣,他需要兩次malloc方法,兩個對象頭在內存地址上不連續通過對象頭中 ptr指針來尋址存儲位置。
擴容策略
  • 字符串的擴容兩種方式:
    • 字符串長度在1MB之前,擴容空間都是加倍擴容,也就是保留100%的冗余空間
    • 字符串長度超過1MB后,避免加倍后冗余空間浪費過多,每次只多分配1MB大小的冗余空間。

上一篇:Redis服務信息–Info指令

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的Redis底层实现--字符串的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。