您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“Redis為什么快”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
Redis是C語言開發(fā)的,C語言自己就有字符類型,但是Redis卻沒直接采用C語言的字符串類型,而是自己構(gòu)建了動態(tài)字符串(SDS)的抽象類型。
就好比這樣的一個命令,其實我是在Redis創(chuàng)建了兩個SDS,一個是名為aobing的Key SDS,另一個是名為cool的Value SDS,就算是字符類型的List,也是由很多的SDS構(gòu)成的Key和Value罷了。
SDS在Redis中除了用作字符串,還用作緩沖區(qū)(buffer),那到這里大家都還是有點疑惑的,C語言的字符串不好么為啥用SDS?SDS長啥樣?有什么優(yōu)點呢?
為此我去找到了Redis的源碼,可以看到SDS值的結(jié)果大概是這樣的,源碼的在GitHub上是開源的大家一搜就有了。
struct sdshdr{ int len; int free; char buf[]; }
回到最初的問題,為什么Redis用了自己新開發(fā)的SDS,而不用C語言的字符串?那好我們?nèi)タ纯此麄兊膮^(qū)別。
SDS與C字符串的區(qū)別
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)
計數(shù)方式不同
C語言對字符串長度的統(tǒng)計,就完全來自遍歷,從頭遍歷到末尾,直到發(fā)現(xiàn)空字符就停止,以此統(tǒng)計出字符串的長度,這樣獲取長度的時間復(fù)雜度來說是0(n),大概就像下面這樣:
但是這樣的計數(shù)方式會留下隱患,所以Redis沒有采用C的字符串,我后面會提到。
而Redis我在上面已經(jīng)給大家看過結(jié)構(gòu)了,他自己本身就保存了長度的信息,所以我們獲取長度的時間復(fù)雜度為0(1),是不是發(fā)現(xiàn)了Redis快的一點小細(xì)節(jié)了?還沒完,不止這些。
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)
杜絕緩沖區(qū)溢出
字符串拼接是我們經(jīng)常做的操作,在C和Redis中一樣,也是很常見的操作,但是問題就來了,C是不記錄字符串長度的,一旦我們調(diào)用了拼接的函數(shù),如果沒有提前計算好內(nèi)存,是會產(chǎn)生緩存區(qū)溢出的。
比如本來字符串長這樣:
你現(xiàn)在需要在后面拼接 ,但是你沒計算好內(nèi)存,結(jié)果就可能這樣了:
這是你要的結(jié)果么?很顯然,不是,你的結(jié)果意外的被修改了,這要是放在線上的系統(tǒng),這不是完了?那Redis是怎么避免這樣的情況的?
我們都知道,他結(jié)構(gòu)存儲了當(dāng)前長度,還有free未使用的長度,那簡單呀,你現(xiàn)在做了拼接操作,我去判斷一些是否可以放得下,如果長度夠就直接執(zhí)行,如果不夠,那我就進行擴容。
這些大家在Redis源碼里面都是可以看到對應(yīng)的API的,后面我就不一一貼源碼了,有興趣的可以自己去看一波,需要一點C語言的基礎(chǔ)。
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)
減少修改字符串時帶來的內(nèi)存重分配次數(shù)
C語言字符串底層也是一個數(shù)組,每次創(chuàng)建的時候就創(chuàng)建一個N+1長度的字符,多的那個1,就是為了保存空字符的,這個空字符也是個坑,但是不是這個環(huán)節(jié)探討的內(nèi)容。
Redis是個高速緩存數(shù)據(jù)庫,如果我們需要對字符串進行頻繁的拼接和截斷操作,如果我們寫代碼忘記了重新分配內(nèi)存,就可能造成緩沖區(qū)溢出,以及內(nèi)存泄露。
內(nèi)存分配算法很耗時,且不說你會不會忘記重新分配內(nèi)存,就算你全部記得,對于一個高速緩存數(shù)據(jù)庫來說,這樣的開銷也是我們應(yīng)該要避免的。
Redis為了避免C字符串這樣的缺陷,就分別采用了兩種解決方案,去達(dá)到性能最大化,空間利用最大化:
空間預(yù)分配:當(dāng)我們對SDS進行擴展操作的時候,Redis會為SDS分配好內(nèi)存,并且根據(jù)特定的公式,分配多余的free空間,還有多余的1byte空間(這1byte也是為了存空字符),這樣就可以避免我們連續(xù)執(zhí)行字符串添加所帶來的內(nèi)存分配消耗。
比如現(xiàn)在有這樣的一個字符:
我們調(diào)用了拼接函數(shù),字符串邊長了,Redis還會根據(jù)算法計算出一個free值給他備用:
我們再繼續(xù)拼接,你會發(fā)現(xiàn),備用的free用上了,省去了這次的內(nèi)存重分配:
惰性空間釋放:剛才提到了會預(yù)分配多余的空間,很多小伙伴會擔(dān)心帶來內(nèi)存的泄露或者浪費,別擔(dān)心,Redis大佬一樣幫我們想到了,當(dāng)我們執(zhí)行完一個字符串縮減的操作,redis并不會馬上收回我們的空間,因為可以預(yù)防你繼續(xù)添加的操作,這樣可以減少分配空間帶來的消耗,但是當(dāng)你再次操作還是沒用到多余空間的時候,Redis也還是會收回對于的空間,防止內(nèi)存的浪費的。
還是一樣的字符串:
當(dāng)我們調(diào)用了刪減的函數(shù),并不會馬上釋放掉free空間:
如果我們需要繼續(xù)添加這個空間就能用上了,減少了內(nèi)存的重分配,如果空間不需要了,調(diào)用函數(shù)刪掉就好了:
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)
二進制安全
仔細(xì)看的仔肯定看到上面我不止一次提到了空字符也就是’0‘,C語言是判斷空字符去判斷一個字符的長度的,但是有很多數(shù)據(jù)結(jié)構(gòu)經(jīng)常會穿插空字符在中間,比如圖片,音頻,視頻,壓縮文件的二進制數(shù)據(jù),就比如下面這個單詞,他只能識別前面的 不能識別后面的字符,那對于我們開發(fā)者而言,這樣的結(jié)果顯然不是我們想要的對不對。
Redis就不存在這個問題了,他不是保存了字符串的長度嘛,他不判斷空字符,他就判斷長度對不對就好了,所以redis也經(jīng)常被我們拿來保存各種二進制數(shù)據(jù),我反正是用的很high,經(jīng)常用來保存小文件的二進制。
“Redis為什么快”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。