成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

為什么單線程的 Redis 能那么快?

數(shù)據(jù)庫 Redis
今天,我們來探討一個很多人都很關(guān)心的問題:“為什么單線程的 Redis 能那么快?”

今天,我們來探討一個很多人都很關(guān)心的問題:“為什么單線程的 Redis 能那么快?”

首先,我要和你厘清一個事實,我們通常說,Redis 是單線程,主要是指 Redis 的網(wǎng)絡 IO 和鍵值對讀寫是由一個線程來完成的,這也是 Redis 對外提供鍵值存儲服務的主要流程。但 Redis 的其他功能,比如持久化、異步刪除、集群數(shù)據(jù)同步等,其實是由額外的線程執(zhí)行的。

所以,嚴格來說,Redis 并不是單線程,但是我們一般把 Redis 稱為單線程高性能,這樣顯得“酷”些。接下來,我也會把 Redis 稱為單線程模式。而且,這也會促使你緊接著提問:“為什么用單線程?為什么單線程能這么快?”

要弄明白這個問題,我們就要深入地學習下 Redis 的單線程設計機制以及多路復用機制。之后你在調(diào)優(yōu) Redis 性能時,也能更有針對性地避免會導致 Redis 單線程阻塞的操作,例如執(zhí)行復雜度高的命令。

好了,話不多說,接下來,我們就先來學習下 Redis 采用單線程的原因。

Redis 為什么用單線程?

要更好地理解 Redis 為什么用單線程,我們就要先了解多線程的開銷。

多線程的開銷

多線程可以增加系統(tǒng)吞吐率,多線程機制可以將一個程序分為多個獨立運行的線程,每個線程可以同時執(zhí)行不同任務,避免了任務之間的互相等待,提高了系統(tǒng)的響應速度。通過合理管理和調(diào)度這些線程,可以更好地利用計算機的處理能力,在較短時間內(nèi)處理更多的請求。

多線程還有助于提高系統(tǒng)的擴展性。通過將任務拆分為多個子任務,每個線程負責執(zhí)行其中一部分,可以更容易地將工作負載分配到多個處理單元上。這樣,在需要擴展系統(tǒng)處理能力時,只需增加更多的線程,而不需要修改整體架構(gòu)或重新設計系統(tǒng)。這種可伸縮性使得系統(tǒng)在應對不斷增長的需求時更具競爭力。

下面的左圖是我們采用多線程時所期待的結(jié)果。

但是,請你注意,通常情況下,在我們采用多線程后,如果沒有良好的系統(tǒng)設計,實際得到的結(jié)果,其實是右圖所展示的那樣。我們剛開始增加線程數(shù)時,系統(tǒng)吞吐率會增加,但是,再進一步增加線程時,系統(tǒng)吞吐率就增長遲緩了,有時甚至還會出現(xiàn)下降的情況。

線程數(shù)與系統(tǒng)吞吐率

為什么會出現(xiàn)這種情況呢?一個關(guān)鍵的瓶頸在于,系統(tǒng)中通常會存在被多線程同時訪問的共享資源,比如一個共享的數(shù)據(jù)結(jié)構(gòu)。當有多個線程要修改這個共享資源時,為了保證共享資源的正確性,就需要有額外的機制進行保證,而這個額外的機制,就會帶來額外的開銷。

拿 Redis 來說,在上節(jié)課中,我提到過,Redis 有 List 的數(shù)據(jù)類型,并提供出隊(LPOP)和入隊(LPUSH)操作。假設 Redis 采用多線程設計,如下圖所示,現(xiàn)在有兩個線程 A 和 B,線程 A 對一個 List 做 LPUSH 操作,并對隊列長度加 1。同時,線程 B 對該 List 執(zhí)行 LPOP 操作,并對隊列長度減 1。為了保證隊列長度的正確性,Redis 需要讓線程 A 和 B 的 LPUSH 和 LPOP 串行執(zhí)行,這樣一來,Redis 可以無誤地記錄它們對 List 長度的修改。否則,我們可能就會得到錯誤的長度結(jié)果。這就是多線程編程模式面臨的共享資源的并發(fā)訪問控制問題。

