redis學習筆記三 redis命令的執行過程

2021-09-25 12:07:57 字數 4102 閱讀 5148

redis 是單執行緒應用,它是如何與多個客戶端簡歷網路鏈結並處理命令的?

由於 redis 是基於 i/o 多路復用技術,為了能夠處理多個客戶端的請求,redis 在本地為每乙個鏈結到 redis 伺服器的客戶端建立了乙個 redisclient 的資料結構,這個資料結構包含了每個客戶端各自的狀態和執行的命令。 redis 伺服器使用乙個鍊錶來維護多個 redisclient 資料結構。

在伺服器端用乙個鍊錶來管理所有的 redisclient。

struct redisserver
所以我就看看 redisclient 包含的資料結構和重要引數:

typedef struct redisclient
這裡需要特別的注意,redisclient 並非指遠端的客戶端,而是乙個 redis 服務本地的資料結構,我們可以理解這個 redisclient 是遠端客戶端的乙個對映或者**。

flags

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

querybuf

querybuf 是乙個 sds 動態字串型別,所謂 buf 說明是它只是乙個緩衝區,用於儲存沒有被解析的命令。

argc & ar**

上文的 querybuf 是乙個沒有處理過的命令,當 redis 將 querybuf 命令解析以後,會將得出的引數個數和以及引數分別儲存在 argc 和 ar** 中。ar** 是乙個 redisobject 的陣列。

cmdredis 使用乙個字典儲存了所有的 rediscommand。key 是 rediscommand 的名字,值就是乙個 rediscommand 結構,這個結構儲存了命令的實現函式,命令的標誌,命令應該給定的引數個數,命令的執行次數和總消耗時長等統計資訊,cmd 是乙個 rediscommand。

當 redis 解析出 ar** 和 argc 後,會根據陣列 ar**[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 這個鍊錶來儲存資料。

其他引數上文說過 redisserver 是用乙個鍊錶來維護所有的 redisclient 狀態,每當有乙個客戶端發起鏈結以後,就會在 redis 中生成乙個對應的 redisclient 資料結構,增加到clients這個鍊錶之後。

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

總體分為幾種型別:

呼叫總結

當客戶端和伺服器端的巢狀字變得可讀的時候,伺服器將會呼叫命令請求處理器來執行以下操作:

讀取巢狀字中的資料,寫入 querybuf。

解析 querybuf 中的命令,記錄到 argc 和 ar** 中。

根據 ar**[0] 查詢對應的 recommand。

執行 recommand 對應的實現函式。

執行以後將結果存入 buf & bufpos & reply 中,返回給呼叫方。

上文是從 redisclient 的角度來觀察命令的執行,文章接下來的部分將會從 redis 的**層面,微觀的觀察 redis 是怎麼實現命令的執行的。

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

可以繼續觀察 redis 的 main() 函式。

int main(int argc, char **ar**)
我們只關注 initserver() 這個函式,他負責初始化伺服器的資料結構。繼續跟蹤**:

void initserver() 

}// 為本地套接字關聯應答處理器

if (server.sofd > 0 && aecreatefileevent(server.el,server.sofd,ae_readable,

acceptunixhandler,null) == ae_err) redispanic("unrecoverable error creating server.sofd file event.");

//...

}

在這段**裡面:

當有乙個遠端客戶端連線到 redis 的伺服器,會觸發 accepttcphandler 事件處理器.

accepttcphandler 事件處理器,會建立乙個鏈結。然後繼續呼叫 acceptcommonhandler。

acceptcommonhandler 事件處理器的作用是:

這個時候 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 和 ar** 中。

processcommand 根據 ar**[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 將會臨時中斷寫入,記錄操作的進度,將處理時間讓給其他操作,剩餘的內容等下次繼續。這樣的套路我們一路走來看過太多了。

遠端客戶端連線到 redis 後,redis服務端會為遠端客戶端建立乙個 redisclient 作為**。

redis 會讀取巢狀字中的資料,寫入 querybuf 中。

解析 querybuf 中的命令,記錄到 argc 和 ar** 中。

根據 ar**[0] 查詢對應的 recommand。

執行 recommend 對應的執行函式。

執行以後將結果存入 buf & bufpos & reply 中。

返回給呼叫方。返回資料的時候,會控制寫入資料量的大小,如果過大會分成若干次。保證 redis 的相應時間。

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

Redis學習筆記(三) pipeline

redis客戶端執行一條命令分4個過程 傳送命令 命令排隊 命令執行 返回結果這個過程稱為round trip time 簡稱rtt,往返時間 mgetmset有效節約了rtt,但大部分命令 如hgetall,並沒有mhgetall 不支援批量操作,需要消耗n次rtt,這個時候需要pipeline來...

redis學習筆記三(set)

sadd keyname value 向set存入值 smembers keyname 查詢set的所有值 sismember keyname value 查詢指定的值是否存在 127.0.0.1 6379 sadd myset v1 integer 1 127.0.0.1 6379 sadd my...

Redis學習筆記 Redis事務

redis事務可以一次執行多個命令 按順序地序列執行,執行中不會被其他命令插入,不許加塞 1.簡介 redis事務可以一次執行多個命令 允許在一次單獨的步驟中執行一組命令 特徵 1 批量操作在傳送exec命令前被放入佇列快取 2 收到exec命令後進入事務執行,事務中任意命令執行失敗,其餘的命令依然...