亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

難道Redis不是單線程?我們啟動一個Redis實例,驗證一下就知道了。Redis安裝部署方式如下所示:

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

接下來啟動Redis實例,使用命令ps查看所有線程,如下所示:

// 啟動Redis實例
./src/redis-server ./redis.conf

// 查看實例進程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個線程!不是說Redis是單線程嗎?怎么會有這么多線程呢?

這6個線程的含義你可能不太了解,但是通過這個示例至少說明Redis并不是單線程。

01 Redis中的多線程

接下來我們逐個介紹上述6個線程的作用:

redis-server:

主線程,用于接收并處理客戶端請求。

jemalloc_bg_thd

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

bio_xxx:

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

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

請?zhí)砑訄D片描述

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

請?zhí)砑訄D片描述

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

請?zhí)砑訄D片描述

  • 懶刪除流程圖

02 I/O多線程

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

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

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

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

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

這兩個配置含義如下:

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

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

開啟多線程I/O能力之后,重新啟動Redis實例,查看所有線程,結(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
……

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

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

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

請?zhí)砑訄D片描述

  • I/O多線程流程圖

03 Redis中的多進程

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

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

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

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

// 查詢Redis進程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跟蹤進程
gdb -p 448144

// 跟蹤創(chuàng)建的子進程(默認GDB只跟蹤主進程,需手動設(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è)置好斷點之后,使用Redis客戶端發(fā)送命令BGSAVE,結(jié)果如下:

// 請求立即返回
127.0.0.1:6379> bgsave
Background saving started

// GDB輸出以下信息
[New process 452541]
Breakpoint 1, rdbSaveDb (...) at rdb.c:1300
可以看到,GDB目前跟蹤的是子進程,進程ID是452541。也可以通過Linux命令 ps 查看所有進程,結(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

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

問題

問題1:為什么采用子進程而不是子線程呢?

因為RDB是將數(shù)據(jù)快照持久化存儲,如果采用子線程,主線程與子線程將會共享內(nèi)存數(shù)據(jù),主線程在持久化的同時還會修改內(nèi)存數(shù)據(jù),這有可能導致數(shù)據(jù)不一致。而主進程與子進程的內(nèi)存數(shù)據(jù)是完全隔離的,不存在此問題。

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

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

請?zhí)砑訄D片描述

04 結(jié)論

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

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

相關(guān)文章

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

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

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

    Redis Cluster集群收縮主從節(jié)點詳細教程

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

    淺談Redis的幾個過期策略

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

    Windows中Redis安裝配置流程并實現(xiàn)遠程訪問功能

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

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

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

    redisson滑動時間窗應用場景解決方案

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

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

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

    windows下使用redis requirepass認證不起作用的解決方法

    今天小編就為大家分享一篇windows下使用redis requirepass認證不起作用的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • 淺談redis在項目中的應用

    淺談redis在項目中的應用

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

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

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

最新評論