欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

關(guān)于Redis最常見的十道面試題總結(jié)大全

 更新時間:2024年07月31日 10:19:41   作者:lose_rose777  
Redis作為一個高性能的內(nèi)存數(shù)據(jù)存儲系統(tǒng),具有快速讀寫、持久性、數(shù)據(jù)結(jié)構(gòu)多樣性等特點,廣泛應(yīng)用于各種應(yīng)用場景,這篇文章主要給大家介紹了關(guān)于Redis最常見的十道面試題總結(jié)的相關(guān)資料,需要的朋友可以參考下

面試題一:Redis為什么執(zhí)行這么快?

Redis運行比較快主要原因有以下幾種:

  • 純內(nèi)存操作:Redis將所有數(shù)據(jù)存儲在內(nèi)存中,這意味著對數(shù)據(jù)的讀寫操作直接在內(nèi)存中運行,而內(nèi)存的訪問速度遠遠高于磁盤。這種設(shè)計使得Redis能夠已接近硬件極限的速度處理數(shù)據(jù)讀寫
  • 單線程模型:Redis使用單線程模型來處理客戶端請求。這可能聽起來效率不高,但是實際上,這種設(shè)計避免了多線程頻繁切換和過度競爭帶來的性能開銷。Redis每個請求的執(zhí)行時間都是很短的,因此單線程下,也能處理大量的并發(fā)請求
  • I/O多路復(fù)用:Redis使用了I/O多路復(fù)用技術(shù),可以在單線程的環(huán)境下同時監(jiān)聽多個客戶端連接,只有當(dāng)有網(wǎng)絡(luò)事件(如用戶發(fā)送一個請求)發(fā)生的時候才會進行實際的I/O操作。這樣有效的利用了CPU資源,減少了無謂的等待
  • 高效數(shù)據(jù)結(jié)構(gòu):Redis提供了多種高效的數(shù)據(jù)結(jié)構(gòu),如哈希表、有序集合等。這些數(shù)據(jù)結(jié)構(gòu)的實現(xiàn)都經(jīng)過了優(yōu)化,使得Redis在處理這些數(shù)據(jù)結(jié)構(gòu)的操作是非常高效的

面試題二:Redis是單線程執(zhí)行還是多線程執(zhí)行?它有線程安全問題嗎?為什么嗎?

Redis版本在6.0之前都是使用的單線程運行的。所有的客戶端的請求處理、命令執(zhí)行以及數(shù)據(jù)讀寫操作都是在一個主線程中完成得。這種設(shè)計目的就是為了防止多線程環(huán)境下的鎖競爭和上下文切換所帶來的性能開銷,這樣保證在高并發(fā)場景下的性能

Redis版本在6.0中,開始引入了多線程的支持,但是這僅限于網(wǎng)絡(luò)I/O層面,即在網(wǎng)絡(luò)請求階段使用工作線程進行處理,對于指令的執(zhí)行過程,仍然是在主線程來處理,所以不會存在多個線程通知執(zhí)行操作指令的情況

關(guān)于線程安全問題,從Redis服務(wù)層面?zhèn)z看,Redis Server本身就是一個線程安全按的K-V數(shù)據(jù)庫,也就是說在Redis Server上面執(zhí)行的指令,不需要任何同步機制,不會存在線程安全問題

面試題三:在實際工作中,使用Redis實現(xiàn)了哪些業(yè)務(wù)場景?

Redis在實際工作中廣泛應(yīng)用于多種業(yè)務(wù)場景,以下是一些常見的例子:

緩存:Redis作為Key-Value形態(tài)的內(nèi)存數(shù)據(jù)庫,最先會被想到的應(yīng)用場景就是作為數(shù)據(jù)緩存。Redis提供了鍵過期功能,也提供了鍵淘汰策略,所以Redis用在緩存的場合非常多

排行榜:很多網(wǎng)站都有排行榜應(yīng)用,如京東的月度銷量榜單、商品按時間上新排行榜等。Redis提供的有序集合(zset)數(shù)據(jù)類

