【redis】線程IO模型

Redis線程IO模型

總結:在redis5.0及之前,redis線程io模型是單線程。那么Redis單線程如何處理那么多的并發客戶端連接的?原因兩點:1)非阻塞io 2)多路復用(事件輪詢)

以下,我就針對上面的總結來展開說說redis線程io模型。

1、客戶端與redis服務器的通信過程

當客戶端執行redis.set(“key”,“value”)命令時,

  • 客戶端通過操作系統創建一個套接字
    • 這個套接字會連接到運行 Redis 服務器的機器地址和端口(通常是 6379)。
    • 一旦連接建立成功,你的程序就可以通過這個套接字向 Redis 服務器發送數據
  • 客戶端將命令通過 write() 進入 內核寫緩沖區
  • 內核寫緩存區的數據會從網卡 → redis服務端的內核讀緩沖區。
  • redis服務端通過多路復用(epoll)得知內核讀緩存區有命令需要執行。
  • 執行之后的響應數據進入Redis服務器的 內核寫緩沖區
  • 接著內核寫緩存區的數據又會從網卡 → redis客戶端的內核讀緩沖區。
  • 客戶端通過 read() 獲取響應數據。

當客戶端執行redis.get(“key”)命令時,

  • 客戶端將命令通過 write() 進入 內核寫緩沖區
  • 內核寫緩存區的數據會從網卡 → redis服務端的內核讀緩沖區。
  • redis服務端通過多路復用(epoll)得知內核讀緩存區有命令需要執行。
  • 執行之后的響應數據進入Redis服務器的 內核寫緩沖區
  • 接著內核寫緩存區的數據又會從網卡 → redis客戶端的內核讀緩沖區。
  • 客戶端通過 read() 獲取響應數據。

GET 命令全流程:

在這里插入圖片描述

客戶端詳細視角:

在這里插入圖片描述

服務端詳細視角:

在這里插入圖片描述

redis服務端視角就能體現Redis高性能的核心
通過非阻塞IO + 多路復用(epoll/kqueue)單線程監聽所有連接的緩沖區狀態

  • 當某連接的讀緩沖區有數據 → 觸發Redis讀取命令
  • 當某連接的寫緩沖區有空閑 → 觸發Redis發送響應

此時你可能還不了解非阻塞IO和多路復用究竟是什么?沒事,繼續看下去。

這里要特別注意,**這里的非阻塞IO是指redis服務器,而非客戶端。**因此下面將對比介紹阻塞IO和非阻塞IO,以及多路復用(事件循環)。

2、非阻塞IO & 阻塞IO

阻塞IO:典型的例子就是Java 的 Jedis(同步阻塞客戶端)

