自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Redis為什么快?你只知道單線程和基于內存?抱歉我不能給你offer...

開發(fā) 后端 Redis
以前就知道Redis快,最多說個Redis是單線程的,說個多路IO復用,說個基于內存的操作就完了,現(xiàn)在是不是還可以展開說說了?

面試場景

面試官:Redis有哪些數(shù)據(jù)類型?

我:String,List,set,zset,hash

面試官:沒了?

我:哦哦哦,還有HyperLogLog,bitMap,GeoHash,BloomFilter

面試官:就這?回家等通知吧。

前言

我敢肯定,第一個回答,100%的人都能說上來,但是第二個回答能回答上來的人可能就不多了,但是這也不是我今天探討的話題。

我就從我自己的去面試的回答思路,以及作為一個面試官他想聽到的標準答案來給大家出一期,Redis基礎類型的文章(系列文章),寫這個的時候我還是很有心得的,不知道大家有多少人跟我最開始一樣,面試官問有哪些類型,就回答出那五種就結束了,如果你是這樣的可以在評論區(qū)留言,讓我看看有多少人是這樣的。

但是,一場面試少說都是半小時起步上不封頂,你這樣一句話就回答了這么重要的五個知識點,這個結果是你想要的么?是面試官想要的么?

我再問你一個問題,你可能就懵逼了:String在Redis底層是怎么存儲的?這些數(shù)據(jù)類型在Redis中是怎么存放的?Redis快的原因就只有單線程和基于內存么?

[[331961]]

寶貝,觸及知識盲區(qū)沒?不慌,我以前也是這樣的,我以為我背出那五種就完事了,結果被面試官安排了一波,后面我苦心修煉,總算是好了一點,現(xiàn)在對緩存也是非常熟悉了,你不會沒事,有我嘛,乖。

正文

Redis是C語言開發(fā)的,C語言自己就有字符類型,但是Redis卻沒直接采用C語言的字符串類型,而是自己構建了動態(tài)字符串(SDS)的抽象類型。

就好比這樣的一個命令,其實我是在Redis創(chuàng)建了兩個SDS,一個是名為aobing的Key SDS,另一個是名為cool的Value SDS,就算是字符類型的List,也是由很多的SDS構成的Key和Value罷了。

SDS在Redis中除了用作字符串,還用作緩沖區(qū)(buffer),那到這里大家都還是有點疑惑的,C語言的字符串不好么為啥用SDS?SDS長啥樣?有什么優(yōu)點呢?

