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

詳解Redis單線程架構(gòu)的優(yōu)勢(shì)與不足

 更新時(shí)間:2024年02月25日 09:00:35   作者:潔潔!  
很多人都遇到過(guò)這么一道面試題:Redis是單線程還是多線程?這個(gè)問(wèn)題既簡(jiǎn)單又復(fù)雜,說(shuō)他簡(jiǎn)單是因?yàn)榇蠖鄶?shù)人都知道Redis是單線程,說(shuō)復(fù)雜是因?yàn)檫@個(gè)答案其實(shí)并不準(zhǔn)確,本文就給大家講講Redis單線程架構(gòu)的優(yōu)勢(shì)與不足,需要的朋友可以參考下

難道Redis不是單線程?我們啟動(dòng)一個(gè)Redis實(shí)例,驗(yàn)證一下就知道了。Redis安裝部署方式如下所示:

// 下載
wget https://download.redis.io/redis-stable.tar.gz
tar -xzvf redis-stable.tar.gz
// 編譯安裝
cd redis-stable
make
// 驗(yàn)證是否安裝成功
./src/redis-server -v
Redis server v=7.2.4

接下來(lái)啟動(dòng)Redis實(shí)例,使用命令ps查看所有線程,如下所示:

// 啟動(dòng)Redis實(shí)例
./src/redis-server ./redis.conf

// 查看實(shí)例進(jìn)程ID
ps aux | grep redis
root     385806  0.0  0.0 245472 11200 pts/2    Sl+  17:32   0:00 ./src/redis-server 127.0.0.1:6379

// 查看所有線程
ps -L -p 385806
   PID    LWP TTY          TIME CMD
385806 385806 pts/2    00:00:00 redis-server
385806 385809 pts/2    00:00:00 bio_close_file
385806 385810 pts/2    00:00:00 bio_aof
385806 385811 pts/2    00:00:00 bio_lazy_free
385806 385812 pts/2    00:00:00 jemalloc_bg_thd
385806 385813 pts/2    00:00:00 jemalloc_bg_thd

竟然有6個(gè)線程!不是說(shuō)Redis是單線程嗎?怎么會(huì)有這么多線程呢?

這6個(gè)線程的含義你可能不太了解,但是通過(guò)這個(gè)示例至少說(shuō)明Redis并不是單線程。

01 Redis中的多線程

接下來(lái)我們逐個(gè)介紹上述6個(gè)線程的作用:

redis-server:

主線程,用于接收并處理客戶端請(qǐng)求。

jemalloc_bg_thd

jemalloc 是新一代的內(nèi)存分配器,Redis底層使用他管理內(nèi)存。

bio_xxx:

以bio前綴開始的都是異步線程,用于異步執(zhí)行一些耗時(shí)任務(wù)。其中,線程bio_close_file用于異步刪除文件,線程bio_aof用于異步將AOF文件刷到磁盤,線程bio_lazy_free用于異步刪除數(shù)據(jù)(懶刪除)。

需要說(shuō)明的是,主線程是通過(guò)隊(duì)列將任務(wù)分發(fā)給異步線程的,并且這一操作是需要加鎖的。主線程與異步線程的關(guān)系如下圖所示:

請(qǐng)?zhí)砑訄D片描述

  • 主線程與異步線程
    這里我們以懶刪除為例,講解為什么要使用異步線程。Redis是一款內(nèi)存數(shù)據(jù)庫(kù),支持多種數(shù)據(jù)類型,包括字符串、列表、哈希表、集合等。思考一下,刪除(DEL)列表類型數(shù)據(jù)的流程是怎樣的呢?第一步從數(shù)據(jù)庫(kù)字典中刪除該鍵值對(duì),第二步遍歷并刪除列表中的所有元素(釋放內(nèi)存)。想想如果列表中的元素?cái)?shù)目非常多呢?這一步將非常耗時(shí)。這種刪除方式稱為同步刪除,流程如下圖所示:

請(qǐng)?zhí)砑訄D片描述

  • 同步刪除流程圖
    針對(duì)上述問(wèn)題,Redis提出了懶刪除(異步刪除),主線程在收到刪除命令(UNLINK)時(shí),首先從數(shù)據(jù)庫(kù)字典中刪除該鍵值對(duì),隨后再將刪除任務(wù)分發(fā)給異步線程bio_lazy_free,由異步線程執(zhí)行第二步耗時(shí)邏輯。這時(shí)候的流程如下圖所示:

