天天看點

短連接配接通路Redis報錯Cannot assign requested address解決方案

“短連接配接通路Redis報錯Cannot assign requested address”,出現這種錯誤的應用程式使用的架構基本都是php-fpm+phpredis。并發較大的情況下,處于TIME-WAIT狀态下的TCP連接配接較多,用戶端無法配置設定出新的端口,報錯Cannot assign requested address。下面針對這種情況給解決方案,有兩種解決方案,适用于不同的場景:

一勞永逸-使用pconnect替換connect

這種方案的思路是用長連接配接替代短連接配接,減少TCP連接配接,同時可以避免每次請求建連,減少延時。

之前連接配接Redis的代碼是:

$redis->connect('inst-name.redis.rds.aliyuncs.com', 6379);
$redis->auth('inst-password');           

修改為pconnect,使用persistent connection:

// phpredis >= 5.3.0, 強烈建議這種pconnect初始化方式,避免斷連時出現no auth
// timeout,persistent_id,retry_interval,read_timeout等參數根據業務實作情況修改
// 官方文檔:https://github.com/phpredis/phpredis#pconnect-popen
// $redis->connect('inst-name.redis.rds.aliyuncs.com', 6379);
$redis->pconnect('inst-name.redis.rds.aliyuncs.com', 6379, 0, NULL, 0, 0, ['auth' => ['inst-password']]);           

無奈之選-修改用戶端所在ECS核心參數tcp_max_tw_buckets

這種方案的思路是直接複用處于TIME-WAIT狀态的端口,但是如果服務端因為重傳對應五元組仍然處于LAST-ACK狀态時,建連會失敗,是以強烈建議pconnect的方案。

對于一些場景(比如說業務代碼牽涉過多元件不易變更等),需要更快的方式來滿足高并發的場景,可以選擇修改核心參數tcp_max_tw_buckets,避免出現Cannot assign requested address錯誤。

  1. 檢視ip_local_port_range和tcp_max_tw_buckets
    $sysctl net.ipv4.tcp_max_tw_buckets net.ipv4.ip_local_port_range
    net.ipv4.tcp_max_tw_buckets = 262144
    net.ipv4.ip_local_port_range = 32768    61000           
  2. 修改tcp_max_tw_buckets,保證tcp_max_tw_buckets比ip_local_port_range小
    sysctl -w net.ipv4.tcp_max_tw_buckets=10000           

請忽略所有修改tcp_tw_reuse、tcp_tw_recycle的方法,這些方法對于使用了nat/lvs的服務均不适用(tcp_tw_recycle在Linux 4.12上已經被棄用)。

繼續閱讀