redis為什麼是單線程?在多核處理器下對主存的訪問真的比多線程更有效率?未來有可能改用多線程嗎?


提這樣的問題,因為你有一些固化的思維,比如:

1. 認為高性能伺服器=多線程

2. 覺得網路伺服器都是 http模型的。

3. 寫多了 HTTP,用多了 erlang 或者 go,以為世界上只有這一種模型。

你的問題在於沒有理清楚:

http/go/erlang 這些網路模型都是 「無狀態」 或者 「弱狀態」 的,每兩個鏈接之間沒有頻繁交互,或者頻繁訪問的中間資源。比如兩個 HTTP請求,沒有任何聯繫,要有聯繫也是放到 redis/mysql之類的地方去。

強狀態強交互的網路服務,設計本身就不一樣。


Redis 每秒可以跑兩百萬個請求,已經很強大了,網路一般先成為瓶頸。

但這並不代表我們所有的網路伺服器都像它一樣採用單線程。

就像韋大神所說,得看應用場景,採用多線程得話是否容易編寫/維護(這也取決於看開發者能力)(像協程,Actor什麼的,並不能減少複雜度,如果彼此之間交互/通信多了,一樣的很複雜,而且效率可能還更低)


單純的網路IO來說,量大到一定程度之後,多線程的確有優勢——但並不是單純的多線程,而是每個線程自己有自己的epoll這樣的模型,也就是多線程和multiplexing混合。

一般這個開頭我們都會跟一個「但是」。

但是。

還要考慮Redis操作的對象。它操作的對象是內存中的數據結構。如果在多線程中操作,那就需要為這些對象加鎖。最終來說,多線程性能有提高,但是每個線程的效率嚴重下降了。而且程序的邏輯嚴重複雜化。

要知道Redis的數據結構並不全是簡單的Key-Value,還有列表,hash,map等等複雜的結構,這些結構有可能會進行很細粒度的操作,比如在很長的列表後面添加一個元素,在hash當中添加或者刪除一個對象,等等。這些操作還可以合成MULTI/EXEC的組。這樣一個操作中可能就需要加非常多的鎖,導致的結果是同步開銷大大增加。這還帶來一個惡果就是吞吐量雖然增大,但是響應延遲可能會增加。

Redis在權衡之後的選擇是用單線程,突出自己功能的靈活性。在單線程基礎上任何原子操作都可以幾乎無代價地實現,多麼複雜的數據結構都可以輕鬆運用,甚至可以使用Lua腳本這樣的功能。對於多線程來說這需要高得多的代價。

並不是所有的KV資料庫或者內存資料庫都應該用單線程,比如ZooKeeper就是多線程的,最終還是看作者自己的意願和取捨。單線程的威力實際上非常強大,每核心效率也非常高,在今天的虛擬化環境當中可以充分利用雲化環境來提高資源利用率。多線程自然是可以比單線程有更高的性能上限,但是在今天的計算環境中,即使是單機多線程的上限也往往不能滿足需要了,需要進一步摸索的是多伺服器集群化的方案,這些方案中多線程的技術照樣是用不上的,所以單線程、多進程的集群不失為一個時髦的解決方案。


我答非所問了~ 想想再改改吧~

-----------

我試著回答這個問題吧。

近2-3年開發同事肯定感受到了,生產線上的物理機器配置越來越高了。究其原因還是硬體成本在降低。所以老闆們在成本不明顯提高的情況下,當然願意購買配置更高的機器了。高配機器運行Reids會有一些問題:

1) 對Redis 單進程/單線程模型無法榨乾機器硬體能力。對開發來說,榨乾機器硬體能力可是很爽的事情。有人說可以在單機上起多個Redis進程,這可以部分解決問題,會帶來運維上的開銷。

2)某些操作嚴重耗時會拖累整個進程;

3)長時間運行後導致內存碎片降低服務質量;

4) 由於單線程,數據備份與同步作的不夠優雅;

如果Redis是多線程模型,很多問題就迎刃而解了,雖然也帶來了一些線程同步的開銷。相比之下,多線程模型還是很有吸引力的。

-------------- 到這來,我的回答基本上結束了-------------

硬廣時間:這來有一個單進程多線程模型的最終兼容Redis協議的project, 名字叫Parallel Redis :fastio/pedis

線程模型:每個Core起一個線程,線程有自己的內存池,獨立的用戶態協議棧,獨立的事件循環。線程之間不通過共享內存方式傳遞數據,而是通過message passing方式,採用lock-free技術,竟可能減少線程間同步消耗。

有興趣同仁一起來玩兒~


感謝shawshank的邀請。

重申一遍,這篇文章不是講多線程,單線程誰的好壞,而是redis的實現機制,它這樣設計有它的架構優勢。

Redis採用的是基於內存(速度非常快),高吞吐,其他定義就不扯了。

這取決於你如何定義並發:

並發和並行通常被認為是不同的概念,有什麼區別?

1、並發性I/O流,意味著能夠讓一個計算單元來處理來自多個客戶端的流請求。

2、並行性,意味著伺服器能夠同時執行幾個事情(具有多個計算單元),這是不同的。

