爲何redis是單線程的以及爲何這麼快?

官網的說法


咱們先來認真看一下官網的說法。翻譯過來大意以下:
CPU並非您使用Redis的瓶頸,由於一般Redis要麼受內存限制,要麼受網絡限制。例如,使用在通常Linux系統上運行的流水線Redis每秒能夠發送一百萬個請求,所以,若是您的應用程序主要使用O(N)或O(log(N))命令,則幾乎不會使用過多的CPU 。
可是,爲了最大程度地利用CPU,您能夠在同一服務器上啓動多個Redis實例,並將它們視爲不一樣的服務器。在某個時候,單個實例可能還不夠,所以,若是您要使用多個CPU,則能夠開始考慮更早地分片的某種方法。
可是,在Redis 4.0中,咱們開始使Redis具備更多線程。目前,這僅限於在後臺刪除對象,以及阻止經過Redis模塊實現的命令。對於未來的版本,計劃是使Redis愈來愈線程化。
既然redis的瓶頸不是cpu,那麼在單線程能夠實現的狀況下,天然就使用單線程了。redis

本身的解讀

咱們知道redis是基於內存的。那麼咱們接下來要了解一個問題多線程cpu和內存直接操做差多少?
多線程操做就是使用多個cpu模擬多個線程,對redis進行操做。這樣會形成一個巨大的問題,就是cpu的上下文切換問題。cpu的上下文切換的效率比直接在內存中進行讀取差的不少。redis使用單個cpu綁定一個內存,針對內存的處理就是單線程的,這樣避免了上下文的切換,因此很是的快。
一次cpu的切換時間大約是1500ns。從內存中讀取1mb的連續數據,耗時大約是250us。若是1mb的數據被多個線程讀取了1000次。那麼就是有1000次時間的上下文切換。因而就是1500ns*1000=1500us。結果顯而易見。1500us和250us差的仍是不少的。
那麼redis採起單線程還避免了不少問題。若是redis使用多線程來進行,那麼就要考慮多線程帶來的數據安全問題,若是咱們在操做redis的list,hash等數據結構的時候。多線程就可能存在數據不安全的狀況,這是就要加鎖。一旦加鎖就影響了程序的執行速度。數據庫

磁盤讀取和內存讀取的區別

【IOPS(Input/Output Operations Per Second)是一個用於計算機存儲設備(如硬盤(HDD)、固態硬盤(SSD)或存儲區域網絡(SAN))性能測試的量測方式】
【吞吐量是指對網絡、設備、端口、虛電路或其餘設施,單位時間內成功地傳送數據的數量(以比特、字節、分組等測量)】
內存是一個 IOPS 很是高的系統,由於我想申請一塊內存就申請一塊內存,銷燬一塊內存我就銷燬一塊內存,內存的申請和銷燬是很容易的。並且內存是能夠動態的申請大小的。
磁盤的特性是:IPOS很低很低,但吞吐量很高。這就意味着,大量的讀寫操做都必須攢到一塊兒,再提交到磁盤的時候,性能最高。爲何呢?
若是我有一個事務組的操做(就是幾個已經分開了的事務請求,好比寫讀寫讀寫,這麼五個操做在一塊兒),在內存中,由於IOPS很是高,我能夠一個一個的完成,可是若是在磁盤中也有這種請求方式的話,
我第一個寫操做是這樣完成的:我先在硬盤中尋址,大概花費10ms,而後我讀一個數據可能花費1ms而後我再運算(忽略不計),再寫回硬盤又是10ms ,總共21ms
第二個操做去讀花了10ms, 第三個又是寫花費了21ms ,而後我再讀10ms, 寫21ms ,五個請求總共花費83ms,這仍是最理想的狀況下,這若是在內存中,大概1ms不到。
因此對於磁盤來講,它吞吐量這麼大,那最好的方案確定是我將N個請求一塊兒放在一個buff裏,而後一塊兒去提交。
方法就是用異步:將請求和處理的線程不綁定,請求的線程將請求放在一個buff裏,而後等buff快滿了,處理的線程再去處理這個buff。而後由這個buff 統一的去寫入磁盤,或者讀磁盤,這樣效率就是最高。
對於慢速設備,這種處理方式就是最佳的,慢速設備有磁盤,網絡 ,SSD 等等。緩存