分布式會話:在集群模式下,一般會搭建以Redis等內(nèi)存等內(nèi)存數(shù)據(jù)庫為中心的session服務(wù),session不再由容器管理,而是由session服務(wù)及內(nèi)存數(shù)據(jù)庫管理

分布式鎖:在高并發(fā)的情景,可以利用Redis的setnx功能來編寫分布式鎖

面試題四:Redis常用數(shù)據(jù)類型有哪些?

Redis中,常見的數(shù)據(jù)類型有如下幾種:

  • 字符串(String):最簡單的數(shù)據(jù)類型,可以包含任意數(shù)據(jù),如文本、二進制數(shù)據(jù)等。常見的使用場景是存儲Session信息、存儲緩存信息、存儲整數(shù)信息,可以使用incr實現(xiàn)整數(shù)+1,使用decr實現(xiàn)整數(shù)-1
  • 列表(List):有序的字符串元素集合,支持雙端進行插入和刪除操作,可以用作隊列或棧
  • 哈希(Hash):用于存儲對象,類似于關(guān)聯(lián)數(shù)組。每個哈??梢园侄魏团c之相關(guān)聯(lián)的值。常見使用場景是存儲Session信息、存儲商品的購物車,購物車非常適用于哈希字典表示,使用人員唯一編號作為字典的key,value值可以存儲商品的id和數(shù)量等信息、存儲詳情頁等信息
  • 集合(Set):一個無序并唯一的鍵值集合。它常見的使用場景是是仙女關(guān)注功能,比如關(guān)注我的人和我關(guān)注的人,使用集合存儲,可以保證人員不重復(fù)
  • 有序集合(Sorted Set):使用zset表示,相當(dāng)于Set集合類型多了一個排序?qū)傩詓core(分值)。。它常見的使用場景是可以用來存儲排名信息,關(guān)注列表功能,這樣就可以根據(jù)關(guān)注實現(xiàn)排序展示

面試題五:存儲Session信息你會使用哪種數(shù)據(jù)類型?為什么?

在實際工作中,小型的項目會使用Redis存儲Session信息,但是不同業(yè)務(wù)場景存儲Session信息的類型也是不同的,具體來說:

存儲數(shù)據(jù)簡單(不涉及局部更新):使用String類型粗怒觸Session,這樣做的優(yōu)缺點如下:

優(yōu)點:

        存取操作簡單直觀,只需要單個鍵執(zhí)行操作即可

        多余小型Session,存儲開銷相對于較小

缺點:

        如果Session數(shù)據(jù)復(fù)雜或者需要頻繁更新其中的部分字段,則每次更新都需要重新序列化整個Session對象

        不利于查詢Session內(nèi)特定字段值

存儲數(shù)據(jù)復(fù)雜(涉及局部更新):如果Session數(shù)據(jù)結(jié)構(gòu)復(fù)雜且需要頻繁更新或查詢其中個別字段,通常建議使用哈希表存儲Session。每個Session視為一個獨立的哈希表,Session ID作為key,Sesion內(nèi)各個字段作為field-value對存儲在哈希表中。示例:HSET session:123 userId 123 username user1,這樣做的優(yōu)缺點如下:

優(yōu)點:

        可以方便地進行字段級別的讀寫操作,例如 HGET session:23 userd 和 HSET session:123 lastAccessTime now

        更新部分字段時無需修改整個Session內(nèi)容

缺點:

        相對于簡單的字符串存儲,哈希表占用的空間可能更大,尤其時當(dāng)Session數(shù)據(jù)包含多個值的時候

小結(jié): 如果 Session 數(shù)據(jù)結(jié)構(gòu)復(fù)雜且需要頻繁更新或查詢其中的個別字段,通常建議使用哈希表來存儲 Session;而在 Session 數(shù)據(jù)較為簡單、不涉及局部更新的情況下,使用字符串存儲也是可行的選擇

面試題六:有序集合底層是如何實現(xiàn)的?

在Redis7之前,有序集合使用的是ziplist(壓縮列表)+skiplist(跳躍表),當(dāng)數(shù)據(jù)列表元素小于128個,并且所有元素成員的長度都小于64字節(jié)時,使用壓縮列表存儲,否則使用調(diào)表存儲