請(qǐng)?zhí)砑訄D片描述

  • 懶刪除流程圖

02 I/O多線程

難道Redis是多線程?那為什么我們老說(shuō)Redis是單線程呢?這是因?yàn)樽x取客戶端命令請(qǐng)求,執(zhí)行命令以及向客戶端返回結(jié)果都是在主線程完成的。不然的話,多線程同時(shí)操作內(nèi)存數(shù)據(jù)庫(kù),并發(fā)問(wèn)題如何解決?如果每次操作之前都加鎖,那和單線程又有什么區(qū)別呢?

當(dāng)然這一流程在Redis6.0版本也發(fā)生了改變,Redis官方指出,Redis是基于內(nèi)存的鍵值對(duì)數(shù)據(jù)庫(kù),執(zhí)行命令的過(guò)程是非常快的,讀取客戶端命令請(qǐng)求和向客戶端返回結(jié)果(即網(wǎng)絡(luò)I/O)通常會(huì)成為Redis的性能瓶頸。

因此,在Redis 6.0版本,作者加入了多線程I/O的能力,即可以開啟多個(gè)I/O線程,并行讀取客戶端命令請(qǐng)求,并行向客戶端返回結(jié)果。I/O多線程能力使得Redis性能提升至少一倍。

為了開啟多線程I/O能力,需要先修改配置文件redis.conf:

io-threads-do-reads yes
io-threads 4

這兩個(gè)配置含義如下:

io-threads-do-reads:是否開啟多線程I/O能力,默認(rèn)為"no";

io-threads:I/O線程數(shù)目,默認(rèn)為1,即只使用主線程執(zhí)行網(wǎng)絡(luò)I/O,線程數(shù)最大為128;該配置應(yīng)該根據(jù)CPU核數(shù)設(shè)置,作者建議,4核CPU設(shè)置2~3個(gè)I/O線程,8核CPU設(shè)置6個(gè)I/O線程。

開啟多線程I/O能力之后,重新啟動(dòng)Redis實(shí)例,查看所有線程,結(jié)果如下:

ps -L -p 104648
   PID    LWP TTY          TIME CMD
104648 104648 pts/1    00:00:00 redis-server
104648 104654 pts/1    00:00:00 io_thd_1
104648 104655 pts/1    00:00:00 io_thd_2
104648 104656 pts/1    00:00:00 io_thd_3
……

由于我們?cè)O(shè)置了io-threads等于4,所以會(huì)創(chuàng)建4個(gè)線程用于執(zhí)行I/O操作(包括主線程),上述結(jié)果符合預(yù)期。

當(dāng)然,只有I/O階段才使用了多線程,處理命令請(qǐng)求還是單線程,畢竟多線程操作內(nèi)存數(shù)據(jù)存在并發(fā)問(wèn)題。

最后,開啟了I/O多線程之后,命令的執(zhí)行流程如下圖所示:

請(qǐng)?zhí)砑訄D片描述

  • I/O多線程流程圖

03 Redis中的多進(jìn)程

Redis還有多進(jìn)程?是的。在某些場(chǎng)景下,Redis也會(huì)創(chuàng)建多個(gè)子進(jìn)程來(lái)執(zhí)行一些任務(wù)。以持久化為例,Redis支持兩種類型的持久化:

  • AOF(Append Only File):可以看作是命令的日志文件,Redis會(huì)將每一個(gè)寫命令都追加到AOF文件。
  • RDB(Redis Database):以快照的方式存儲(chǔ)Redis內(nèi)存中的數(shù)據(jù)。命令SAVE用于手動(dòng)觸發(fā)RDB持久化。想想如果Redis中的數(shù)據(jù)量非常大,持久化操作必然耗時(shí)比較長(zhǎng),而Redis是單線程處理命令請(qǐng)求,那么當(dāng)命令SAVE的執(zhí)行時(shí)間過(guò)長(zhǎng)時(shí),必然會(huì)影響其他命令的執(zhí)行。

