日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

02 | 高性能 IO 模型:为什么单线程 Redis 能那么快?

發布時間:2024/10/6 数据库 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 02 | 高性能 IO 模型:为什么单线程 Redis 能那么快? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

我們通常說,Redis 是單線程,主要是指Redis 的網絡 IO和鍵值對讀寫是由一個線程來完成的,這也是 Redis 對外提供鍵值存儲服務的主要流程。但 Redis 的其他功能,比如持久化、異步刪除、集群數據同步等,其實是由額外的線程執行的。

單線程Redis為什么那么快

一方面,Redis 的大部分操作在內存上完成,再加上它采用了高效的數據結構,例如哈希表和跳表,這是它實現高性能的一個重要原因。另一方面,就是 Redis 采用了多路復用機制,使其在網絡 IO 操作中能并發處理大量的客戶端請求,實現高吞吐率。
接下來,我們就重點學習下多路復用機制。首先,我們要弄明白網絡操作的基本 IO 模型和潛在的阻塞點。畢竟,Redis 采用單線程進行 IO,如果線程被阻塞了,就無法進行多路復用了。

基本IO模型與阻塞點

以 Get 請求為例,SimpleKV 為了處理一個 Get 請求,需要監聽客戶端請求(bind/listen),和客戶端建立連接(accept),從 socket 中讀取請求(recv),解析客戶端發送請求(parse),根據請求類型讀取鍵值數據(get),最后給客戶端返回結果,即向 socket 中寫回數據(send)。

在這里的網絡 IO 操作中,有潛在的阻塞點,分別是 accept() 和 recv()。當 Redis監聽到一個客戶端有連接請求,但一直未能成功建立起連接時,會阻塞在 accept() 函數這里,導致其他客戶端無法和 Redis 建立連接。類似的,當 Redis 通過 recv() 從一個客戶端讀取數據時,如果數據一直沒有到達,Redis 也會一直阻塞在 recv()。
這就導致 Redis 整個線程阻塞,無法處理其他客戶端請求,效率很低。不過,幸運的是,socket 網絡模型本身支持非阻塞模式。

非阻塞模式

Socket 網絡模型的非阻塞模式設置,主要體現在三個關鍵的函數調用上,在 socket 模型中,不同操作調用后會返回不同的套接字類型。socket() 方法會返回主動套接字,然后調用 listen() 方法,將主動套接字轉化為監聽套接字,此時,可以監聽來自客戶端的連接請求。最后,調用 accept() 方法接收到達的客戶端連接,并返回已連接套接字。

我們也可以針對已連接套接字設置非阻塞模式:Redis 調用 recv() 后,如果已連接套接字上一直沒有數據到達,Redis 線程同樣可以返回處理其他操作。我們也需要有機制繼續監聽該已連接套接字,并在有數據達到時通知 Redis。

基于多路復用的高性能I/O模型

Linux 中的 IO 多路復用機制是指一個線程處理多個 IO 流,就是我們經常聽到的select/epoll 機制。簡單來說,在 Redis 只運行單線程的情況下,該機制允許內核中,同時存在多個監聽套接字和已連接套接字。內核會一直監聽這些套接字上的連接請求或數據請求。一旦有請求到達,就會交給 Redis 線程處理,這就實現了一個 Redis 線程處理多個IO 流的效果。
下圖就是基于多路復用的 Redis IO 模型。圖中的多個 FD 就是剛才所說的多個套接字。Redis 網絡框架調用 epoll 機制,讓內核監聽這些套接字。此時,Redis 線程不會阻塞在某一個特定的監聽或已連接套接字上,也就是說,不會阻塞在某一個特定的客戶端請求處理上。正因為此,Redis 可以同時和多個客戶端連接并處理請求,從而提升并發性。

為了在請求到達時能通知到 Redis 線程,select/epoll 提供了
基于事件的回調機制,即針對不同事件的發生,調用相應的處理函數。
那么,回調機制是怎么工作的呢?其實,select/epoll 一旦監測到 FD 上有請求到達時,就會觸發相應的事件。這些事件會被放進一個事件隊列,Redis 單線程對該事件隊列不斷進行處理。這樣一來,Redis 無需一直輪詢是否有請求實際發生,這就可以避免造成 CPU 資源浪費。
同時,Redis 在對事件隊列中的事件進行處理時,會調用相應的處理函數,這就實現了基于事件的回調。因為 Redis 一直在對事件隊列進行處理,所以能及時響應客戶端請求,提升Redis 的響應性能。
為了方便你理解,我再以連接請求和讀數據請求為例,具體解釋一下。
這兩個請求分別對應 Accept 事件和 Read 事件,Redis 分別對這兩個事件注冊 accept 和get 回調函數。當 Linux 內核監聽到有連接請求或讀數據請求時,就會觸發 Accept 事件
和 Read 事件,此時,內核就會回調 Redis 相應的 accept 和 get 函數進行處理。
這就像病人去醫院瞧病。在醫生實際診斷前,每個病人(等同于請求)都需要先分診、測體溫、登記等。如果這些工作都由醫生來完成,醫生的工作效率就會很低。所以,醫院都
設置了分診臺,分診臺會一直處理這些診斷前的工作(類似于 Linux 內核監聽請求),然后再轉交給醫生做實際診斷。這樣即使一個醫生(相當于 Redis 單線程),效率也能提升。
不過,需要注意的是,即使你的應用場景中部署了不同的操作系統,多路復用機制也是適用的。因為這個機制的實現有很多種,既有基于 Linux 系統下的 select 和 epoll 實現,也有基于 FreeBSD 的 kqueue 實現,以及基于 Solaris 的 evport 實現,這樣,你可以根據Redis 實際運行的操作系統,選擇相應的多路復用實現。

總結

以上是生活随笔為你收集整理的02 | 高性能 IO 模型:为什么单线程 Redis 能那么快?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。