1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        應(yīng)對(duì)面試你要掌握 Redis 哪些原理

        共 5614字,需瀏覽 12分鐘

         ·

        2021-06-13 02:26


        • 案例背景

        • 案例分析

        • 案例解答

          • Redis 如何實(shí)現(xiàn)數(shù)據(jù)不丟失?

          • AOF 日志是如何實(shí)現(xiàn)的?

          • AOF 執(zhí)行過(guò)程

          • 那么 RDB 快照是如何實(shí)現(xiàn)的呢?

          • RDB 做快照時(shí)會(huì)阻塞線程嗎?

          • RDB 做快照的時(shí)候數(shù)據(jù)能修改嗎?

          • Redis 如何實(shí)現(xiàn)服務(wù)高可用?

        • 總結(jié)


        提及緩存,就不得不提 Redis,Redis 已經(jīng)是現(xiàn)在使用最廣泛的緩存中間件了

        案例背景

        我們現(xiàn)在就模擬一場(chǎng)面試,假如我是面試官,你是候選人,我問(wèn)你:

        Redis 屬于單線程還是多線程?

        這道題其實(shí)就在考察 Redis 的線程模型(這幾乎是 Redis 必問(wèn)的問(wèn)題之一)。

        案例分析

        很多人基本都知道 Redis 是單線程的,并且能說(shuō)出 Redis 單線程的一些優(yōu)缺點(diǎn),比如,實(shí)現(xiàn)簡(jiǎn)單,可以在無(wú)鎖的情況下完成所有操作,不存在死鎖和線程切換帶來(lái)的性能和時(shí)間上的開(kāi)銷,但同時(shí)單線程也不能發(fā)揮多核 CPU 的性能。

        很明顯,如果你停留在上面的回答思路上,只能勉強(qiáng)及格,因?yàn)閷?duì)于這樣一道經(jīng)典的面試題,你回答得沒(méi)有亮點(diǎn),幾乎喪失了機(jī)會(huì)。一個(gè)相對(duì)完整的思路應(yīng)該基于 Redis 單線程,補(bǔ)充相關(guān)的知識(shí)點(diǎn),比如:

        Redis 只有單線程嗎?

        Redis 是單線程的,主要是指 Redis 的網(wǎng)絡(luò) I/O 線程,以及鍵值的 SET 和 GET 等讀寫(xiě)操作都是由一個(gè)線程來(lái)完成的。但 Redis 的持久化、集群同步等操作,則是由另外的線程來(lái)執(zhí)行的。

        Redis 采用單線程為什么還這么快?

        一般來(lái)說(shuō),單線程的處理能力應(yīng)該要比多線程差才對(duì),但為什么 Redis 還能達(dá)到每秒數(shù)萬(wàn)級(jí)的處理能力呢?主要有如下幾個(gè)原因。

        首先,一個(gè)重要的原因是,Redis 的大部分操作都在內(nèi)存中完成,并且采用了高效的數(shù)據(jù)結(jié)構(gòu),比如哈希表和跳表。

        其次,因?yàn)槭菃尉€程模型避免了多線程之間的競(jìng)爭(zhēng),省去了多線程切換帶來(lái)的時(shí)間和性能上的開(kāi)銷,而且也不會(huì)導(dǎo)致死鎖問(wèn)題。

        最后,也是最重要的一點(diǎn), Redis 采用了 I/O 多路復(fù)用機(jī)制處理大量的客戶端 Socket 請(qǐng)求,這讓 Redis 可以高效地進(jìn)行網(wǎng)絡(luò)通信,因?yàn)榛诜亲枞?I/O 模型,就意味著 I/O 的讀寫(xiě)流程不再阻塞。

        但是因?yàn)?Redis 不同版本的特殊性,所以對(duì)于 Redis 的線程模型要分版本來(lái)看。

        Redis 4.0 版本之前,使用單線程速度快的原因就是上述的幾個(gè)原因;

        Redis 4.0 版本之后,Redis 添加了多線程的支持,但這時(shí)的多線程主要體現(xiàn)在大數(shù)據(jù)的異步刪除功能上,例如 unlink key、flushdb async、flushall async 等。

        Redis 6.0 版本之后,為了更好地提高 Redis 的性能,新增了多線程 I/O 的讀寫(xiě)并發(fā)能力,但是在面試中,能把 Redis 6.0 中的多線程模型回答上來(lái)的人很少,如果你能在面試中補(bǔ)充 Redis 6.0 多線程的原理,勢(shì)必會(huì)增加面試官對(duì)你的認(rèn)可。

        你可以在面試中這樣補(bǔ)充:

        雖然 Redis 一直是單線程模型,但是在 Redis 6.0 版本之后,也采用了多個(gè) I/O 線程來(lái)處理網(wǎng)絡(luò)請(qǐng)求,這是因?yàn)殡S著網(wǎng)絡(luò)硬件的性能提升,Redis 的性能瓶頸有時(shí)會(huì)出現(xiàn)在網(wǎng)絡(luò) I/O 的處理上,所以為了提高網(wǎng)絡(luò)請(qǐng)求處理的并行度,Redis 6.0 對(duì)于網(wǎng)絡(luò)請(qǐng)求采用多線程來(lái)處理。但是對(duì)于讀寫(xiě)命令,Redis 仍然使用單線程來(lái)處理。

        從圖中,你可以看到,線程模型只是高性能考點(diǎn)中的一環(huán),而高可用考點(diǎn)中,包括了持久化、數(shù)據(jù)復(fù)制(主從復(fù)制,哨兵復(fù)制)等內(nèi)容。

        Redis 是如何實(shí)現(xiàn)數(shù)據(jù)不丟失的(考察持久化)?

        Redis 是如何實(shí)現(xiàn)服務(wù)高可用的(考察數(shù)據(jù)復(fù)制)?

        案例解答

        Redis 如何實(shí)現(xiàn)數(shù)據(jù)不丟失?

        我們知道,緩存數(shù)據(jù)庫(kù)的讀寫(xiě)都是在內(nèi)存中,所以它的性能才會(huì)高,但在內(nèi)存中的數(shù)據(jù)會(huì)隨著服務(wù)器的重啟而丟失,為了保證數(shù)據(jù)不丟失,要把內(nèi)存中的數(shù)據(jù)存儲(chǔ)到磁盤(pán),以便緩存服務(wù)器重啟之后,還能夠從磁盤(pán)中恢復(fù)原有的數(shù)據(jù),這個(gè)過(guò)程就是 Redis 的數(shù)據(jù)持久化。

        這也是 Redis 區(qū)別于其他緩存數(shù)據(jù)庫(kù)的優(yōu)點(diǎn)之一(比如 Memcached 就不具備持久化功能)。Redis 的數(shù)據(jù)持久化有三種方式。

        • AOF 日志(Append Only File,文件追加方式):記錄所有的操作命令,并以文本的形式追加到文件中。

        • RDB 快照(Redis DataBase):將某一個(gè)時(shí)刻的內(nèi)存數(shù)據(jù),以二進(jìn)制的方式寫(xiě)入磁盤(pán)。

        • 混合持久化方式:Redis 4.0 新增了混合持久化的方式,集成了 RDB 和 AOF 的優(yōu)點(diǎn)。

        接下來(lái)我們看一下這三種方式的實(shí)現(xiàn)原理。

        AOF 日志是如何實(shí)現(xiàn)的?

        通常情況下,關(guān)系型數(shù)據(jù)庫(kù)(如 MySQL)的日志都是“寫(xiě)前日志”(Write Ahead Log, WAL),也就是說(shuō),在實(shí)際寫(xiě)數(shù)據(jù)之前,先把修改的數(shù)據(jù)記到日志文件中,以便當(dāng)出現(xiàn)故障時(shí)進(jìn)行恢復(fù),比如 MySQL 的 redo log(重做日志),記錄的就是修改后的數(shù)據(jù)。

        而 AOF 里記錄的是 Redis 收到的每一條命令,這些命令是以文本形式保存的,不同的是,Redis 的 AOF 日志的記錄順序與傳統(tǒng)關(guān)系型數(shù)據(jù)庫(kù)正好相反,它是寫(xiě)后日志,“寫(xiě)后”是指 Redis 要先執(zhí)行命令,把數(shù)據(jù)寫(xiě)入內(nèi)存,然后再記錄日志到文件。

        AOF 執(zhí)行過(guò)程

        那么面試的考察點(diǎn)來(lái)了:Reids 為什么先執(zhí)行命令,在把數(shù)據(jù)寫(xiě)入日志呢?為了方便你理解,我整理了關(guān)鍵的記憶點(diǎn):

        • 因?yàn)?,Redis 在寫(xiě)入日志之前,不對(duì)命令進(jìn)行語(yǔ)法檢查;

        • 所以,只記錄執(zhí)行成功的命令,避免了出現(xiàn)記錄錯(cuò)誤命令的情況;

        • 并且,在命令執(zhí)行完之后再記錄,不會(huì)阻塞當(dāng)前的寫(xiě)操作。

        當(dāng)然,這樣做也會(huì)帶來(lái)風(fēng)險(xiǎn)(這一點(diǎn)你也要在面試中給出解釋)。

        • 數(shù)據(jù)可能會(huì)丟失:如果 Redis 剛執(zhí)行完命令,此時(shí)發(fā)生故障宕機(jī),會(huì)導(dǎo)致這條命令存在丟失的風(fēng)險(xiǎn)。

        • 可能阻塞其他操作:雖然 AOF 是寫(xiě)后日志,避免阻塞當(dāng)前命令的執(zhí)行,但因?yàn)?AOF 日志也是在主線程中執(zhí)行,所以當(dāng) Redis 把日志文件寫(xiě)入磁盤(pán)的時(shí)候,還是會(huì)阻塞后續(xù)的操作無(wú)法執(zhí)行。

        又因?yàn)?Redis 的持久化離不開(kāi) AOF 和 RDB,所以我們就需要學(xué)習(xí) RDB。

        那么 RDB 快照是如何實(shí)現(xiàn)的呢?

        因?yàn)?AOF 日志記錄的是操作命令,不是實(shí)際的數(shù)據(jù),所以用 AOF 方法做故障恢復(fù)時(shí),需要全量把日志都執(zhí)行一遍,一旦日志非常多,勢(shì)必會(huì)造成 Redis 的恢復(fù)操作緩慢。

        為了解決這個(gè)問(wèn)題,Redis 增加了 RDB 內(nèi)存快照(所謂內(nèi)存快照,就是將內(nèi)存中的某一時(shí)刻狀態(tài)以數(shù)據(jù)的形式記錄在磁盤(pán)中)的操作,它即可以保證可靠性,又能在宕機(jī)時(shí)實(shí)現(xiàn)快速恢復(fù)。

        和 AOF 不同的是,RDB 記錄 Redis 某一時(shí)刻的數(shù)據(jù),而不是操作,所以在做數(shù)據(jù)恢復(fù)時(shí)候,只需要直接把 RDB 文件讀入內(nèi)存,完成快速恢復(fù)。

        RDB 做快照時(shí)會(huì)阻塞線程嗎?

        因?yàn)?Redis 的單線程模型決定了它所有操作都要盡量避免阻塞主線程,所以對(duì)于 RDB 快照也不例外,這關(guān)系到是否會(huì)降低 Redis 的性能。

        為了解決這個(gè)問(wèn)題,Redis 提供了兩個(gè)命令來(lái)生成 RDB 快照文件,分別是 save 和 bgsave。save 命令在主線程中執(zhí)行,會(huì)導(dǎo)致阻塞。而 bgsave 命令則會(huì)創(chuàng)建一個(gè)子進(jìn)程,用于寫(xiě)入 RDB 文件的操作,避免了對(duì)主線程的阻塞,這也是 Redis RDB 的默認(rèn)配置。

        RDB 做快照的時(shí)候數(shù)據(jù)能修改嗎?

        這個(gè)問(wèn)題非常重要,考察候選人對(duì) RDB 的技術(shù)掌握得夠不夠深。你可以思考一下,如果在執(zhí)行快照的過(guò)程中,數(shù)據(jù)如果能被修改或者不能被修改都會(huì)帶來(lái)什么影響?

        如果此時(shí)可以執(zhí)行寫(xiě)操作:意味著 Redis 還能正常處理寫(xiě)操作,就可能出現(xiàn)正在執(zhí)行快照的數(shù)據(jù)是已經(jīng)被修改了的情況;

        如果此時(shí)不可以執(zhí)行寫(xiě)操作:意味著 Redis 的所有寫(xiě)操作都得等到快照?qǐng)?zhí)行完成之后才能執(zhí)行,那么就又出現(xiàn)了阻塞主線程的問(wèn)題。

        那Redis 是如何解決這個(gè)問(wèn)題的呢?它利用了 bgsave 的子進(jìn)程,具體操作如下:

        如果主線程執(zhí)行讀操作,則主線程和 bgsave 子進(jìn)程互相不影響;

        如果主線程執(zhí)行寫(xiě)操作,則被修改的數(shù)據(jù)會(huì)復(fù)制一份副本,然后 bgsave 子進(jìn)程會(huì)把該副本數(shù)據(jù)寫(xiě)入 RDB 文件,在這個(gè)過(guò)程中,主線程仍然可以直接修改原來(lái)的數(shù)據(jù)。

        要注意,Redis 對(duì) RDB 的執(zhí)行頻率非常重要,因?yàn)檫@會(huì)影響快照數(shù)據(jù)的完整性以及 Redis 的穩(wěn)定性,所以在 Redis 4.0 后,增加了 AOF 和 RDB 混合的數(shù)據(jù)持久化機(jī)制:把數(shù)據(jù)以 RDB 的方式寫(xiě)入文件,再將后續(xù)的操作命令以 AOF 的格式存入文件,既保證了 Redis 重啟速度,又降低數(shù)據(jù)丟失風(fēng)險(xiǎn)。

        我們來(lái)總結(jié)一下,當(dāng)面試官問(wèn)你“Redis 是如何實(shí)現(xiàn)數(shù)據(jù)不丟失的”時(shí),你首先要意識(shí)到這是在考察你對(duì) Redis 數(shù)據(jù)持久化知識(shí)的掌握程度,那么你的回答思路是:先說(shuō)明 Redis 有幾種持久化的方式,然后分析 AOF 和 RDB 的原理以及存在的問(wèn)題,最后分析一下 Redis 4.0 版本之后的持久化機(jī)制。

        Redis 如何實(shí)現(xiàn)服務(wù)高可用?

        另外,Redis 不僅僅可以用來(lái)當(dāng)作緩存,很多時(shí)候也會(huì)直接作為數(shù)據(jù)存儲(chǔ),那么你就要一個(gè)高可用的 Redis 服務(wù),來(lái)支撐和保證業(yè)務(wù)的正常運(yùn)行。那么你怎么設(shè)計(jì)一個(gè)不宕機(jī)的 Redis 高可用服務(wù)呢?

        思考一下,解決數(shù)據(jù)高可用的手段是什么?是副本。那么要想設(shè)計(jì)一個(gè)高可用的 Redis 服務(wù),一定要從 Redis 的多服務(wù)節(jié)點(diǎn)來(lái)考慮,比如 Redis 的主從復(fù)制、哨兵模式,以及 Redis 集群。這三點(diǎn)是你一定要在面試中回答出來(lái)的。

        主從同步 (主從復(fù)制)

        這是 Redis 高可用服務(wù)的最基礎(chǔ)的保證,實(shí)現(xiàn)方案就是將從前的一臺(tái) Redis 服務(wù)器,同步數(shù)據(jù)到多臺(tái)從 Redis 服務(wù)器上,即一主多從的模式,這樣我們就可以對(duì) Redis 做讀寫(xiě)分離了,來(lái)承載更多的并發(fā)操作,這里和 MySQL 的主從復(fù)制原理上是一樣的。

        Redis Sentinel(哨兵模式)

        在使用 Redis 主從服務(wù)的時(shí)候,會(huì)有一個(gè)問(wèn)題,就是當(dāng) Redis 的主從服務(wù)器出現(xiàn)故障宕機(jī)時(shí),需要手動(dòng)進(jìn)行恢復(fù),為了解決這個(gè)問(wèn)題,Redis 增加了哨兵模式(因?yàn)樯诒J阶龅搅丝梢员O(jiān)控主從服務(wù)器,并且提供自動(dòng)容災(zāi)恢復(fù)的功能)。

        Redis Cluster(集群)

        Redis Cluster 是一種分布式去中心化的運(yùn)行模式,是在 Redis 3.0 版本中推出的 Redis 集群方案,它將數(shù)據(jù)分布在不同的服務(wù)器上,以此來(lái)降低系統(tǒng)對(duì)單主節(jié)點(diǎn)的依賴,從而提高 Redis 服務(wù)的讀寫(xiě)性能。

        Redis Cluster 方案采用哈希槽(Hash Slot),來(lái)處理數(shù)據(jù)和實(shí)例之間的映射關(guān)系。在 Redis Cluster 方案中,一個(gè)切片集群共有 16384 個(gè)哈希槽,這些哈希槽類似于數(shù)據(jù)分區(qū),每個(gè)鍵值對(duì)都會(huì)根據(jù)它的 key,被映射到一個(gè)哈希槽中,具體執(zhí)行過(guò)程分為兩大步。

        1. 根據(jù)鍵值對(duì)的 key,按照 CRC16 算法計(jì)算一個(gè) 16 bit 的值。

        2. 再用 16bit 值對(duì) 16384 取模,得到 0~16383 范圍內(nèi)的模數(shù),每個(gè)模數(shù)代表一個(gè)相應(yīng)編號(hào)的哈希槽。

        剩下的一個(gè)問(wèn)題就是,這些哈希槽怎么被映射到具體的 Redis 實(shí)例上的呢?有兩種方案。

        • 平均分配:在使用 cluster create 命令創(chuàng)建 Redis 集群時(shí),Redis 會(huì)自動(dòng)把所有哈希槽平均分布到集群實(shí)例上。比如集群中有 9 個(gè)實(shí)例,則每個(gè)實(shí)例上槽的個(gè)數(shù)為 16384/9 個(gè)。

        • 手動(dòng)分配:可以使用 cluster meet 命令手動(dòng)建立實(shí)例間的連接,組成集群,再使用 cluster addslots 命令,指定每個(gè)實(shí)例上的哈希槽個(gè)數(shù),為了方便你的理解,我通過(guò)一張圖來(lái)解釋數(shù)據(jù)、哈希槽,以及實(shí)例三者的映射分布關(guān)系。

        示意圖中的分片集群一共有 3 個(gè)實(shí)例,假設(shè)有 4 個(gè)哈希槽時(shí),我們就可以通過(guò)命令手動(dòng)分配哈希槽,比如實(shí)例 1 保存哈希槽 0 和 1,實(shí)例 2 保存哈希槽 2 和 3。

        然后在集群運(yùn)行的過(guò)程中,key1 和 key2 計(jì)算完 CRC16 值后,對(duì)哈希槽總個(gè)數(shù) 5 進(jìn)行取模,再根據(jù)各自的模數(shù)結(jié)果,就可以被映射到對(duì)應(yīng)的實(shí)例 1 和實(shí)例 3 上了。

        主從同步是 Redis 高可用最基礎(chǔ)的服務(wù)高可用方案,但它當(dāng)發(fā)生故障時(shí),需要手動(dòng)恢復(fù)故障,因此就有了哨兵模式用于監(jiān)控和實(shí)現(xiàn)主從服務(wù)器的自動(dòng)容災(zāi)。

        總結(jié)

        Redis 的三個(gè)核心問(wèn)題:線程模型、數(shù)據(jù)持久化,以及高可用,分別描述了:

        • 對(duì)于線程模型的知識(shí)點(diǎn),你要分開(kāi)三條線進(jìn)行理解(Redis 4.0 之前、Redis 4.0 之后,以及 Redis 6.0)。

        • 對(duì)于數(shù)據(jù)持久化,你要掌握 Redis 持久化的幾種方案,AOF 和 RDB 的原理,以及為了彌補(bǔ)他們的缺點(diǎn),Redis 增加了混合持久化方式,以較小的性能開(kāi)銷保證數(shù)據(jù)的可靠性。

        • 實(shí)現(xiàn)高可用的三種手段:主從同步、哨兵模式和 Redis 集群服務(wù),對(duì)于 Redis 集群,你要掌握哈希槽的數(shù)據(jù)分布機(jī)制,以及自動(dòng)分配和手動(dòng)分配的實(shí)現(xiàn)原理 。

        — 【 THE END 】—
        本公眾號(hào)全部博文已整理成一個(gè)目錄,請(qǐng)?jiān)诠娞?hào)里回復(fù)「m」獲?。?/span>

        最近面試BAT,整理一份面試資料Java面試BATJ通關(guān)手冊(cè),覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫(kù)、數(shù)據(jù)結(jié)構(gòu)等等。

        獲取方式:點(diǎn)“在看”,關(guān)注公眾號(hào)并回復(fù) PDF 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

        文章有幫助的話,在看,轉(zhuǎn)發(fā)吧。

        謝謝支持喲 (*^__^*)

        瀏覽 66
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            女人的下面无遮无挡 | 国产麻豆天美果冻无码视频 | 青青草A片成人网站免费看 | 成人做爰黄 片视频免费观看 | 国产最爽的乱淫视频媛 | 兔费A片免费看 | 午夜成人免费福利 | 亚洲精品成人网站 | 久久久精品美女 | 天堂a|