命令SAVE有可能會(huì)阻塞其他請(qǐng)求,為此,Redis又引入了命令BGSAVE,該命令會(huì)創(chuàng)建一個(gè)子進(jìn)程來(lái)執(zhí)行持久化操作,這樣就不會(huì)影響主進(jìn)程執(zhí)行其他請(qǐng)求了。

我們可以手動(dòng)執(zhí)行命令BGSAVE驗(yàn)證。首先,使用GDB跟蹤Redis進(jìn)程,添加斷點(diǎn),讓子進(jìn)程阻塞在持久化邏輯。如下所示:

// 查詢Redis進(jìn)程ID
ps aux | grep redis
root     448144  0.1  0.0 270060 11520 pts/1    tl+  17:00   0:00 ./src/redis-server 127.0.0.1:6379

// GDB跟蹤進(jìn)程
gdb -p 448144

// 跟蹤創(chuàng)建的子進(jìn)程(默認(rèn)GDB只跟蹤主進(jìn)程,需手動(dòng)設(shè)置)
(gdb) set follow-fork-mode child
// 函數(shù)rdbSaveDb用于持久化數(shù)據(jù)快照
(gdb) b rdbSaveDb
Breakpoint 1 at 0x541a10: file rdb.c, line 1300.
(gdb) c
設(shè)置好斷點(diǎn)之后,使用Redis客戶端發(fā)送命令BGSAVE,結(jié)果如下:

// 請(qǐng)求立即返回
127.0.0.1:6379> bgsave
Background saving started

// GDB輸出以下信息
[New process 452541]
Breakpoint 1, rdbSaveDb (...) at rdb.c:1300
可以看到,GDB目前跟蹤的是子進(jìn)程,進(jìn)程ID是452541。也可以通過(guò)Linux命令 ps 查看所有進(jìn)程,結(jié)果如下:

ps aux | grep redis
root     448144  0.0  0.0 270060 11520 pts/1    Sl+  17:00   0:00 ./src/redis-server 127.0.0.1:6379
root     452541  0.0  0.0 270064 11412 pts/1    t+   17:19   0:00 redis-rdb-bgsave 127.0.0.1:6379

可以看到子進(jìn)程的名稱是redis-rdb-bgsave,也就是該進(jìn)程將所有數(shù)據(jù)的快照持久化在RDB文件。

問(wèn)題

問(wèn)題1:為什么采用子進(jìn)程而不是子線程呢?

因?yàn)镽DB是將數(shù)據(jù)快照持久化存儲(chǔ),如果采用子線程,主線程與子線程將會(huì)共享內(nèi)存數(shù)據(jù),主線程在持久化的同時(shí)還會(huì)修改內(nèi)存數(shù)據(jù),這有可能導(dǎo)致數(shù)據(jù)不一致。而主進(jìn)程與子進(jìn)程的內(nèi)存數(shù)據(jù)是完全隔離的,不存在此問(wèn)題。

問(wèn)題2:假設(shè)Redis內(nèi)存中存儲(chǔ)了10GB的數(shù)據(jù),在創(chuàng)建子進(jìn)程執(zhí)行持久化操作之后,此時(shí)子進(jìn)程也需要10GB的內(nèi)存嗎?復(fù)制10GB的內(nèi)存數(shù)據(jù),也會(huì)比較耗時(shí)吧?另外如果系統(tǒng)只有15GB的內(nèi)存,還能執(zhí)行BGSAVE命令嗎?

這里有一個(gè)概念叫寫時(shí)復(fù)制(copy on write),在使用系統(tǒng)調(diào)用fork創(chuàng)建子進(jìn)程之后,主進(jìn)程與子進(jìn)程的內(nèi)存數(shù)據(jù)暫時(shí)還是共享的,但是當(dāng)主進(jìn)程需要修改內(nèi)存數(shù)據(jù)時(shí),系統(tǒng)會(huì)自動(dòng)將該內(nèi)存塊復(fù)制一份,以此實(shí)現(xiàn)內(nèi)存數(shù)據(jù)的隔離。

請(qǐng)?zhí)砑訄D片描述

04 結(jié)論

Redis的進(jìn)程模型/線程模型還是比較復(fù)雜的,這里也只是簡(jiǎn)單介紹了部分場(chǎng)景下的多線程以及多進(jìn)程,其他場(chǎng)景下的多線程、多進(jìn)程還有待讀者自己研究。

