校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃

主頁 > 知識庫 > Redis學習教程之命令的執行過程詳解

Redis學習教程之命令的執行過程詳解

熱門標簽:小紅書怎么地圖標注店 地圖標注如何即時生效 地圖標注費用 竹間科技AI電銷機器人 玄武湖地圖標注 太原營銷外呼系統 百度商家地圖標注怎么做 最簡單的百度地圖標注 西藏教育智能外呼系統價格

前言

之前寫了一系列文章,已經很深入的探討了 Redis 的數據結構,數據庫的實現,key的過期策略以及 Redis 是怎么處理事件的。所以距離 Redis 的單機實現只差最后一步了,就是 Redis 是怎么處理 client 發來的命令并返回結果的,所以我們就仔細討論一下 Redis 是怎么執行命令的。

閱讀這篇文章你將會了解到:

  • Redis 是怎么執行遠程客戶端發來的命令的

Redis client(客戶端)

Redis 是單線程應用,它是如何與多個客戶端簡歷網絡鏈接并處理命令的?
由于 Redis 是基于 I/O 多路復用技術,為了能夠處理多個客戶端的請求,Redis 在本地為每一個鏈接到 Redis 服務器的客戶端創建了一個 redisClient 的數據結構,這個數據結構包含了每個客戶端各自的狀態和執行的命令。 Redis 服務器使用一個鏈表來維護多個 redisClient 數據結構。

在服務器端用一個鏈表來管理所有的 redisClient。

struct redisServer {
 //...
 list *clients;  /* List of active clients */
 //...
}

所以我就看看 redisClient 包含的數據結構和重要參數:

typedef struct redisClient {

 // 客戶端狀態標志
 int flags;  /* REDIS_SLAVE | REDIS_MONITOR | REDIS_MULTI ... */
 
 // 套接字描述符
 int fd;

 // 當前正在使用的數據庫
 redisDb *db;

 // 當前正在使用的數據庫的 id (號碼)
 int dictid;

 // 客戶端的名字
 robj *name;  /* As set by CLIENT SETNAME */

 // 查詢緩沖區
 sds querybuf;

 // 查詢緩沖區長度峰值
 size_t querybuf_peak; /* Recent (100ms or more) peak of querybuf size */

 // 參數數量
 int argc;

 // 參數對象數組
 robj **argv;

 // 記錄被客戶端執行的命令
 struct redisCommand *cmd, *lastcmd;

 // 請求的類型:內聯命令還是多條命令
 int reqtype;

 // 剩余未讀取的命令內容數量
 int multibulklen; /* number of multi bulk arguments left to read */

 // 命令內容的長度
 long bulklen;  /* length of bulk argument in multi bulk request */

 // 回復鏈表
 list *reply;

 // 回復鏈表中對象的總大小
 unsigned long reply_bytes; /* Tot bytes of objects in reply list */

 // 已發送字節,處理 short write 用
 int sentlen;  /* Amount of bytes already sent in the current
    buffer or object being sent. */

 // 回復偏移量
 int bufpos;
 // 回復緩沖區
 char buf[REDIS_REPLY_CHUNK_BYTES];
 // ...
}

這里需要特別的注意,redisClient 并非指遠程的客戶端,而是一個 Redis 服務本地的數據結構,我們可以理解這個 redisClient 是遠程客戶端的一個映射或者代理。

flags

flags 表示了目前客戶端的角色,以及目前所處的狀態。他比較特殊可以單獨表示一個狀態或者多個狀態。

querybuf

querybuf 是一個 sds 動態字符串類型,所謂 buf 說明是它只是一個緩沖區,用于存儲沒有被解析的命令。

argc argv

上文的 querybuf 是一個沒有處理過的命令,當 Redis 將 querybuf 命令解析以后,會將得出的參數個數和以及參數分別保存在 argc 和 argv 中。argv 是一個 redisObject 的數組。

cmd

Redis 使用一個字典保存了所有的 redisCommand。key 是 redisCommand 的名字,值就是一個 redisCommand 結構,這個結構保存了命令的實現函數,命令的標志,命令應該給定的參數個數,命令的執行次數和總消耗時長等統計信息,cmd 是一個 redisCommand。

當 Redis 解析出 argv 和 argc 后,會根據數組 argv[0],到字典中查詢出對應的 redisCommand。上文的例子中 Redis 就會去字典去查找 SET 這個命令對應的 redisCommand。redis 會執行 redisCommand 中命令的實現函數。

buf bufpos reply

buf 是一個長度為 REDIS_REPLY_CHUNK_BYTES 的數組。Redis 執行相應的操作以后,就會將需要返回的返回的數據存儲到 buf 中,bufpos 用于記錄 buf 中已用的字節數數量,當需要恢復的數據大于 REDIS_REPLY_CHUNK_BYTES 時,redis 就會是用 reply 這個鏈表來保存數據。