在Redis之后,有序集合使用listPack(緊湊列表)+skiplist(跳躍表)

面試題七:什么是跳表?為什么使用跳表?

skiplist是一種以空間換時間的數(shù)據(jù)結(jié)構(gòu)。由于鏈表無法進行二分查找,因此借鑒數(shù)據(jù)庫索引的思想,提取出鏈表中的關(guān)鍵姐點(索引),現(xiàn)在關(guān)鍵節(jié)點上查找,在進入下層鏈表查找提取多層關(guān)鍵節(jié)點,就形成了跳表。但是由于索引要占據(jù)一定的空間,所以索引添加的越多,占用的空間越多。

對于一個單鏈表來講,即便鏈表中存儲的數(shù)據(jù)是有序的,如果我們要想在其中查找某個數(shù)據(jù),也只能從頭到尾遍歷鏈表。這樣查找效率就會很低,時間復(fù)雜度會很高O(N)

從這個例子里,我們看出,加來一層索引之后,查找一個結(jié)點需要遍歷的結(jié)點個數(shù)減少了,也就是說查找效率提高了。時間復(fù)雜度從原來的O(n)到O(logn),是一空間換時間的解決方法

面試題八:說一下跳表的查詢流程?

跳表的查詢流程如下:

  • 起始搜索:查詢操作從跳表的頂層開始,跳表的頂層包含一個或多個節(jié)點,從最頂層的頭節(jié)點開始,將當(dāng)前節(jié)點設(shè)置為頭節(jié)點
  • 檢查下一個節(jié)點:檢查當(dāng)前節(jié)點的下一個節(jié)點,如果節(jié)點的分值小于目標(biāo)分值,則向右移動檢查下一個節(jié)點,重復(fù)此步驟,直到找到一個大于目標(biāo)值的節(jié)點,或者最后一個節(jié)點
  • 逐層探索:如果當(dāng)前下一個結(jié)點的值大于目標(biāo)值,或者最后一個節(jié)點,則將當(dāng)前指針向下層進行搜索,重復(fù)上述步驟
  • 終止并返回:在查找的過程中,如果找到了和目標(biāo)分支相同的值,或者遍歷完所有層級仍然未找到對應(yīng)的節(jié)點,則說明要查找的元素不存在于跳表中,則終止查找并返回查詢到的內(nèi)容或NULL值

面試題九:說一下跳表的添加流程?為什么要有“隨機層數(shù)”這個概念?

跳表的添加流程主要是包括以下步驟:

查找插入位置:首先,我們需要找到新元素應(yīng)該插入的位置。這個過程與跳表查找操作類似,我們從最高層所以一年開始,逐層向下查找直到找到最后一個位置,使得該位置前面的元素小于新元素,后面的元素大于新元素

生成隨機層數(shù):在確定新元素插入位置后,我們需要決定新元素在跳表中的層數(shù)。這個層數(shù)是通過一個隨機函數(shù)生成的。每個節(jié)點肯定都有第一層指針(每個節(jié)點都在第一層鏈表中)。如果一個節(jié)點有第i層指針(即節(jié)點已經(jīng)在第一層到第i層鏈表中),那么他又第(i+1)層指針的

插入新元素:根據(jù)生成的隨機層數(shù),我們在相應(yīng)的層中插入新元素。對于每一層,我們都需要更新相應(yīng)的前驅(qū)和后繼指針,使得它們指向新插入的元素

更新跳表的最大層數(shù):如果新插入的元素的層數(shù)大于跳表的當(dāng)前最大層數(shù),我們需要更新跳表的最大層數(shù)

關(guān)于“隨機層數(shù)”的概念,其主要目的是為了保持跳表的平衡性。如果我們固定每個元素的層數(shù),那么在某些情況下,跳表可能會退化成普通的鏈表,從而導(dǎo)致查找效率降低。通過隨機選擇每個元素的層數(shù),我們可以確保跳表的高度大致為log(n),從而保證查找、插入和刪除操作的時間復(fù)雜度為O(log n)

