Redis單線程原理

Redis單線程原理

Redis是單進程單線程的,Redis利用隊列技術將併發訪問變爲串行訪問,消除了傳統數據庫串行控制的開銷。

單線程指的是網絡請求模塊使用了一個線程(所以不需考慮併發安全性),即一個線程處理所有網絡請求,其他模塊仍用了多個線程。

Redis客戶端對服務端的每次調用都經歷了發送命令,執行命令,返回結果三個過程。其中執行命令階段,由於Redis是單線程來處理命令的,所有到達服務端的命令都不會立刻執行,所有的命令都會進入一個隊列中,然後逐個執行,並且多個客戶端發送的命令的執行順序是不確定的,但是可以確定的是不會有兩條命令被同時執行,不會產生併發問題,這就是Redis的單線程基本模型。

Redis服務器通過socket(套接字)與客戶端或其他Redis服務器進行連接,而文件事件就是服務器對socket操作的抽象。服務器與客戶端或其他服務器的通信會產生相應的文件事件,而服務器通過監聽並處理這些事件來完成一系列網絡通信操作。

Redis基於Reactor模式開發了自己的網絡事件處理器——文件事件處理器,文件事件處理器使用I/O多路複用程序來同時監聽多個socket(I/O多路複用技術下面有介紹),並根據socket目前執行的任務來爲socket關聯不同的事件處理器。當被監聽的socket準備好執行連接應答、讀取、寫入、關閉等操作時,與操作相對應的文件事件就會產生,這時文件事件處理器就會調用socket之前已關聯好的事件處理器來處理這些事件。

文件事件處理器的構成:
在這裏插入圖片描述
注意:其中I/O多路複用程序通過隊列向文件事件分派器傳送socket

Redis是單線程的原因

1.官網
由於Redis是基於內存的操作,因此CPU並不是Redis的瓶頸。 Redis的瓶頸很可能是機器內存或網絡帶寬的大小。 既然單線程易於實現並且CPU不會成爲瓶頸,那採用單線程解決方案是合乎邏輯的了。

2.性能指標
關於redis的性能,官方網站也有介紹,普通筆記本可以輕鬆地每秒處理數十萬個請求。

3.詳細原因
1)不需要各種鎖的性能消耗
Redis的數據結構並非全都是簡單的鍵值(Key-Value),而是有複雜的結構,如列表(list)和哈希(hash)。 這些結構可以執行細粒度的操作,例如在長列表後面添加元素並將其添加到哈希(hash)或刪除對象。

這些操作可能需要非常大量的鎖,從而導致同步開銷顯着增加。 簡而言之,在單線程的情況下,不需要考慮各種鎖,沒有鎖釋放操作,也沒有由於可能的死鎖而導致的性能消耗。

2)單線程多進程集羣方案
單線程的功能實際上非常強大,每個內核的效率也很高。 與單線程相比,多線程自然可以具有更高的性能限制。 但是,在當今的計算環境中,甚至單機多線程限制通常也無法滿足。需要進一步探索的是多服務器羣集方案,並且這些方案中的多線程技術仍然是不可用的。

所以單線程、多進程的集羣不失爲一個時髦的解決方案。

3)CPU消耗
單線程用於避免不必要的上下文切換和競爭條件,並且不存在消耗CPU的多進程或多線程切換。 但是,如果CPU成爲Redis的瓶頸,或者不想讓服務器的其他CPU內核閒置怎麼辦? 您可以考慮幾個Redis進程。 Redis是一個鍵值(key-value)數據庫,而不是關係數據庫,並且數據之間沒有約束。 只要客戶端能夠區分哪個鍵位於哪個Redis進程上,就可以完成了。

Redis單線程的優劣勢

單進程單線程優勢
代碼更清晰,處理邏輯也更簡單。 無需考慮各種鎖。 沒有鎖定釋放操作。 由於可能存在死鎖,因此不會降低性能。 沒有由多進程或多線程消耗的CPU引起的切換

單進程單線程弊端
無法利用多核CPU的性能,但可以通過在單臺計算機上打開多個Redis實例來提高性能;

IO多路複用技術
當有多個連接時,Redis使用網絡IO多路複用技術來確保系統的高吞吐量。 多路複用是指多個socket連接,而多路複用是指對線程進行多路複用。

多路複用主要有三種技術:select,poll,epoll。epoll是目前最新的也是最好的多路複用技術了。

“多路複用”是指多個網絡連接,“多路複用”是指多路複用同一線程。 使用多個I / O多路複用技術可以使單個線程有效地處理多個連接請求(最大程度地減少網絡IO的時間消耗),並且Redis可以非常快速地操作內存中的數據(這裏的內存操作不會成爲性能瓶頸),以上兩個 要點使Redis具有很高的吞吐量。
在這裏插入圖片描述
關於I/O多路複用(又被稱爲“事件驅動”),首先要理解的是,操作系統爲你提供了一個功能,當你的某個socket可讀或者可寫的時候,它可以給你一個通知。這樣當配合非阻塞的socket使用時,只有當系統通知我哪個描述符可讀了,我纔去執行read操作,可以保證每次read都能讀到有效數據而不做純返回-1和EAGAIN的無用功,寫操作類似。

操作系統的這個功能是通過select/poll/epoll/kqueue之類的系統調用函數來實現,這些函數都可以同時監視多個描述符的讀寫就緒狀況,這樣,多個描述符的I/O操作都能在一個線程內併發交替地順序完成,這就叫I/O多路複用,這裏的“多路”指的是多個網絡連接,“複用”指的是複用同一個Redis處理線程。

採用多路 I/O 複用技術可以讓單個線程高效的處理多個連接請求(儘量減少網絡 I/O 的時間消耗),且 Redis 在內存中操作數據的速度非常快,也就是說內存內的操作不會成爲影響Redis性能的瓶頸,所有 Redis 具有很高的吞吐量。

Redis的單線程爲什麼這麼快?

1.完全基於內存,絕大部分請求是純粹的內存操作,非常快速。數據存在內存中,類似於HashMap,HashMap的優勢就是查找和操作的時間複雜度都是O(1);

2.數據結構簡單,對數據操作也簡單,Redis中的數據結構是專門進行設計的;

3.採用單線程,避免了不必要的上下文切換和競爭條件,也不存在多進程或者多線程導致的切換而消耗 CPU,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有因爲可能出現死鎖而導致的性能消耗;

4.使用多路I/O複用模型,非阻塞I/O;

5.Redis直接自己構建了VM 機制 ,因爲一般的系統調用系統函數的話,會浪費一定的時間去移動和請求;

爲什麼不採用多進程或多線程處理?

1.多線程處理可能涉及到鎖

2.多線程處理會涉及到線程切換而消耗CPU

單線程處理的缺點?

1.耗時的命令會導致併發的下降,不只是讀併發,寫併發也會下降

2.無法發揮多核CPU性能,不過可以通過在單機開多個Redis實例來完善

4、Redis不存在線程安全問題?

Redis採用了線程封閉的方式,把任務封閉在一個線程,自然避免了線程安全問題,不過對於需要依賴多個redis操作(即:多個Redis操作命令)的複合操作來說,依然需要鎖,而且有可能是分佈式鎖。

參考文章:
Redis爲什麼是單線程,高併發快由哪些因素決定?
乾貨|Redis單線程的正確理解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章