其他參數

其他參數大家看注釋就能明白,就是字面的意思。省略的參數基本上涉及 Redis 集群管理的參數,在之后的文章中會繼續講解。

客戶端的鏈接和斷開

上文說過 redisServer 是用一個鏈表來維護所有的 redisClient 狀態,每當有一個客戶端發起鏈接以后,就會在 Redis 中生成一個對應的 redisClient 數據結構,增加到clients這個鏈表之后。

一個客戶端很可能被多種原因斷開。

總體分為幾種類型:

  • 客戶端主動退出或者被 kill。
  • timeout 超時。
  • Redis 為了自我保護,會斷開發的數據超過限制大小的客戶端。
  • Redis 為了自我保護,會斷需要返回的數據超過限制大小的客戶端。

調用總結

當客戶端和服務器端的嵌套字變得可讀的時候,服務器將會調用命令請求處理器來執行以下操作:

  1. 讀取嵌套字中的數據,寫入 querybuf。
  2. 解析 querybuf 中的命令,記錄到 argc 和 argv 中。
  3. 根據 argv[0] 查找對應的 recommand。
  4. 執行 recommand 對應的實現函數。
  5. 執行以后將結果存入 buf bufpos reply 中,返回給調用方。

Redis Server (服務端)

上文是從 redisClient 的角度來觀察命令的執行,文章接下來的部分將會從 Redis 的代碼層面,微觀的觀察 Redis 是怎么實現命令的執行的。

redisServer 的啟動

在了解redisServer 的工作機制的工作機制之前,需要了解 redisServer 的啟動做了什么:

可以繼續觀察 Redis 的 main() 函數。

int main(int argc, char **argv) {
 //...
 // 創建并初始化服務器數據結構
 initServer();
 //...
}

我們只關注 initServer() 這個函數,他負責初始化服務器的數據結構。繼續跟蹤代碼:

void initServer() {
 //...
 //創建eventLoop
 server.el = aeCreateEventLoop(server.maxclients+REDIS_EVENTLOOP_FDSET_INCR);
 /* Create an event handler for accepting new connections in TCP and Unix
 * domain sockets. */
 // 為 TCP 連接關聯連接應答(accept)處理器
 // 用于接受并應答客戶端的 connect() 調用
 for (j = 0; j  server.ipfd_count; j++) {
 if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,
  acceptTcpHandler,NULL) == AE_ERR)
  {
  redisPanic(
   "Unrecoverable error creating server.ipfd file event.");
  }
 }

 // 為本地套接字關聯應答處理器
 if (server.sofd > 0  aeCreateFileEvent(server.el,server.sofd,AE_READABLE,
 acceptUnixHandler,NULL) == AE_ERR) redisPanic("Unrecoverable error creating server.sofd file event.");
 //...
}

篇幅限制,我們省略了很多與本編文章無關的代碼,保留了核心邏輯代碼。

在上一篇文章中 《Redis 中的事件驅動模型》 我們講解過,redis 使用不同的事件處理器,處理不同的事件。

在這段代碼里面:

  • 初始化了事件處理器的 eventLoop
  • 向 eventLoop 中注冊了兩個事件處理器 acceptTcpHandler 和 acceptUnixHandler,分別處理遠程的鏈接和本地鏈接。

redisClient 的創建

當有一個遠程客戶端連接到 Redis 的服務器,會觸發 acceptTcpHandler 事件處理器.

acceptTcpHandler 事件處理器,會創建一個鏈接。然后繼續調用 acceptCommonHandler。

acceptCommonHandler 事件處理器的作用是:

  • 調用 createClient() 方法創建 redisClient
  • 檢查已經創建的 redisClient 是否超過 server 允許的數量的上限
  • 如果超過上限就拒絕遠程連接
  • 否則創建 redisClient 創建成功
  • 并更新連接的統計次數,更新 redisClinet 的 flags 字段

這個時候 Redis 在服務端創建了 redisClient 數據結構,這個時候遠程的客戶端就在 redisServer 中創建了一個代理。遠程的客戶端就與 Redis 服務器建立了聯系,就可以向服務器發送命令了。

處理命令

在 createClient() 行數中:

// 綁定讀事件到事件 loop (開始接收命令請求)
if (aeCreateFileEvent(server.el,fd,AE_READABLE,readQueryFromClient, c) == AE_ERR)

向 eventLoop 中注冊了 readQueryFromClient。 readQueryFromClient 的作用就是從client中讀取客戶端的查詢緩沖區內容。

然后調用函數 processInputBuffer 來處理客戶端的請求。在 processInputBuffer 中有幾個核心函數:

  • processInlineBuffer 和 processMultibulkBuffer 解析 querybuf 中的命令,記錄到 argc 和 argv 中。
  • processCommand 根據 argv[0] 查找對應的 recommen,執行 recommend 對應的執行函數。在執行之前還會驗證命令的正確性。將結果存入 buf bufpos reply 中