給定如上跳表,假設(shè)要插入節(jié)點2。首先需要判斷節(jié)點2是否已經(jīng)存在,若存在則返回false。否則,隨機生成待插入節(jié)點的層數(shù)

/**
 * 生成隨機層數(shù)[0,maxLevel)
 * 生成的值越大,概率越小
 *
 * @return
 */
private int randomLevel() {
    int level = 0;
    while (Math.random() < PROBABILITY && level < maxLevel - 1) {
        ++level;
    }
    return level;
}

這里的PROBABILITY =0.5。上面算法的意思是返回1的概率是1/2,返回2的概率是1/4,返回3的概率是1/8,依次類推??闯梢粋€分布的話,第0層包含所有節(jié)點,第1層含有1/2個節(jié)點,第2層含有1/4 個節(jié)點…

注意這里有一個最大層數(shù)maxLevel ,也可以不設(shè)置最大層數(shù)。通過這種隨機生成層數(shù)的方式使得實現(xiàn)起來簡單。假設(shè)我們生成的層數(shù)是3

在1和3之間插入節(jié)點2,層數(shù)是3,也就是節(jié)點2跳躍到了第3層

public boolean add(E e) {
    if (contains(e)) {
        return false;
    }
    int level = randomLevel();
    if (level > curLevel) {
        curLevel = level;
    }
    Node newNode = new Node(e);
    Node current = head;
    //插入方向由上到下
    while (level >= 0) {
        //找到比e小的最大節(jié)點
        current = findNext(e, current, level);
        //將newNode插入到current后面
        //newNode的next指針指向該節(jié)點的后繼
        newNode.forwards.add(0, current.next(level));
        //該節(jié)點的next指向newNode
        current.forwards.set(level, newNode);
        level--;//每層都要插入
    }
    size++;
    return true;
}

我們通過一個例子來模擬,由于實現(xiàn)了直觀的打印算法。假設(shè)我們要插入1, 6, 9, 3, 5, 7, 4, 8 過程如下:

add: 1
Level 0:  1

add: 6
Level 0:  1 6

add: 9
Level 2:      9
Level 1:      9
Level 0:  1 6 9

add: 3
Level 2:    3   9
Level 1:    3   9
Level 0:  1 3 6 9

add: 5
Level 2:    3     9
Level 1:    3 5   9
Level 0:  1 3 5 6 9

add: 7
Level 2:    3       9
Level 1:    3 5     9
Level 0:  1 3 5 6 7 9

add: 4
Level 2:    3         9
Level 1:    3   5     9
Level 0:  1 3 4 5 6 7 9

add: 8
Level 2:    3           9
Level 1:    3   5       9
Level 0:  1 3 4 5 6 7 8 9

面試題十:使用Redis如何實現(xiàn)分布式鎖?

實現(xiàn)分布式鎖

使用Redis實現(xiàn)分布式鎖可以通過setnx(set if not exists)命令實現(xiàn),但當(dāng)我們使用setnx創(chuàng)建鍵值成功時,則表中加鎖成功,否則代碼加鎖失敗,實現(xiàn)示例如下:

127.0.0.1:6379> setnx lock true
(integer) 1#創(chuàng)建鎖成功
#邏輯業(yè)務(wù)處理..

當(dāng)我們重復(fù)加鎖時,只有第一次會加鎖成功

127.8..1:6379> setnx lock true # 第一次加鎖
(integer) 1
127.8.8.1:6379> setnx lock true # 第二次加鎖
(integer) 0

從上述命令可以看出,我們可以看執(zhí)行結(jié)果返回是不是1,就可以看出是否加鎖成功

釋放分布式鎖

127.0.0.1:6379> de1 lock
(integer) 1 #釋放鎖

然而,如果使用 setnx ock true 實現(xiàn)分布式鎖會存在死鎖問題,以為 setnx 如未設(shè)置過期時間,鎖忘記刪了或加鎖線程宕機都會導(dǎo)致死鎖,也就是分布式鎖一直被占用的情況

解決死鎖問題