多線程并發(fā)訪問Redis

并發(fā)訪問控制一直是多線程開發(fā)中的一個難點問題,如果沒有精細的設計,比如說,只是簡單地采用一個粗粒度互斥鎖,就會出現(xiàn)不理想的結(jié)果:即使增加了線程,大部分線程也在等待獲取訪問共享資源的互斥鎖,并行變串行,系統(tǒng)吞吐率并沒有隨著線程的增加而增加。

而且,采用多線程開發(fā)一般會引入同步原語來保護共享資源的并發(fā)訪問,這也會降低系統(tǒng)代碼的易調(diào)試性和可維護性。為了避免這些問題,Redis 直接采用了單線程模式。

講到這里,你應該已經(jīng)明白了“Redis 為什么用單線程”,那么,接下來,我們就來看看,為什么單線程 Redis 能獲得高性能。

單線程 Redis 為什么那么快?

通常來說,單線程的處理能力要比多線程差很多,但是 Redis 卻能使用單線程模型達到每秒數(shù)十萬級別的處理能力,這是為什么呢?其實,這是 Redis 多方面設計選擇的一個綜合結(jié)果。

一方面,Redis 的大部分操作在內(nèi)存上完成,再加上它采用了高效的數(shù)據(jù)結(jié)構(gòu),例如哈希表和跳表,這是它實現(xiàn)高性能的一個重要原因。另一方面,就是 Redis 采用了多路復用機制,使其在網(wǎng)絡 IO 操作中能并發(fā)處理大量的客戶端請求,實現(xiàn)高吞吐率。接下來,我們就重點學習下多路復用機制。

首先,我們要弄明白網(wǎng)絡操作的基本 IO 模型和潛在的阻塞點。畢竟,Redis 采用單線程進行 IO,如果線程被阻塞了,就無法進行多路復用了。

1.基本 IO 模型與阻塞點

(1) 阻塞模式

其實下面所說的Socket 網(wǎng)絡模型在早期的時候是沒有非阻塞設置的,因此會造成一直等待,也就阻塞了。

這也就是我們所說的BIO網(wǎng)絡模型,關(guān)于BIO這個最基本的IO模型,具體是怎么阻塞的想必大家都比較清楚,這里不再過多解釋,本號其他文章有關(guān)于io模型的介紹。

(2) 非阻塞模式

Socket 網(wǎng)絡模型的非阻塞模式設置,主要體現(xiàn)在三個關(guān)鍵的函數(shù)調(diào)用上,如果想要使用 socket 非阻塞模式,就必須要了解這三個函數(shù)的調(diào)用返回類型和設置模式。接下來,我們就重點學習下它們。

在 socket 模型中,不同操作調(diào)用后會返回不同的套接字類型。socket() 方法會返回主動套接字,然后調(diào)用 listen() 方法,將主動套接字轉(zhuǎn)化為監(jiān)聽套接字,此時,可以監(jiān)聽來自客戶端的連接請求。最后,調(diào)用 accept() 方法接收到達的客戶端連接,并返回已連接套接字。

Redis套接字類型與非阻塞設置

針對監(jiān)聽套接字,我們可以設置非阻塞模式:當 Redis 調(diào)用 accept() 但一直未有連接請求到達時,Redis 線程可以返回處理其他操作,而不用一直等待。但是,你要注意的是,調(diào)用 accept() 時,已經(jīng)存在監(jiān)聽套接字了。

雖然 Redis 線程可以不用繼續(xù)等待,但是總得有機制繼續(xù)在監(jiān)聽套接字上等待后續(xù)連接請求,并在有請求時通知 Redis。

類似的,我們也可以針對已連接套接字設置非阻塞模式:Redis 調(diào)用 recv() 后,如果已連接套接字上一直沒有數(shù)據(jù)到達,Redis 線程同樣可以返回處理其他操作。我們也需要有機制繼續(xù)監(jiān)聽該已連接套接字,并在有數(shù)據(jù)達到時通知 Redis。