返回數據

萬事具備了,執行完了命令就需要把數據返回給遠程的調用方。調用鏈如下

processCommand -> addReply -> prepareClientToWrite

在 prepareClientToWrite 中我們有見到了熟悉的代碼:

aeCreateFileEvent(server.el, c->fd, AE_WRITABLE,sendReplyToClient, c) == AE_ERR) return REDIS_ERR;

向 eventloop 綁定了 sendReplyToClient 事件處理器。

在 sendReplyToClient 中觀察代碼發現,如果 bufpos 大于 0,將會把 buf 發送給遠程的客戶端,如果鏈表 reply 的長度大于0,就會將遍歷鏈表 reply,發送給遠程的客戶端,這里需要注意的是,為了避免 reply 數據量過大,就會過度的占用資源引起 Redis 相應慢。為了解決這個問題,當寫入的總數量大于 REDIS_MAX_WRITE_PER_EVENT 時,Redis 將會臨時中斷寫入,記錄操作的進度,將處理時間讓給其他操作,剩余的內容等下次繼續。這樣的套路我們一路走來看過太多了。

總結

  1. 遠程客戶端連接到 redis 后,redis服務端會為遠程客戶端創建一個 redisClient 作為代理。
  2. redis 會讀取嵌套字中的數據,寫入 querybuf 中。
  3. 解析 querybuf 中的命令,記錄到 argc 和 argv 中。
  4. 根據 argv[0] 查找對應的 recommand。
  5. 執行 recommend 對應的執行函數。
  6. 執行以后將結果存入 buf bufpos reply 中。
  7. 返回給調用方。返回數據的時候,會控制寫入數據量的大小,如果過大會分成若干次。保證 redis 的相應時間。

Redis 作為單線程應用,一直貫徹的思想就是,每個步驟的執行都有一個上限(包括執行時間的上限或者文件尺寸的上限)一旦達到上限,就會記錄下當前的執行進度,下次再執行。保證了 Redis 能夠及時響應不發生阻塞。

好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

您可能感興趣的文章:
  • 利用yum安裝Redis的方法詳解
  • Redis中scan命令的深入講解
  • Redis不使用 keys 命令獲取鍵值信息的方法
  • redis禁止幾個危險命令的方法
  • 詳解centos7 yum安裝redis及常用命令

標簽:揚州 贛州 澳門 唐山 林芝 香港 廣東 景德鎮