死鎖問題可以通過設(shè)置超時時間來解決,如果超過了超時時間,分布鎖會自動釋放,這樣就不會存在死鎖問題了也就是 setnx和 expire 配合使用,在 Redis 2.6.12 版本之后,新增了一個強大的功能,我們可以使用一個原子操作也就是一條命令來執(zhí)行 setnx 和expire 操作了,實現(xiàn)示例如下:

127.0.0.1:6379> set lock true ex 3 nx
OK #創(chuàng)建鎖成功
127...1:6379> set lock true ex 3 nx
(ni1) #在鎖被占用的時候,企圖獲取鎖失敗

其中ex為設(shè)置超時時間, nx 為元素非空判斷,用來判斷是否能正常使用鎖的。

因此,我們在 Redis 中實現(xiàn)分布式鎖最直接的方案就是使用 set key value ex timeout nx 的方式來實現(xiàn)。

總結(jié)

到此這篇關(guān)于Redis最常見的十道面試題總結(jié)的文章就介紹到這了,更多相關(guān)Redis最常見面試題內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Redis實現(xiàn)用戶簽到的示例代碼

    Redis實現(xiàn)用戶簽到的示例代碼

    Redis的位圖可以高效實現(xiàn)用戶簽到功能,每個bit位對應(yīng)一個簽到狀態(tài),節(jié)省存儲空間,利用SETBIT、GETBIT等命令操作簽到數(shù)據(jù),可統(tǒng)計連續(xù)簽到天數(shù)和本月簽到情況,感興趣的可以了解一下
    2024-09-09
  • Redis如何存儲對象

    Redis如何存儲對象

    這篇文章主要介紹了Redis如何存儲對象,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • 使用Redis實現(xiàn)用戶積分排行榜的教程

    使用Redis實現(xiàn)用戶積分排行榜的教程

    這篇文章主要介紹了使用Redis實現(xiàn)用戶積分排行榜的教程,包括一個用PHP腳本進行操作的例子,需要的朋友可以參考下
    2015-04-04
  • Redis遠程字典服務(wù)器?hash類型示例詳解

    Redis遠程字典服務(wù)器?hash類型示例詳解

    這篇文章主要介紹了Redis遠程字典服務(wù)器?hash類型示例詳解,本文通過示例代碼給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • Redis中一些最常見的面試問題總結(jié)

    Redis中一些最常見的面試問題總結(jié)

    Redis在互聯(lián)網(wǎng)技術(shù)存儲方面使用如此廣泛,幾乎所有的后端技術(shù)面試官都要在Redis的使用和原理方面對小伙伴們進行各種刁難。下面這篇文章主要給大家總結(jié)介紹了關(guān)于Redis中一些最常見的面試問題,需要的朋友可以參考下
    2018-09-09
  • redis發(fā)布訂閱模式的實現(xiàn)

    redis發(fā)布訂閱模式的實現(xiàn)

    本文主要介紹了redis發(fā)布訂閱模式,Redis?的?SUBSCRIBE?命令可以讓客戶端訂閱任意數(shù)量的頻道,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-04-04
  • Redis+Caffeine兩級緩存的實現(xiàn)

    Redis+Caffeine兩級緩存的實現(xiàn)

    本文主要介紹了Redis+Caffeine兩級緩存的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • 利用redis實現(xiàn)排行榜的小秘訣

    利用redis實現(xiàn)排行榜的小秘訣

    這篇文章主要給大家介紹了關(guān)于如何利用redis實現(xiàn)排行榜的小秘訣,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用redis具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • 詳解Redis使用認(rèn)證密碼登錄

    詳解Redis使用認(rèn)證密碼登錄

    本篇文章主要介紹了詳解Redis使用認(rèn)證密碼登錄 。啟用Redis的認(rèn)證密碼可以增加Redis服務(wù)器的安全性。有興趣的可以了解下
    2017-06-06
  • 詳解Redis實現(xiàn)限流的三種方式

    詳解Redis實現(xiàn)限流的三種方式

    這篇文章主要介紹了詳解Redis實現(xiàn)限流的三種方式,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04

最新評論