爲何單核cpu綁定一塊線程內存效率最高

咱們不能任由操做系統負載均衡,由於咱們本身更瞭解本身的程序,因此咱們能夠手動地爲其分配CPU核,而不會過多地佔用CPU」,默認狀況下單線程在進行系統調用的時候會隨機使用CPU內核,爲了優化Redis,咱們可使用工具爲單線程綁定固定的CPU內核,減小沒必要要的性能損耗!
redis做爲單進程模型的程序,爲了充分利用多核CPU,經常在一臺server上會啓動多個實例。而爲了減小切換的開銷,有必要爲每一個實例指定其所運行的CPU。
Linux 上 taskset 能夠將某個進程綁定到一個特定的CPU。你比操做系統更瞭解本身的程序,爲了不調度器愚蠢的調度你的程序,或是爲了在多線程程序中避免緩存失效形成的開銷。安全

redis的多線程狀況

一個redisserver運行的時候,不是單線程的,好比進行rdb備份的時候,就是fork出了一個子進程來進行實現。
能夠經過 ps -ef | grep redis 來查看到redis的進程pid。
再使用ps -T -p pid 來查看當前pid下面的線程數。

ps命令的「-T」參數表示顯示線程(Show threads, possibly with SPID column.)「SPID」欄表示線程ID,而「CMD」欄則顯示了線程名稱。服務器

redis的內存模式爲何比數據庫磁盤塊

磁盤數據庫的形式,當咱們找數據的時候,先找到索引,經過索引而後關聯到磁盤的數據。若是使用內存的方式,能夠直接從內存中讀取數據。減小了硬盤的io。不受硬盤的讀取速度影響。網絡

redis的單線程到底有多快


redis的每秒查詢次數能夠達到10w+。可是隨着鏈接數的增長,每秒的查詢數會進行減小。通一個服務器多個鏈接數致使。數據結構

爲何內存讀取比硬盤快

兩種的方式不一樣。內存是一種半導體的存儲器,是ram。內存中的數據是電,一旦斷電內存中的數據就會消失。內存沒有機械結構。
硬盤是一種機械結構。查找數據的時候,磁盤要運動到想應的位置。磁頭讀取磁盤裏的數據。多線程

redis單線程的優點和劣勢

優點

代碼更清晰,處理邏輯更簡單。
不用去考慮各類鎖的問題,不存在加鎖、釋放鎖操做,沒有由於可能出現死鎖而致使的性能消耗。
不存在「多進程或者多線程致使的切換」而消耗CPU。負載均衡

劣勢

沒法發揮多核CPU性能,不過能夠經過在單機開多個Redis實例來完善。異步

redis的多路io複用

redis 採用網絡IO多路複用技術,來保證在多鏈接的時候系統的高吞吐量。
多路-指的是多個socket網絡鏈接,複用-指的是複用一個線程。多路複用主要有三種技術:select,poll,epoll。epoll是最新的、也是目前最好的多路複用技術。
採用多路I/O複用技術:其一,可讓單個線程高效處理多個鏈接請求(儘可能減小網絡IO的時間消耗)。其二,Redis在內存中操做數據的速度很是快(內存裏的操做不會成爲這裏的性能瓶頸)。主要以上兩點造就了Redis具備很高的吞吐量。
採用多路 I/O 複用技術可讓單個線程高效的處理多個鏈接請求。

redis爲何是單線程及爲何快的總結

一、Redis是純內存數據庫,通常都是簡單的存取操做,線程佔用的時間不少,時間的花費主要集中在IO上,因此讀取速度快。 二、Redis使用的是非阻塞IO、IO多路複用,使用了單線程來輪詢描述符,將數據庫的開、關、讀、寫都轉換成了事件,減小了線程切換時上下文的切換和競爭。 三、Redis採用了單線程的模型,保證了每一個操做的原子性,也減小了線程的上下文切換和競爭。 四、Redis避免了多線程的鎖的消耗。 五、Redis採用本身實現的事件分離器,效率比較高,內部採用非阻塞的執行方式,吞吐能力比較大。

相關文章
相關標籤/搜索