這樣才能保證 Redis 線程,既不會像基本 IO 模型中一直在阻塞點等待,也不會導致 Redis 無法處理實際到達的連接請求或數(shù)據(jù)。

到此,Linux 中的 IO 多路復用機制就要登場了。

2.基于多路復用的高性能 I/O 模型

Linux 中的 IO 多路復用機制是指一個線程處理多個 IO 流,就是我們經(jīng)常聽到的 select/epoll 機制。簡單來說,在 Redis 只運行單線程的情況下,該機制允許內(nèi)核中,同時存在多個監(jiān)聽套接字和已連接套接字。內(nèi)核會一直監(jiān)聽這些套接字上的連接請求或數(shù)據(jù)請求。一旦有請求到達,就會交給 Redis 線程處理,這就實現(xiàn)了一個 Redis 線程處理多個 IO 流的效果。

下圖就是基于多路復用的 Redis IO 模型。圖中的多個 FD 就是剛才所說的多個套接字。Redis 網(wǎng)絡框架調(diào)用 epoll 機制,讓內(nèi)核監(jiān)聽這些套接字。此時,Redis 線程不會阻塞在某一個特定的監(jiān)聽或已連接套接字上,也就是說,不會阻塞在某一個特定的客戶端請求處理上。正因為此,Redis 可以同時和多個客戶端連接并處理請求,從而提升并發(fā)性。

基于多路復用的Redis高性能IO模型

為了在請求到達時能通知到 Redis 線程,select/epoll 提供了基于事件的回調(diào)機制,即針對不同事件的發(fā)生,調(diào)用相應的處理函數(shù)。

那么,回調(diào)機制是怎么工作的呢?其實,select/epoll 一旦監(jiān)測到 FD 上有請求到達時,就會觸發(fā)相應的事件。

這些事件會被存放在一個事件隊列中,Redis 單線程會不斷地處理這個事件隊列。這種方法使得 Redis 不必持續(xù)輪詢是否有請求發(fā)生,有效地減少了對 CPU 資源的浪費。同時,Redis 在處理事件隊列中的事件時,會觸發(fā)相應的處理函數(shù),從而實現(xiàn)了基于事件的回調(diào)機制。由于 Redis 不斷地處理事件隊列,因此能夠迅速響應客戶端請求,提高了 Redis 的響應性能。

為了更好地理解,我以連接請求和讀數(shù)據(jù)請求為例,進一步解釋這個過程。

這兩個請求對應著 Accept 事件和 Read 事件,Redis 分別注冊了 accept 和 get 回調(diào)函數(shù)來處理這兩類事件。當 Linux 內(nèi)核檢測到連接請求或讀取數(shù)據(jù)請求時,就會觸發(fā) Accept 事件和 Read 事件,此時內(nèi)核會回調(diào) Redis 的相應 accept 和 get 函數(shù)來處理這些事件。

這就好比病人前往醫(yī)院就醫(yī)。在醫(yī)生實際進行診斷之前,每位病人(類似于請求)都需要經(jīng)歷分診、測量體溫、填寫登記表等過程。如果所有這些工作都由醫(yī)生親自完成,那醫(yī)生的效率將會很低。因此,醫(yī)院通常設置了分診臺,分診臺會專門處理這些在診斷之前的任務(類似于 Linux 內(nèi)核監(jiān)聽請求),然后再將病人交給醫(yī)生進行實際診斷。這種方式,即使只有一個醫(yī)生(相當于 Redis 單線程),效率也能夠顯著提高。

需要注意的是,多路復用機制是適用于各種操作系統(tǒng)的,即使你的應用在不同操作系統(tǒng)上運行,多路復用機制依然有效。這是因為多路復用機制的具體實現(xiàn)方式有多種,包括基于 Linux 系統(tǒng)的 select 和 epoll 實現(xiàn)、基于 FreeBSD 的 kqueue 實現(xiàn),以及基于 Solaris 的 evport 實現(xiàn),因此你可以根據(jù) Redis 運行的實際操作系統(tǒng),選擇合適的多路復用實現(xiàn)方式。