jedis.get(“key”) :

  • 觸發 write():客戶端將 GET key 命令寫入內核寫緩沖區 → 通常瞬間完成

    • 緩沖區未滿:寫入數據
    • 緩沖區滿了:線程卡在 write() 調用(阻塞)
  • 觸發read():客戶端嘗試從內核讀緩沖區讀取 Redis 的響應(如 "value"

    • 有數據:立即返回結果 → 線程繼續執行

    • 無數據:線程卡在 read() 調用(阻塞)

非阻塞IO:典型的例子就是Redis 服務器內部

Redis 將 socket 設置為 Non_Blocking

  • 調用 read() 時無數據,也會立刻返回 EAGAIN 錯誤而非阻塞。
  • 調用 write() 時無空間,也會立刻返回 EAGAIN 錯誤而非阻塞。

這邊想要再擴展一個非阻塞IO的例子:

支持非阻塞的客戶端庫(如 Lettuce

  1. commands.get() 將命令寫入內核寫緩沖區(非阻塞寫)。
  2. 客戶端庫 注冊回調函數 并立即返回。
  3. 庫內部用 Selector 輪詢 內核讀緩沖區 → 數據到達后調用回調。

其實,redis只有在感知到內核讀緩沖區有數據時,才會調用 read() 去讀取數據。

那么redis是怎么感知到內核讀緩沖區有數據的?當緩沖區滿了,又是怎么知道要什么時候能繼續寫入數據?答案就是通過多路復用(epoll)。

3、多路復用(epoll)

// Redis 事件循環偽代碼
void eventLoop() {while(server.running) {// 0. 計算超時時間(動態值,假設為200ms)timeout = calculate_timeout(); // 1. 獲取待處理事件(核心:epoll_wait 在此等待,最多只會阻塞等待timeout時間,如果在這個超時時間內有數據了就會恢復運行態,如果在這個超時時間內依然沒有數據,那么就會去處理其他事件,比如時間事件)events = epoll_wait(epoll_fd, events, MAX_EVENTS, timeout); // 2. 處理文件事件(網絡請求,處理命令)for each event in events:if event.is_readable:  // 可讀事件 → 執行客戶端命令readQueryFromClient()if event.is_writable: // 可寫事件 → 發送響應writeReplyToClient()// 3. 處理時間事件(定時任務,如RDB備份、Key過期)processTimeEvents()}
}

流程圖如下:

 />

以上代碼,基本可以說明redis單線程都在干什么了:

一個永不停止的循環(while(1)),用 單線程 同時監聽 所有客戶端連接 + 定時任務 + 內部任務,通過事件分發處理請求。

這里具體介紹epoll機制:

// Redis 僅通過 epoll 做一件事:
int num_events = epoll_wait(epoll_fd, events, MAX_EVENTS, timeout);
  • 監聽對象:所有客戶端連接的 socket
  • 監聽事件
    • EPOLLIN內核讀緩沖區有數據可讀(客戶端命令到達)
    • EPOLLOUT內核寫緩沖區有空閑空間(可發送響應)

在這里插入圖片描述

epoll 感知事件的底層原理是全程無CPU輪詢!依賴硬件中斷

// 系統調用流程
int epoll_wait() {// 1. 檢查就緒隊列(快速路徑)if (!list_empty(rdllist)) return events; // 立即返回// 2. 無事件時:讓出CPUset_current_state(TASK_INTERRUPTIBLE); // 標記為阻塞態schedule(); // 主動讓出CPU → 其他進程運行
}

也就是說,進入epoll_wait方法,該redis單線程是處于阻塞態的,不占cpu的任何消耗。

在這里插入圖片描述

這里我還想補充一點,就是之前我學的,redis的rdb持久化以及aof重寫過程中會fork一個子進程、aof是開啟后臺線程刷屏、以及redis4.0出現的懶惰刪除也是在后臺線程進行的。以上三種情況與redis的單線程又是什么關系呢?

可以這樣理解:Redis的「單線程」本質上是對命令執行模型的核心描述,但整個系統確實存在多線程/多進程協作。

在這里插入圖片描述

BIO后臺線程(Background I/O Threads):

  • AOF fsync :將AOF緩沖數據刷盤,因為 fsync() 可能阻塞30ms+
  • lazy free :異步刪除大Key,避免主線程阻塞數秒。(BIO線程刪除Key時,主線程已將該Key標記為邏輯刪除(移除key的指針的指針引用),BIO只是物理釋放內存)

在這里插入圖片描述

子進程(Child Process):

  • AOF重寫 觸發 BGREWRITEAOF,fork子進程,父子進程共享內存頁,Copy-On-Write 寫時復制
  • RDB持久化 執行 SAVE / 定時保存,fork子進程,父子進程共享內存頁,Copy-On-Write 寫時復制

總結:主線程獨占寫操作(100%),而子進程是只讀數據,而BIO線程只處理非數據操作。

  • AOF重寫 觸發 BGREWRITEAOF,fork子進程,父子進程共享內存頁,Copy-On-Write 寫時復制
  • RDB持久化 執行 SAVE / 定時保存,fork子進程,父子進程共享內存頁,Copy-On-Write 寫時復制

總結:主線程獨占寫操作(100%),而子進程是只讀數據,而BIO線程只處理非數據操作。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/86780.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/86780.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/86780.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

進程間通信詳解(三):Linux進程信號深度解析

文章目錄 一、Linux進程信號核心概念1.1 信號本質1.2 關鍵術語1.3 Linux 信號機制的核心流程: 二、信號產生機制全景2.1 通過終端按鍵產生信號2.1.1 基本操作 2.2 調用系統命令向進程發信號2.2.1 kill 命令:向指定進程發送信號2.2.2 killall 命令&#x…

C++ 日志系統實戰第五步:日志器的設計

全是通俗易懂的講解,如果你本節之前的知識都掌握清楚,那就速速來看我的項目筆記吧~ 本文項目代碼編寫收尾! 日志器類 (Logger) 設計(建造者模式) 日志器主要用于和前端交互。當我們需要使用日志系統打印 log 時&…

Spring Boot + MyBatis日志前綴清除方法

在 Spring Boot 結合 MyBatis 的應用中&#xff0c;清空日志前綴&#xff08;如 > 、< 等&#xff09;需要通過 自定義 MyBatis 的日志實現 或 修改日志模板 來實現。以下是兩種常用方法&#xff1a; 方法 1&#xff1a;自定義 MyBatis 日志實現&#xff08;推薦&#xf…

【消息隊列】——如何實現消息保序

目錄 一、哪些場景需要消息保序?二、如何實現消息保序?三、保序消息的常見問題和應對策略3.1、重復消息3.2、節點故障3.3、分區擴容四、小結本文來源:極客時間vip課程筆記 一、哪些場景需要消息保序? 消息保序問題指的是,在通過消息中間件傳遞消息過程中,我們希望消費者收…

Transformer模型詳解

Transformer Transformer真是個細節滿滿的框架呢&#xff0c;大三讀到根本不敢看&#xff0c;考研復試前看了看&#xff0c;以為懂了其實差得還遠&#xff0c;兩個多月前看了&#xff0c;還是一知半解&#xff0c;如今終于經過細細分析&#xff0c;算是知道了Transformer的基本…

火山引擎發布豆包大模型 1.6 與視頻生成模型 Seedance 1.0 pro

6 月 11 日&#xff0c;在火山引擎 FORCE 原動力大會上&#xff0c;字節跳動旗下火山引擎正式發布豆包大模型 1.6、豆包?視頻生成模型 Seedance 1.0 pro、豆包?語音播客模型&#xff0c;豆包?實時語音模型也在火山引擎全量上線&#xff0c;豆包大模型家族已成為擁有全模態、…

PH熱榜 | 2025-06-12

1. Atlas 標語&#xff1a;幾秒鐘內了解定價情況 介紹&#xff1a;獲取即插即用的定價頁面&#xff0c;讓你輕松賺錢&#xff0c;不再辛苦操勞。 產品網站&#xff1a; 立即訪問 Product Hunt&#xff1a; View on Product Hunt 關鍵詞&#xff1a;Atlas, 定價快速, 插件式…

ChatGPT革命升級!o3-pro模型重磅發布:開啟AI推理新紀元

2025年6月10日&#xff0c;OpenAI以一場低調而震撼的發布&#xff0c;正式推出了新一代推理模型o3-pro&#xff0c;這標志著人工智能在復雜問題解決領域的重大突破。作為ChatGPT Pro和Team訂閱用戶的專屬工具&#xff0c;o3-pro不僅重新定義了AI的可靠性標準&#xff0c;更以其…

NVIDIA Isaac GR00T N1.5 適用于 LeRobot SO-101 機械臂

系列文章目錄 目錄 系列文章目錄 前言 一、簡介 二、詳細教程 2.1 數據集準備 2.1.1 創建或下載您的數據集 2.1.2 配置模態文件 2.2 模型微調 2.3 開環評估 2.4 部署 &#x1f389; 快樂編程&#xff01;&#x1f4bb;&#x1f6e0;? 立即開始&#xff01; 前言 一…

【編譯工具】(自動化)自動化測試工具:如何讓我的開發效率提升300%并保證代碼質量?

目錄 引言&#xff1a;自動化測試在現代開發中的關鍵作用 一、自動化測試金字塔&#xff1a;構建高效的測試策略 &#xff08;1&#xff09;測試金字塔模型 &#xff08;2&#xff09;各層級代表工具 二、前端自動化測試實戰&#xff1a;Jest Cypress &#xff08;1&…

R語言緩釋制劑QBD解決方案之一

本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》緩釋制劑包衣處方研究的R語言解決方案。 ER聚合物包衣處方優化研究 基于初步風險評估和初始可行性研究&#xff0c;進行帶3個中心點的24-1分式析因DOE。藥物的釋放被識別為CQA。本研究的…

行為模式-命令模式

定義&#xff1a; 命令模式是一個高內聚的模式&#xff0c;其定義為&#xff1a;Encapsulate a request as an object,thereby letting you parameterize clients with different requests,queue or log requests,and support undoable operations.&#xff08;將一個請求封裝成…

Ubuntu 24.04 上安裝與 Docker 部署 Sentinel

Ubuntu 24.04 上安裝與 Docker 部署 Sentinel 一、Sentinel 簡介 Sentinel 是阿里巴巴開源的分布式系統流量控制組件&#xff0c;提供流量控制、熔斷降級和系統負載保護等功能。它通過可視化控制臺&#xff08;Dashboard&#xff09;實現實時監控和規則管理&#xff0c;是微服…

IP 地址查詢在證券交易中的應用方式

網絡安全保障與IP地址查詢 證券交易平臺存儲著海量投資者的敏感信息以及巨額資金的交易數據&#xff0c;是網絡攻擊的重點目標。IP 地址查詢在檢測異常登錄行為方面至關重要。例如&#xff0c;當一個賬戶短時間內先在國內某城市登錄&#xff0c;隨后又在境外 IP 地址發起交易操…

Flutter 常用組件詳解:Text、Button、Image、ListView 和 GridView

Flutter 作為 Google 推出的跨平臺 UI 框架&#xff0c;憑借其高效的渲染性能和豐富的組件庫&#xff0c;已經成為移動應用開發的熱門選擇。本文將深入探討 Flutter 中最常用的五個基礎組件&#xff1a;Text、Button、Image、ListView 和 GridView&#xff0c;幫助開發者快速掌…

docker 單機部署redis集群(一)

docker 部署redis集群 1、創建redis網卡 docker network create redis --subnet 172.38.0.0/16查看網卡信息 docker network ls docker network inspect redis2、創建redis配置 #使用腳本創建6個redis配置for port in $(seq

MySQL 索引學習筆記

1.二叉樹&#xff0c;紅黑樹&#xff0c;B 樹&#xff0c;B樹 二叉樹&#xff1a;就是每個節點最多只能有兩個子節點的樹&#xff1b; 紅黑樹&#xff1a;就是自平衡二叉搜索樹&#xff0c;紅黑樹通過一下五個規則構建&#xff1a; 1.節點只能是紅色或黑色&#xff1b; 2.根…

Windows安裝docker及使用

下載 https://www.docker.com/ 安裝 啟動 此時拉取鏡像會報錯 Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers) 配置引擎 添加以…

多參表達式Hive UDF

支持的操作符 &#xff1a;跳過&#xff0c;即無條件篩選&#xff1a;等于!&#xff1a;不等于range&#xff1a;區間內&#xff0c;range[n,m]表示 between n and mnrange&#xff1a;區間外&#xff0c;即not between andin&#xff1a;集合內&#xff0c;in(n,m,j,k)表示 in…

GO后端開發內存管理及參考答案

什么是 Go 的逃逸分析&#xff08;Escape Analysis&#xff09;&#xff0c;為什么需要它&#xff1f; Go 的逃逸分析是一種編譯時技術&#xff0c;用于確定變量的生命周期是否超出其創建的函數作用域。通過分析變量的使用方式&#xff0c;編譯器能夠判斷變量是否需要在堆上分…