Redis到底是單線程還是多線程?

一、什麼是Redis

redis是一個高性能的key-value數據庫,它是完全開源免費的,而且redis是一個NOSQL類型數據庫,是爲了解決高併發、高擴展,大數據存儲等一系列的問題而產生的數據庫解決方案,是一個非關係型的數據庫。但是,它也是不能替代關係型數據庫,只能作爲特定環境下的擴充。

redis是一個以key-value存儲的數據庫結構型服務器,它支持的數據結構類型包括:字符串(String)、鏈表(lists)、哈希表(hash)、集合(set)、有序集合(Zset)等。爲了保證讀取的效率,redis把數據對象都存儲在內存當中,它可以支持週期性的把更新的數據寫入磁盤文件中。而且它還提供了交集和並集,以及一些不同方式排序的操作。

二、Redis到底有多快

Redis採用的是基於內存的採用的是單進程單線程模型的 KV 數據庫,由C語言編寫,官方提供的數據是可以達到100000+的QPS(每秒內查詢次數)。這個數據不比採用單進程多線程的同樣基於內存的 KV 數據庫 Memcached 差!有興趣的可以參考官方的基準程序測試《How fast is Redis?》(https://redis.io/topics/benchmarks
在這裏插入圖片描述
橫軸是連接數,縱軸是QPS。 此時,這張圖反映了一個數量級,希望大家在面試的時候可以正確的描述出來,不要問你的時候,你回答的數量級相差甚遠!

三、Redis爲什麼這麼快

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

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

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

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

  5. 使用底層模型不同,它們之間底層實現方式以及與客戶端之間通信的應用協議不一樣,Redis直接自己構建了VM 機制 ,因爲一般的系統調用系統函數的話,會浪費一定的時間去移動和請求;

以上幾點都比較好理解,下邊我們針對多路 I/O 複用模型進行簡單的探討:

多路 I/O 複用模型

多路I/O複用模型是利用 select、poll、epoll 可以同時監察多個流的 I/O 事件的能力,在空閒的時候,會把當前線程阻塞掉,當有一個或多個流有 I/O 事件時,就從阻塞態中喚醒,於是程序就會輪詢一遍所有的流(epoll 是隻輪詢那些真正發出了事件的流),並且只依次順序的處理就緒的流,這種做法就避免了大量的無用操作。

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

四:那麼爲什麼Redis是單線程的

原因如下:
1. CPU不是瓶頸:Redis的所有操作都是基於內存的,而CPU不是Redis的瓶頸。在大多數情況下,Redis的瓶頸很可能是機器內存或網絡帶寬的大小。如果我們想要更高的性能,可以使用單線程Redis,我們可以使用集羣(多個進程)解決方案。
2. 併發性:並行性不是支持多個客戶端的唯一策略。Redis使用epoll和事件循環來實現併發策略並節省大量時間而無需上下文切換。
3. 易於實現:編寫多線程程序可能會更加困難。我們需要爲線程添加鎖和同步機制。
4. 易於部署:單線程應用程序可以部署在至少具有單個CPU內核的任何計算機上。

併發與並行?

併發性和並行性之間的區別
1. 併發就是一次處理很多事情。並行是關於一次做很多事情。
2. 併發是關於結構;並行是關於執行的。
3. 併發提供了一種構造解決方案的方法,以解決可能(但不一定)可並行化的問題。

我們可以使用餐廳服務員的類比:
什麼是併發
服務員可以爲多個客戶提供服務,而一次只能爲一個客戶準備菜。
由於廚房提供的菜餚之間會有一定的間隔,因此當顧客人數少於5人時,一位侍者通常可以處理。
什麼是並行
假設廚房一次可以爲20位顧客提供餐具。如果一位服務員的顧客數量太大,我們需要更多的服務員。在這種情況下,多個服務員同時工作。我們稱其爲並行性。

五:多線程的Redis?

在 2019 年 12 月 20 號這天,衆所期待的 Redis 新版 6.0 rc1 發佈了(Redis 6 RC1 is out today),肯定很多關注的同學都進行了試用,雖然因爲引入了 c11 的 _Atomic 導致相當多的環境都無法直接編譯成功,但是對於想一探究竟的粉絲們來說,這是完全阻擋不了的熱情,

新版除了增加 ACLS 權限控制模塊、支持更爲廣泛的新協議 RESP3、客戶端緩存、無磁盤同步、Cluster Proxy 等十來個相當實用的新特性外,還對 長久以來 社區筒子們 呼聲比較高的 多線程 進行了支持,當然也帶來 性能提升了一倍 的好處
這次我們的任務有兩個: - 剖析 Redis6 多線程的實現方式 - 與 Memcached 的多線程模型(個人認爲這是一個極其經典的多線程網絡編程案例)進行對比

加入多線程 IO 之後,整體的讀流程如下:

  1. 主線程負責接收建連請求,讀事件到來(收到請求)則放到一個全局等待讀處理隊列
  2. 主線程處理完讀事件之後,通過 RR(Round Robin) 將這些連接分配給這些 IO 線程,然後主線程忙等待(spinlock 的效果)狀態
  3. IO 線程將請求數據讀取並解析完成(這裏只是讀數據和解析並不執行)
  4. 主線程執行所有命令並清空整個請求等待讀處理隊列(執行部分串行)

上面的這個過程是完全無鎖的,因爲在 IO 線程處理的時主線程會等待全部的 IO 線程完成,所以不會出現 data race 的場景。
參考鏈接:https://www.sohu.com/a/331991216_268033

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