單線程 Redis 如此之快的四個原因
?前言
作為內存中數據存儲,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 仍然是性能最高和最常用的內存數據存儲之一。