例如,酒吧能夠服務幾個顧客,同時他只能一次準備一個飲料。所以他可以提供沒有並行性的並發服務。

Redis雖然是單線程程序,但可以通過使用I / O多路復用同一個線程和事件循環在I / O級別上提供並發性。

像Redis這樣的高效存儲引擎的瓶頸通常是網路,在CPU之上。

因此,Redis原子性(隔離事件循環)在沒有額外成本的情況下提供並發性(不需要進程、線程同步),無需支付同步開銷。

並行性有一個代價:現在硬體設備都是多核,當然多核速度肯定比單核效率高,但進程線程之間的同步是非常昂貴的。

好比,人家redis只要一台伺服器可以搞定的事情,你幹嘛一定要讓我使用多台伺服器。它輕巧,可作為構建高效可擴展的伺服器,何必糾結一定要裝波音747的發動機(對應的設計比較複雜),redis設計有它自己架構的好處!

官網也說了,要發揮多核CPU性能,可以通過在單機開多個Redis core實例來完善,一樣實現分散式;


1.單線程確實是瓶頸,多來幾個客戶端測一下,CPU一下子就100%.

2.多線程版有人做的,只是沒有併到官方版本裡面

3.單線程實現上確實簡單

4.還有說200萬的,不知道機器什麼配置,我們實際測試沒那麼高。。。


Redis為什麼是單線程的?
因為CPU不是Redis的瓶頸。
Redis的瓶頸最有可能是機器內存或者網路帶寬。
(以上主要來自官方FAQ。。。)
既然單線程容易實現,而且CPU不會成為瓶頸,那就順理成章地採用單線程的方案了。
關於redis的性能,官方網站也有,普通筆記本輕鬆處理每秒幾十萬的請求,參見:How fast is Redis?

如果萬一CPU成為你的Redis瓶頸了,或者,你就是不想讓伺服器其他核閑置,那怎麼辦?
那也很簡單,你多起幾個Redis進程就好了。
Redis是keyvalue資料庫,又不是關係資料庫,數據之間沒有約束。
只要客戶端分清哪些key放在哪個Redis進程上就可以了。
redis-cluster可以幫你做的更好。

單線程可以處理高並發請求嗎?

當然可以了。。你看Redis都實現了。

有一點概念需要澄清,並發並不是並行。

這是一個2012年的講座,ppt的首頁長這個樣子:

鏈接見:

鏈接見:https://talks.golang.org/2012/waza.slide

多核處理器下對主存的訪問,多線程是不是更有效率?
一個簡單的回答是,對主存的訪問速度(你說的效率是指速度嗎),和是否多線程沒關係。我覺得可以先不用關注這個問題。

Redis未來會改成多線程嗎?

根據他們CTO在2013年的回答,How much work is it to make Redis multi-threaded?,把Redis改成多線程並不是正確的方向。雖然過去了三四年,這一點應該沒有變。

我的公眾號dingshukai666,教編程,歡迎關注~

http://weixin.qq.com/r/yzhMVE3EShA1rQk3923Z (二維碼自動識別)


Redis performance on a multi core CPU


我猜,redis設計之初可能考慮的就是單線程的模型…redis的基礎數據結構都不是線程安全的,改成多線程模型的代價比較高,另外大多數場景下redis基本就是當作cache來用,目前的性能已經不錯了,沒必要大刀闊斧地改。


redis單工作線程的原因是在保證性能比較好的前提下,極大的簡化程序邏輯。


又來了,一幫人為單線程喝彩,敢情兩個CPU還能跑不過一個CPU似的,搞硬體設計人還不羞愧死?不會寫或者寫不好就是了。


考慮性能問題的前提是得了解性能的瓶頸在哪。redis 目標就是高性能內存kv存儲。 非同步io,純內存操作(持久化邏輯fork),全非阻塞(非耗時)操作,並且不包含複雜計算。

靠開多線程反而會把開銷浪費在加鎖,miss cache,很多數據結構也不能實現無鎖,而且非同步服務的狀態和設計比較下更複雜。相比較多進程,單線程的模式在性能和代碼設計帶來的優勢更明顯。


單線程確實是瓶頸 尤其大量的 set操作和計數操作

一般我們都是單機上開多個redis 進程

用埠號區分

這樣充分利用多CPU


一個線程就可以打爆千兆網卡。問題是響應時間,一個慢查詢就拖垮後續所有操作


當時本來的設計是一組高性能物理機處理所有的redis相關業務,當發現是單線程之後,就在業務層進行了拆分。


高性能程序的技術分類:多進程、多線程、非同步、無狀態。

可以任意組合。


要我我也是單線程 邏輯多簡單啊!搞那麼複雜要死人的


如果一台扛不住,加進程不就好了,為啥一定要多線程?多線程帶來的複雜度完全不合算


推薦閱讀:

malloc和free是線程安全的嗎,在多線程開發時用這兩個函數應該注意什麼?
Python有GIL為什麼還需要線程同步?
像網路爬蟲、資料庫等方面多線程程序如何設置線程數?
UDP socket能否被多線程同時調用sendto來發送數據?
Linux 開發,使用多線程還是用 IO 復用 select/epoll?

TAG:Redis | 多線程 | 並發 |