為此我去找到了Redis的源碼,可以看到SDS值的結果大概是這樣的,源碼的在GitHub上是開源的大家一搜就有了。 

  1. struct sdshdr{  
  2.     int len;  
  3.     int free;  
  4.     char buf[];  

回到最初的問題,為什么Redis用了自己新開發(fā)的SDS,而不用C語言的字符串?那好我們去看看他們的區(qū)別。

SDS與C字符串的區(qū)別

  1. 計數(shù)方式不同

C語言對字符串長度的統(tǒng)計,就完全來自遍歷,從頭遍歷到末尾,直到發(fā)現(xiàn)空字符就停止,以此統(tǒng)計出字符串的長度,這樣獲取長度的時間復雜度來說是0(n),大概就像下面這樣:

但是這樣的計數(shù)方式會留下隱患,所以Redis沒有采用C的字符串,我后面會提到。

而Redis我在上面已經(jīng)給大家看過結構了,他自己本身就保存了長度的信息,所以我們獲取長度的時間復雜度為0(1),是不是發(fā)現(xiàn)了Redis快的一點小細節(jié)了?還沒完,不止這些。

  1. 杜絕緩沖區(qū)溢出

字符串拼接是我們經(jīng)常做的操作,在C和Redis中一樣,也是很常見的操作,但是問題就來了,C是不記錄字符串長度的,一旦我們調用了拼接的函數(shù),如果沒有提前計算好內存,是會產(chǎn)生緩存區(qū)溢出的。

比如本來字符串長這樣:

你現(xiàn)在需要在后面拼接 ,但是你沒計算好內存,結果就可能這樣了:

這是你要的結果么?很顯然,不是,你的結果意外的被修改了,這要是放在線上的系統(tǒng),這不是完了?那Redis是怎么避免這樣的情況的?

我們都知道,他結構存儲了當前長度,還有free未使用的長度,那簡單呀,你現(xiàn)在做了拼接操作,我去判斷一些是否可以放得下,如果長度夠就直接執(zhí)行,如果不夠,那我就進行擴容。

這些大家在Redis源碼里面都是可以看到對應的API的,后面我就不一一貼源碼了,有興趣的可以自己去看一波,需要一點C語言的基礎。

  1.  減少修改字符串時帶來的內存重分配次數(shù)

C語言字符串底層也是一個數(shù)組,每次創(chuàng)建的時候就創(chuàng)建一個N+1長度的字符,多的那個1,就是為了保存空字符的,這個空字符也是個坑,但是不是這個環(huán)節(jié)探討的內容。

Redis是個高速緩存數(shù)據(jù)庫,如果我們需要對字符串進行頻繁的拼接和截斷操作,如果我們寫代碼忘記了重新分配內存,就可能造成緩沖區(qū)溢出,以及內存泄露。

內存分配算法很耗時,且不說你會不會忘記重新分配內存,就算你全部記得,對于一個高速緩存數(shù)據(jù)庫來說,這樣的開銷也是我們應該要避免的。

Redis為了避免C字符串這樣的缺陷,就分別采用了兩種解決方案,去達到性能最大化,空間利用最大化:

  •  空間預分配:當我們對SDS進行擴展操作的時候,Redis會為SDS分配好內存,并且根據(jù)特定的公式,分配多余的free空間,還有多余的1byte空間(這1byte也是為了存空字符),這樣就可以避免我們連續(xù)執(zhí)行字符串添加所帶來的內存分配消耗。

比如現(xiàn)在有這樣的一個字符:

我們調用了拼接函數(shù),字符串邊長了,Redis還會根據(jù)算法計算出一個free值給他備用:

我們再繼續(xù)拼接,你會發(fā)現(xiàn),備用的free用上了,省去了這次的內存重分配:

  •  惰性空間釋放:剛才提到了會預分配多余的空間,很多小伙伴會擔心帶來內存的泄露或者浪費,別擔心,Redis大佬一樣幫我們想到了,當我們執(zhí)行完一個字符串縮減的操作,redis并不會馬上收回我們的空間,因為可以預防你繼續(xù)添加的操作,這樣可以減少分配空間帶來的消耗,但是當你再次操作還是沒用到多余空間的時候,Redis也還是會收回對于的空間,防止內存的浪費的。

還是一樣的字符串:

當我們調用了刪減的函數(shù),并不會馬上釋放掉free空間:

如果我們需要繼續(xù)添加這個空間就能用上了,減少了內存的重分配,如果空間不需要了,調用函數(shù)刪掉就好了:

  1. 二進制安全

仔細看的仔肯定看到上面我不止一次提到了空字符也就是’0‘,C語言是判斷空字符去判斷一個字符的長度的,但是有很多數(shù)據(jù)結構經(jīng)常會穿插空字符在中間,比如圖片,音頻,視頻,壓縮文件的二進制數(shù)據(jù),就比如下面這個單詞,他只能識別前面的 不能識別后面的字符,那對于我們開發(fā)者而言,這樣的結果顯然不是我們想要的對不對。

Redis就不存在這個問題了,他不是保存了字符串的長度嘛,他不判斷空字符,他就判斷長度對不對就好了,所以redis也經(jīng)常被我們拿來保存各種二進制數(shù)據(jù),我反正是用的很high,經(jīng)常用來保存小文件的二進制。

 

資料參考:Redis設計與實現(xiàn)

總結

大家是不是發(fā)現(xiàn),一個小小的SDS居然有這么多道理在這?

以前就知道Redis快,最多說個Redis是單線程的,說個多路IO復用,說個基于內存的操作就完了,現(xiàn)在是不是還可以展開說說了?

本文是系列文的第一章,后續(xù)會陸續(xù)更新的,不知道這樣的類型大家是否喜歡。

大家一同去面試,一樣的問題,就是有人能過,有人不能過,大家經(jīng)常歸咎于自己學歷,自己過往經(jīng)歷的原因,但是你可以問一下自己,底層的細節(jié)字節(jié)是否有深究呢?細節(jié)往往才是最重要的,也是最少人知道的,如何和別的仔拉開差距拿到offer,我想就是這樣些細節(jié)決定的吧,背誰不會呢? 

 

責任編輯:龐桂玉 來源: segmentfault
相關推薦

2023-03-21 08:02:36

Redis6.0IO多線程

2019-06-17 14:20:51

Redis數(shù)據(jù)庫Java

2023-10-15 12:23:10

單線程Redis

2019-02-18 08:10:53

2020-06-11 09:35:39

Redis單線程Java

2020-10-30 16:20:38

Redis單線程高并發(fā)

2023-08-17 14:12:17

2019-05-07 09:44:45

Redis高并發(fā)模型

2019-05-06 11:12:18

Redis高并發(fā)單線程

2020-11-09 09:33:37

多線程

2020-10-16 16:00:50

Redis單線程數(shù)據(jù)庫

2019-04-02 11:20:48

Redis高并發(fā)單線程

2020-11-17 10:20:53

Redis多線程單線程

2022-01-04 11:11:32

Redis單線程Reactor

2021-03-03 08:01:58

Redis多線程程序

2025-01-17 08:23:33

2023-02-07 08:18:34

單線程Redis內存

2024-04-03 09:23:31

ES索引分析器

2021-12-28 09:50:18

Redis單線程高并發(fā)

2025-04-24 08:15:00

Redis單線程線程
點贊
收藏

51CTO技術棧公眾號