小結(jié)

在前面的學習中,我們重點探討了 Redis 線程背后的三個關(guān)鍵問題,即“Redis是否真的只使用單線程?”、“為什么堅持使用單線程?”以及“為何Redis的單線程如此高效?”

現(xiàn)在,我們已經(jīng)理解,Redis的單線程指的是它采用單一線程來處理網(wǎng)絡I/O和數(shù)據(jù)讀寫操作,而采用單線程的核心原因之一是為了避免多線程開發(fā)中的復雜并發(fā)控制問題。Redis的單線程性能卓越,與其采用的多路復用I/O模型密切相關(guān),因為這有助于規(guī)避accept()和send()/recv()等潛在的網(wǎng)絡I/O操作阻塞問題。

通過深入理解這些問題,您已經(jīng)走在了許多人的前沿。如果您的朋友或同事還對這些問題感到困惑,不妨與他們分享這些見解,幫助他們消除疑慮。

此外,我來透露一下,您可能已經(jīng)注意到,于2020年5月,Redis 6.0發(fā)布了其穩(wěn)定版本,其中引入了多線程模型。那么,這個多線程模型與我們在本課程中討論的I/O模型是否有關(guān)系?它是否會引入復雜的并發(fā)控制問題?又是否將如何提升Redis 6.0的性能表現(xiàn)?關(guān)于這些問題,我將在接下來的課程中為您詳細介紹。

責任編輯:趙寧寧 來源: 碼農(nóng)本農(nóng)
相關(guān)推薦

2023-03-21 08:02:36

Redis6.0IO多線程

2019-06-17 14:20:51

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

2020-10-30 16:20:38

Redis單線程高并發(fā)

2020-06-11 09:35:39

Redis單線程Java

2019-02-18 08:10:53

2021-03-03 08:01:58

Redis多線程程序

2025-01-17 08:23:33

2019-05-07 09:44:45

Redis高并發(fā)模型

2023-08-17 14:12:17

2020-11-09 09:33:37

多線程

2019-05-06 11:12:18

Redis高并發(fā)單線程

2019-04-02 11:20:48

Redis高并發(fā)單線程

2020-11-17 10:20:53

Redis多線程單線程

2025-06-17 00:22:00

2023-02-07 08:18:34

單線程Redis內(nèi)存

2020-07-29 08:06:30

Kafka MQ消息

2023-06-08 18:25:40

Doris場景查詢

2022-01-04 11:11:32

Redis單線程Reactor

2020-10-16 16:00:50

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

2025-04-24 08:15:00

Redis單線程線程
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 亚洲人成人一区二区在线观看 | 极品久久 | 影音先锋欧美资源 | 国产大毛片 | 一区二区三区免费在线观看 | 亚洲高清在线 | 中文字幕亚洲免费 | 国产精品永久久久久 | 国产精品久久av | 伊人中文字幕 | 亚洲欧美中文日韩在线 | 欧洲一区二区三区 | 亚欧洲精品在线视频免费观看 | 日韩欧美一区二区三区免费观看 | 国产精品18hdxxxⅹ在线 | 色综合久久久 | 久久人人网| 成人免费福利视频 | 最新av片| 国产精品入口麻豆www | 婷婷色在线播放 | 国产精品一区二区视频 | 在线天堂免费中文字幕视频 | 精品小视频| 欧美久久天堂 | 国产一级视频免费播放 | 久久久久久国模大尺度人体 | 日韩av手机在线观看 | 亚洲h色| 国产视频导航 | 男女一区二区三区 | 男人的天堂一级片 | 成人激情视频免费观看 | 久久久激情视频 | 秋霞精品 | 精品国产不卡一区二区三区 | 国产精品一区二区三区久久久 | 91亚洲精品久久久电影 | 亚州精品天堂中文字幕 | 色视频欧美 | 国产精品2|