以上就是詳解Redis單線程架構(gòu)的優(yōu)勢(shì)與不足的詳細(xì)內(nèi)容,更多關(guān)于Redis單線程架構(gòu)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Redis數(shù)據(jù)庫(kù)安全詳解

    Redis數(shù)據(jù)庫(kù)安全詳解

    這篇文章主要為大家介紹了Redis數(shù)據(jù)庫(kù)安全詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • Redis Cluster集群收縮主從節(jié)點(diǎn)詳細(xì)教程

    Redis Cluster集群收縮主從節(jié)點(diǎn)詳細(xì)教程

    集群收縮的源端就是要下線的主節(jié)點(diǎn),目標(biāo)端就是在線的主節(jié)點(diǎn),這篇文章主要介紹了Redis Cluster集群收縮主從節(jié)點(diǎn)詳細(xì)教程,需要的朋友可以參考下
    2021-11-11
  • 淺談Redis的幾個(gè)過(guò)期策略

    淺談Redis的幾個(gè)過(guò)期策略

    在使用redis時(shí),一般會(huì)設(shè)置一個(gè)過(guò)期時(shí)間,當(dāng)然也有不設(shè)置過(guò)期時(shí)間的,也就是永久不過(guò)期。當(dāng)設(shè)置了過(guò)期時(shí)間,redis是如何判斷是否過(guò)期,以及根據(jù)什么策略來(lái)進(jìn)行刪除的。
    2021-05-05
  • Windows中Redis安裝配置流程并實(shí)現(xiàn)遠(yuǎn)程訪問(wèn)功能

    Windows中Redis安裝配置流程并實(shí)現(xiàn)遠(yuǎn)程訪問(wèn)功能

    很多在windows環(huán)境中安裝Redis總是出錯(cuò),今天小編抽空給大家分享在Windows中Redis安裝配置流程并實(shí)現(xiàn)遠(yuǎn)程訪問(wèn)功能,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2021-06-06
  • redis實(shí)現(xiàn)排行榜的簡(jiǎn)單方法

    redis實(shí)現(xiàn)排行榜的簡(jiǎn)單方法

    這篇文章主要給大家介紹了關(guān)于redis實(shí)現(xiàn)排行榜的簡(jiǎn)單方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • redisson滑動(dòng)時(shí)間窗應(yīng)用場(chǎng)景解決方案

    redisson滑動(dòng)時(shí)間窗應(yīng)用場(chǎng)景解決方案

    前10分鐘內(nèi)累計(jì)3次驗(yàn)證失敗后,增加圖形驗(yàn)證碼驗(yàn)證條件,前10分鐘內(nèi)累計(jì)6次驗(yàn)證失敗后,系統(tǒng)自動(dòng)鎖定該賬號(hào)15分鐘,15分鐘后自動(dòng)解鎖,本文給大家分享redisson滑動(dòng)時(shí)間窗應(yīng)用場(chǎng)景解決方案,感興趣的朋友一起看看吧
    2024-01-01
  • Redis精確去重計(jì)數(shù)方法(咆哮位圖)

    Redis精確去重計(jì)數(shù)方法(咆哮位圖)

    這篇文章主要給大家介紹了關(guān)于Redis精確去重計(jì)數(shù)方法(咆哮位圖)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • windows下使用redis requirepass認(rèn)證不起作用的解決方法

    windows下使用redis requirepass認(rèn)證不起作用的解決方法

    今天小編就為大家分享一篇windows下使用redis requirepass認(rèn)證不起作用的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • 淺談redis在項(xiàng)目中的應(yīng)用

    淺談redis在項(xiàng)目中的應(yīng)用

    下面小編就為大家?guī)?lái)一篇淺談redis在項(xiàng)目中的應(yīng)用。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-12-12
  • 關(guān)于使用IDEA的springboot框架往Redis里寫入數(shù)據(jù)亂碼問(wèn)題

    關(guān)于使用IDEA的springboot框架往Redis里寫入數(shù)據(jù)亂碼問(wèn)題

    這篇文章主要介紹了用IDEA的springboot框架往Redis里寫入數(shù)據(jù)亂碼問(wèn)題,本文給大家分享解決方法通過(guò)圖文示例相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10

最新評(píng)論