php-redis源碼之長連接、短連接、命令自動檢活

源碼函數所在文件

爲了避免代碼影響閱讀,以及代碼順序不符合個人的讀碼習慣,就不貼代碼了,都可以通過函數名在下面幾個c文件中找到

  • redis.c
  • library.c
  • common.h

幾個核心函數

  • redis_connect:用於創建redis對象並建立sock連接。第一個參數INTERNAL_FUNCTION_PARAM_PASSTHRU是宏定義,用來獲取函數傳入的參數,第二個參數persistent用於區分是否長鏈接。

  • redis_sock_get:獲取sock,檢活,第一個參數如果爲空的sock對象,則代表用新的連接,並且不需要檢活;如果爲當前sock對象(getThis函數獲取),則需要在hash符號表裏查找是否有舊的sock對象。

  • redis_sock_get_instance:根據redis實例的id,返回redis實例中的sock

  • redis_sock_server_open:用於判斷socket活躍狀態,如果連接已斷開調用redis_sock_connect重新連接。

  • redis_sock_create:爲redis實例對象創建新的sock連接,申請空間,存儲到zend全局空間中

  • redis_sock_disconnect:釋放sock連接,如果是長鏈接從連接池中獲取釋放,短連接直接釋放

  • redis_sock_get_connection_pool:從連接池中獲取連接

  • php_stream_pclose:關閉長連接數據流

  • php_stream_close:關閉短連接數據流

  • redis_free_socket:釋放sock佔用的zend全局空間

幾個核心宏定義

  • PHPREDIS_GET_OBJECT:獲取redis實例

  • REDIS_THROW_EXCEPTION:拋出異常

  • INTERNAL_FUNCTION_PARAM_PASSTHRU獲取參數

 

pconnect長鏈接邏輯

調用redis_connect創建長鏈接經歷下面幾個步驟(參數persistent爲1)

  1. 初始化變量和參數
  2. 條件編譯,檢測ZTS宏定義,將persistent改爲0(我猜是在某些環境下不允許長鏈接)
  3. 調用zend_parse_method_parameters獲取參數,獲取失敗則返回錯誤

  4. 如果是短連接,persistent_id(長鏈接id)定義爲NULL,這裏由於是長鏈接,跳過

  5. 檢測timeout、read_timeout、retry_interval、port

  6. 調用PHPREDIS_GET_OBJECT宏定義獲取redis對象

  7. 如果該redis對象的sock已經被創建則調用redis_sock_disconnect斷開sock連接,並調用redis_free_socket關閉sock(避免同一個redis實例創建多個sock造成端口占用)

  8. redis_sock_create爲sock創建持久化連接,這裏通過保存在RedisSock裏的持久化標識persistent_id來使用同一個sock

  9. 爲了保險,調用redis_sock_server_open檢查連接狀態,如果連接失敗調用redis_free_socket釋放sock,並返回錯誤

  10. 返回成功

connect短連接邏輯

    和上面創建長鏈接步驟一致,只不過persistent參數爲0

redis命令操作

  • REDIS_PROCESS_CMD進入執行redis命令

  • 調用redis_sock_get獲取當前連接,第一個參數用getThis()函數獲取當前redis對象,參數no_throw傳0代表redis_sock_get_instance不跳過異常拋出

  • 調用redis_sock_get_instance獲取redis實例中的sock連接

  • 調用redis_sock_server_open檢測連接狀態,斷開會自動重連

  • 返回活躍的redis_sock連接

  • 用前面返回的sock連接執行redis命令

  • 返回命令結果

 

結論

  1. redis客戶端對象存儲在Zend的全局EG哈希表中,所以redis對象和sock長連接的在子進程重啓後纔會被釋放
  2. redis長鏈接通過複用同一個sock實現,通過RedisSock結構體中的persistent標識是否爲長鏈接
  3. 重複pconnect會造成多次斷開和連接
  4. 每次redis命令之前會自動檢活
  5. 如果使用pconnect連接,調用close之後會關閉並釋放sock連接,但是隻要子進程不重啓,就會複用同一個sock連接,重新連接
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章