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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

Redis底层实现--字符串

發(fā)布時(shí)間:2023/12/4 数据库 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis底层实现--字符串 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Redis字符串存儲(chǔ)實(shí)現(xiàn)原理

  • Redis 中的字符串是可以修改的字符串,在內(nèi)存中他是以字節(jié)數(shù)組的形式存在的。我們?cè)谌腴T語(yǔ)言C語(yǔ)言里面的字符串標(biāo)準(zhǔn)形式是以NULL(即0x\0)作為結(jié)束符,但是Redis里面,字符串表示方法不是這樣,因?yàn)?#xff0c;要獲取以null結(jié)尾的字符串需要遍歷整個(gè)字符串,時(shí)間復(fù)雜度是O(n),對(duì)應(yīng)單線程對(duì)外服務(wù)的Redis來(lái)說(shuō)是無(wú)法承受的。
  • Redis的字符串結(jié)構(gòu)叫做SDS,Simple Dynamic String。他的結(jié)構(gòu)是一個(gè)帶上長(zhǎng)度信息的字節(jié)數(shù)組,類似C語(yǔ)言中的結(jié)構(gòu)體。
struct SDS<T>{T capacity; //數(shù)組容量T len; //已有數(shù)據(jù)長(zhǎng)度byte flags; //特殊標(biāo)志位byte[] content; //數(shù)組主體內(nèi)容 }
  • Redis中SDS存儲(chǔ)結(jié)構(gòu)的設(shè)計(jì)類似于ArrayList機(jī)構(gòu),因?yàn)镽edis允許字符串的修改,因此初始申請(qǐng)可以有一部分的冗余空間。
    • capacity 標(biāo)識(shí)所有分配數(shù)組的長(zhǎng)度,包括未存儲(chǔ)數(shù)據(jù)的部分空間
    • len標(biāo)識(shí)字符串的實(shí)際長(zhǎng)度
    • 當(dāng)冗余的空間不夠時(shí)候,先擴(kuò)容,在復(fù)制舊的內(nèi)容,然后在添加新內(nèi)容,如果字符串長(zhǎng)度非常長(zhǎng),內(nèi)存的分配和復(fù)制開(kāi)銷會(huì)特別大。
  • 以上結(jié)構(gòu)體中,使用的泛型T,其中Capacity和len的類型是T,因?yàn)镽edis對(duì)存儲(chǔ)的壓縮優(yōu)化
    • 當(dāng)存儲(chǔ)字符串比較短的時(shí)候,了你和capacity可以使用byte和short來(lái)表示,
  • Redis規(guī)定字符串長(zhǎng)度不超過(guò)512M,創(chuàng)建字符串時(shí)候len和capacity一樣長(zhǎng),不會(huì)多分配冗余空間,這是因?yàn)榻^大多數(shù)場(chǎng)景下我們不會(huì)去修改字符串。
embstr OR raw
  • Redis字符串有兩種存儲(chǔ)方式,在長(zhǎng)度短的時(shí)候,使用embstr形式存儲(chǔ),長(zhǎng)度超過(guò)44 字節(jié)時(shí)候,使用raw形式存儲(chǔ),如下實(shí)驗(yàn):
新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"
  • 一下我們通過(guò)分析Redis字符串對(duì)象存儲(chǔ)結(jié)構(gòu)來(lái)說(shuō)明兩個(gè)問(wèn)題

    • 問(wèn)題一:為什么是44個(gè)字節(jié)作為界限
    • 問(wèn)題二:embstr 和raw存儲(chǔ)的區(qū)別
  • Redis對(duì)象存儲(chǔ)都會(huì)有一個(gè)頭部結(jié)構(gòu),如下形式

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

  • 同一個(gè)類型的type也會(huì)有不同的存儲(chǔ)方式encoding(4bit)。

  • 為了記錄對(duì)象的lru信息,使用了24bit來(lái)記錄lru信息

  • 每個(gè)對(duì)象都有一個(gè)引用計(jì)數(shù),refcount,當(dāng)他歸零時(shí)候,對(duì)象不被任何地方使用,對(duì)象將被銷毀,內(nèi)存被回收

  • ptr指針結(jié)構(gòu)將指向?qū)ο蟮木唧w存儲(chǔ)位置(body)

  • 以上所有的綜合一起 4bit+ 4bit+ 24bit + 32 bit + 64bit = 128bit = 16byte,所有Redis對(duì)象的對(duì)象頭結(jié)構(gòu)都需要占據(jù)16字節(jié)存儲(chǔ)空間。

  • 接著我們?cè)诜窒鞸DS結(jié)構(gòu)體大小,在字符串比較小的時(shí)候,SDS對(duì)象頭結(jié)構(gòu)的大小如下:

struct SDS{int8 capacity; //1byteint8 len; //1byteint8 flags; //1bytebyte[] content; //存儲(chǔ)數(shù)據(jù)的數(shù)組,長(zhǎng)度capacity }
  • 如上結(jié)構(gòu)中 capacity ,len, flags 三個(gè)都占用1byte的內(nèi)存,其他的就是 capacity長(zhǎng)度的數(shù)組,用來(lái)存儲(chǔ)具體數(shù)據(jù)。也就是最少也要3 個(gè)字節(jié)的存儲(chǔ)空間。加上上面的16byte,我們一個(gè)沒(méi)有存儲(chǔ)字符串的Redis字符串對(duì)象,已經(jīng)有19 byte的空間被系統(tǒng)各種屬性占用。

  • 我們?cè)趦?nèi)存分配的時(shí)候,使用jemalloc, tcmalloc等分配內(nèi)存大小的單元都是2/4/4/8/16/32/64 byte,

  • 為了容納完整的embstr對(duì)象,jemalloc最少分配32byte空間,如果字符串稍微長(zhǎng)點(diǎn),那就是64byte,如果字符串超過(guò)64byte,Redis會(huì)認(rèn)為是一個(gè)大字符串,不在適合emdstr存儲(chǔ)的形式,而使用raw形式

  • 我們用最大內(nèi)存空間64 來(lái)計(jì)算最大字符串長(zhǎng)度, 64 - 19 = 45 ,但是之前實(shí)驗(yàn)得到的是44

  • SDS結(jié)構(gòu)中content中字符串是以null結(jié)尾,多出這個(gè)字節(jié),便于直接使用glbc的字符串處理函數(shù),以及便于字符串的調(diào)試打印輸出。最終得出了44 的長(zhǎng)度。如下圖:

  • 問(wèn)題二中embstr存儲(chǔ)形式與 raw的存儲(chǔ)形式如下

    • embst存儲(chǔ)將RedisObject對(duì)象頭結(jié)構(gòu)和SDS對(duì)象連續(xù)存儲(chǔ)在一起,使用malloc方法一次性分配內(nèi)存
    • raw存儲(chǔ)形式不一樣,他需要兩次malloc方法,兩個(gè)對(duì)象頭在內(nèi)存地址上不連續(xù)通過(guò)對(duì)象頭中 ptr指針來(lái)尋址存儲(chǔ)位置。
擴(kuò)容策略
  • 字符串的擴(kuò)容兩種方式:
    • 字符串長(zhǎng)度在1MB之前,擴(kuò)容空間都是加倍擴(kuò)容,也就是保留100%的冗余空間
    • 字符串長(zhǎng)度超過(guò)1MB后,避免加倍后冗余空間浪費(fèi)過(guò)多,每次只多分配1MB大小的冗余空間。

上一篇:Redis服務(wù)信息–Info指令

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

總結(jié)

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

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。