單執行緒的 Redis 為什麼這麼快

2021-10-03 16:30:23 字數 2663 閱讀 4936

redis採用的是基於記憶體的、單程序單執行緒模型的kv資料庫,由c語言編寫。官方提供的資料是可以達到1000000+的qps(每秒內查詢次數)。這個資料不比採用單程序多執行緒的同樣基於記憶體的kv資料庫memcached查。

為了更好的回答和理解redis為什麼有這好的效能,我們從以下兩個問題來解答:

redis為什麼這麼快?

redis為什麼選擇單程序單執行緒模型?

redis快的主要原因是:

以上幾點都比較好理解,下邊我們針對多路 i/o 復用模型進行簡單的**:

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

這裡「多路」指的是多個網路連線,「復用」指的是復用同乙個執行緒。採用多路 i/o 復用技術可以讓單個執行緒高效的處理多個連線請求(儘量減少網路 io 的時間消耗),且 redis 在記憶體中運算元據的速度非常快,也就是說記憶體內的操作不會成為影響redis效能的瓶頸,主要由以上幾點造就了 redis 具有很高的吞吐量。

redis為什麼是單執行緒模型呢?官網faq表示,因為redis是基於記憶體的操作,cpu不是redis的瓶頸,redis的瓶頸最有可能是機器記憶體的大小或者網路頻寬。既然單執行緒容易實現,而且cpu不會成為瓶頸,那就順理成章地採用單執行緒的方案了(畢竟採用多執行緒會有很多麻煩!)。

redis 從一開始就選擇使用單執行緒模型處理來自客戶端的絕大多數網路請求,這種考慮其實是多方面的,其中最重要的幾個原因如下:

上述三個原因中的最後乙個是最終使用單執行緒模型的決定性因素,其他的兩個原因都是使用單執行緒模型額外帶來的好處。

可維護性

可維護性對於乙個專案來說非常重要,如果**難以除錯和測試,問題也經常難以復現,這對於任何乙個專案來說都會嚴重地影響專案的可維護性。多執行緒模型雖然在某些方面表現優異,但是它卻引入了程式執行順序的不確定性,**的執行過程不再是序列的,多個執行緒同時訪問的變數如果沒有謹慎處理就會帶來詭異的問題。

併發處理

使用單執行緒模型也並不意味著程式不能併發的處理任務,redis 雖然使用單執行緒模型處理使用者的請求,但是它卻使用 i/o 多路復用機制併發處理來自客戶端的多個連線,同時等待多個連線傳送的請求。

在 i/o 多路復用模型中,最重要的函式呼叫就是 select以及類似函式,該方法的能夠同時監控多個檔案描述符(也就是客戶端的連線)的可讀可寫情況,當其中的某些檔案描述符可讀或者可寫時,select方法就會返回可讀以及可寫的檔案描述符個數。使用 i/o 多路復用技術能夠極大地減少系統的開銷,系統不再需要額外建立和維護程序和執行緒來監聽來自客戶端的大量連線,減少了伺服器的開發成本和維護成本。

效能瓶頸

redis 選擇單執行緒模型的決定性原因 —— 多執行緒技術的能夠幫助我們充分利用 cpu 的計算資源來併發的執行不同的任務,但是 cpu 資源往往都不是 redis 伺服器的效能瓶頸。哪怕我們在乙個普通的 linux 伺服器上啟動 redis 服務,它也能在 1s 的時間內處理 1,000,000 個使用者請求。

如果這種吞吐量不能滿足我們的需求,更推薦的做法是使用分片的方式將不同的請求交給不同的 redis 伺服器來處理,而不是在同乙個 redis 服務中引入大量的多執行緒操作。

簡單總結一下,redis 並不是 cpu 密集型的服務,如果不開啟 aof 備份,所有 redis 的操作都會在記憶體中完成不會涉及任何的 i/o 操作,這些資料的讀寫由於只發生在記憶體中,所以處理速度是非常快的;整個服務的瓶頸在於網路傳輸帶來的延遲和等待客戶端的資料傳輸,也就是網路 i/o,所以使用多執行緒模型處理全部的外部請求可能不是乙個好的方案。

多執行緒雖然會幫助我們更充分地利用 cpu 資源,但是作業系統上線程的切換也不是免費的,執行緒切換其實會帶來額外的開銷,其中包括:

頻繁的對執行緒的上下文進行切換可能還會導致效能地急劇下降,這可能會導致我們不僅沒有提公升請求處理的平均速度,反而進行了負優化,所以這也是為什麼 redis 對於使用多執行緒技術非常謹慎。

redis 在最新的幾個版本中加入了一些可以被其他執行緒非同步處理的刪除操作,也就是我們在上面提到的 unlink、flushall async和 flushdb async,我們為什麼會需要這些刪除操作,而它們為什麼需要通過多執行緒的方式非同步處理?

redis 在中使用 del命令來刪除乙個鍵對應的值,如果待刪除的鍵值對占用了較小的記憶體空間,那麼哪怕是同步地刪除這些鍵值對也不會消耗太多的時間。但是對於 redis 中的一些超大鍵值對,幾十 mb 或者幾百 mb 的資料並不能在幾毫秒的時間內處理完,redis 可能會需要在釋放記憶體空間上消耗較多的時間,這些操作就會阻塞待處理的任務,影響 redis 服務處理請求的 pct99 和可用性。

然而釋放記憶體空間的工作其實可以由後台執行緒非同步進行處理,這也就是 unlink命令的實現原理,它只會將鍵從元資料中刪除,真正的刪除操作會在後台非同步執行。

redis 選擇使用單執行緒模型處理客戶端的請求主要還是因為 cpu 不是 redis 伺服器的瓶頸,所以使用多執行緒模型帶來的效能提公升並不能抵消它帶來的開發成本和維護成本,系統的效能瓶頸也主要在網路 i/o 操作上;而 redis 引入多執行緒操作也是出於效能上的考慮,對於一些大鍵值對的刪除操作,通過多執行緒非阻塞地釋放記憶體空間也能減少對 redis 主線程阻塞的時間,提高執行的效率。

參考:

Redis是單執行緒,為什麼這麼快?

為什麼這麼快,簡單說法 1.redis是基於記憶體的,記憶體的讀寫速度非常快 2.redis是單執行緒的,省去了很多上下文切換執行緒的時間 3.redis使用多路復用技術,可以處理併發的連線 較詳細的解釋 1 完全基於記憶體,絕大部分請求是純粹的記憶體操作,非常快速。資料存在記憶體中,類似於hash...

Redis為什麼是單執行緒還這麼快

1 redis是基於記憶體的操作,cpu不是redis的瓶頸,redis的瓶頸最有可能是機器記憶體的大小或者網路頻寬 2 採用單執行緒,避免了不必要的上下文切換和競爭條件,也不存在多程序或者多執行緒導致的切換而消耗 cpu 3 採用網路io多路復用技術來保證在多連線的時候,系統的高吞吐量。多路 指的...

redis是單執行緒的為什麼速度這麼快?

redis是基於記憶體的也可以持久化的日誌型 key value資料庫,是單執行緒的。由於redis是基於記憶體進行讀寫的,所以他的io瓶頸並不在磁碟上 記憶體的速度非常快。redis是key value型資料庫,相比於關係型資料庫效率更高,時間複雜度為o 1 redis的使用場景為連線非常多但每個...