前言
作為記憶體中資料儲存,Redis 以其速度和效能著稱,通常被用作大多數後端服務的快取解決方案。
但是,在內部,Redis 採用單執行緒架構。
為什麼單執行緒設計依然會有這麼高的效能?如果利用多執行緒併發處理請求不是更好嗎?
在本文中,讓我們深入探討為什麼 Redis 才有單執行緒架構,依然如此之快,主要從下面4個方面講解。
- 記憶體資料儲存
- 優良的資料結構
- 單執行緒架構
- 非阻塞IO
讓我們一一剖析。
記憶體資料儲存
訪問 RAM 比磁碟快幾個數量級
Redis 是一個基於記憶體儲存資料,也就是上面表的RAM。
Redis 中的每個讀寫操作都等同於從命中 RAM(隨機存取儲存器)的變數中讀取和寫入。
訪問 RAM 比直接訪問磁碟快幾個數量級,因此,Redis 比其他資料儲存快得多。
優良的資料結構
作為記憶體中的資料儲存,Redis 利用各種底層資料結構來高效地儲存資料,而無需擔心如何將它們持久化到持久儲存中。
例如,Redis 列表是使用連結串列實現的,該連結串列允許在列表的頭部和尾部附近進行恆定時間 O(1) 的插入和刪除。
另一方面,Redis 排序集是透過跳躍列表實現的,它可以實現更快的查詢和插入。
簡而言之,無需擔心持久化資料,Redis 中的資料可以更有效地儲存,以便透過不同的資料結構進行快速檢索。
單執行緒架構
單執行緒程式
Redis 的寫入和讀取速度極快,CPU 使用率對 Redis 來說從來都不是問題。
根據 Redis 官方文件,在普通 Linux 系統上執行時,Redis 每秒可以傳遞多達 100 萬個請求。
然而,瓶頸主要來自網路 I/O。Redis 中的處理時間主要浪費在等待網路 I/O 上。
雖然多執行緒架構允許應用程式透過上下文切換併發處理任務,但 Redis 的效能提升是微乎其微的,因為大多數執行緒最終會在 I/O 中被阻塞。
透過採用單執行緒架構,Redis有下面的幾個好處:
- 最小化由於執行緒建立或銷燬引起的 CPU 消耗
- 最大限度地減少由於上下文切換引起的 CPU 消耗
- 減少鎖開銷,因為多執行緒應用程式需要鎖來進行執行緒同步,這很容易出錯
- 能夠使用各種“執行緒不安全”命令,例如 lpush
非阻塞 I/O
為了處理傳入的請求,伺服器需要在套接字上呼叫系統呼叫以將資料從網路緩衝區讀取到使用者空間。
這通常是一個阻塞操作,執行緒被阻塞並且在完全接收到來自客戶端的資料之前什麼都不做。
為什麼我們不在確定套接字中的資料已準備好讀取時才呼叫系統呼叫?
這就是 I/O 多路複用發揮作用的地方。
I/O 多路複用模組同時監視多個套接字,並且只返回可讀的套接字。
準備好讀取的套接字被推送到單執行緒事件迴圈,並由相應的處理程式使用Reactor Pattern
進行處理。
簡而言之,
- 由於其阻塞性質,網路 I/O 很慢
- Redis記憶體操作速度快,Redis收到命令後可以快速執行
因此,Redis 有意識地做出以下決定:
- 使用 I/O 多路複用來緩解緩慢的網路 I/O 問題
- 使用單執行緒架構減少鎖開銷
總結
綜上所述,單執行緒架構是Redis團隊經過時間考驗的深思熟慮的選擇。儘管是單執行緒的,Redis 仍然是效能最高和最常用的記憶體資料儲存之一。
歡迎關注個人公眾號【JAVA旭陽】交流學習