巨人網絡通訊聲明:本文標題《Redis學習教程之命令的執行過程詳解》,本文關鍵詞  Redis,學習教程,之,命令,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《Redis學習教程之命令的執行過程詳解》相關的同類信息!
  • 本頁收集關于Redis學習教程之命令的執行過程詳解的相關信息資訊供網民參考!
  • 推薦文章
    校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃
    欧美人与性动xxxx| 国产精品素人一区二区| 欧美一级久久久| 国产一区二区电影| 日韩在线播放一区二区| 欧美精品一区二区三区蜜桃| 色88888久久久久久影院按摩| 亚洲色图在线看| 久久精品理论片| 日韩成人av影视| 天天操天天色综合| 久久―日本道色综合久久| 精品一区二区三区香蕉蜜桃 | 99热精品一区二区| 午夜一区二区三区在线观看| 欧美日韩免费观看一区三区| hitomi一区二区三区精品| 欧美伊人久久大香线蕉综合69 | 日本一区二区免费在线| 国产二区国产一区在线观看| 首页国产欧美久久| 国产精品一级片在线观看| 久久先锋资源网| 日韩电影在线观看网站| 日本aⅴ免费视频一区二区三区 | 91麻豆国产福利在线观看| 国内精品久久久久影院色| 国产精品国产三级国产aⅴ无密码| 欧美激情在线一区二区三区| 一区二区激情视频| 九一九一国产精品| 日韩免费在线观看| 韩国一区二区视频| 久久久99免费| 极品瑜伽女神91| 精品国产青草久久久久福利| 日日摸夜夜添夜夜添精品视频| 91在线小视频| 亚洲成人在线免费| 欧美大片一区二区| 国产mv日韩mv欧美| 国产精品国产自产拍高清av| 99精品视频一区| 亚洲成va人在线观看| 3d动漫精品啪啪1区2区免费| 蜜臀va亚洲va欧美va天堂| 精品久久久久久久一区二区蜜臀| 成人av在线播放网址| 国产欧美一区二区精品性色| 国产精品看片你懂得| 久久成人羞羞网站| 91欧美激情一区二区三区成人| 日韩欧美区一区二| 亚洲卡通动漫在线| 欧美性色黄大片| 欧美综合一区二区| 国产一区二区精品久久91| 一本色道亚洲精品aⅴ| 国产精品污网站| 久久激情五月婷婷| 国产欧美日韩三级| 91视频你懂的| 亚洲视频一区二区在线观看| 色天使久久综合网天天| 美腿丝袜亚洲综合| 天天亚洲美女在线视频| 中文字幕一区二区三区色视频 | 99国产精品99久久久久久| 一区二区三区波多野结衣在线观看| 日韩欧美二区三区| 欧美一区二区三区免费视频 | 日韩欧美亚洲一区二区| 日本精品免费观看高清观看| 国产一区二区在线观看视频| 麻豆国产精品视频| 日韩综合小视频| 日本sm残虐另类| 久草中文综合在线| 国产91在线|亚洲| 成人激情av网| 在线观看视频一区二区 | 日本乱人伦一区| 欧美视频一区二区在线观看| 欧美日韩亚洲高清一区二区| 91久久精品一区二区二区| 欧美专区在线观看一区| 日韩欧美成人激情| 日本一区二区免费在线观看视频| 亚洲国产高清在线观看视频| 亚洲免费资源在线播放| 蜜桃视频一区二区三区在线观看| 久草在线在线精品观看| 99re这里只有精品首页| 日韩一级免费观看| 亚洲天堂a在线| 国产麻豆精品视频| 在线亚洲+欧美+日本专区| www成人在线观看| 一区二区三区四区乱视频| 日韩精品电影在线| 99久久精品费精品国产一区二区| 91精品久久久久久久99蜜桃| 夜夜精品视频一区二区| 精品一区二区免费| 欧美日韩国产bt| 午夜欧美大尺度福利影院在线看| 国内偷窥港台综合视频在线播放| 亚洲黄色小说网站| 99国产精品久久久久| 国产午夜亚洲精品理论片色戒| 香蕉久久一区二区不卡无毒影院| 91伊人久久大香线蕉| 日韩毛片精品高清免费| www.久久精品| 亚洲人成影院在线观看| 午夜精品视频一区| 91麻豆精品国产91久久久久久久久| 一区二区在线观看视频| 在线观看日韩毛片| 欧美aa在线视频| 婷婷综合久久一区二区三区| 成人av片在线观看| 亚洲综合色自拍一区| 91福利在线观看| 免费在线观看成人| 国产婷婷一区二区| 在线免费观看日本一区| 九九热在线视频观看这里只有精品| 精品不卡在线视频| 色噜噜偷拍精品综合在线| 图片区小说区区亚洲影院| 久久伊人中文字幕| 91成人免费网站| 丁香激情综合五月| 午夜视频在线观看一区| 国产精品视频观看| 日韩一区二区三免费高清| 99精品视频在线观看免费| 蜜桃久久久久久| 日本成人超碰在线观看| 精品捆绑美女sm三区| 91在线视频在线| av综合在线播放| 成人午夜激情在线| 高清免费成人av| 国内成+人亚洲+欧美+综合在线| 一区二区三区欧美亚洲| 国产精品久久夜| 亚洲精品欧美综合四区| 久久精品在这里| 日本一区二区三区在线观看| 国产欧美精品国产国产专区| 精品国产髙清在线看国产毛片| 日韩免费一区二区| 久久久精品天堂| 国产精品毛片久久久久久| 国产精品天干天干在观线| 亚洲同性同志一二三专区| 亚洲欧美在线aaa| 亚洲18影院在线观看| 久草中文综合在线| 色综合久久精品| 欧美一区二区三区影视| 国产精品三级在线观看| 亚洲成人免费影院| 国产盗摄视频一区二区三区| 99国产精品久久| 日韩欧美成人一区| 自拍偷拍国产精品| 久久不见久久见免费视频7| jvid福利写真一区二区三区| 6080亚洲精品一区二区| 亚洲精品高清在线| 国产成人在线色| 精品理论电影在线| 午夜视频一区二区三区| 日韩黄色免费电影| av资源网一区| 亚洲精品一区二区三区精华液 | 蜜臀91精品一区二区三区| 色婷婷综合久久久久中文一区二区| 日韩欧美高清dvd碟片| 亚洲国产中文字幕| 欧美视频一区二区三区在线观看| 国产精品青草综合久久久久99| 国产精品一级二级三级| 久久久久久久久久电影| 日本不卡高清视频| 91麻豆精品国产91久久久久| 蜜桃久久精品一区二区| 日韩一区二区三区四区| 国产精品自拍在线| 国产欧美视频一区二区| 国产成人综合在线| 国产午夜一区二区三区| 粉嫩蜜臀av国产精品网站| 亚洲视频在线一区观看| 欧美综合在线视频| 加勒比av一区二区| 国产欧美一区二区三区沐欲|