文档首页/ 分布式缓存服务 DCS/ 常见问题/ 客户端和网络连接/ 使用短连接访问Redis出现“Cannot assign requested address”错误
更新时间:2022-08-16 GMT+08:00

使用短连接访问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('${Hostname}',${Port});
    $redis->auth('${Inst_Password}');

    现使用pconnect替换connect,即使用persistent connection的方式连接。

    $redis->pconnect('${Hostname}', ${Port}, 0, NULL, 0, 0, ['auth' => ['${Inst_Password}']]);
    • 示例中的连接参数请根据业务实现情况修改,${Hostname}、${Port}和${Inst_Password}为Redis实例的连接地址、端口号和密码。
    • PhpRedis应为5.3.0及以上版本,且建议使用这种pconnect初始化方式,避免断连时出现no auth问题。
  • 方案二:修改客户端所在ECS实例的tcp_max_tw_buckets内核参数。

    此方案的思路是直接复用处于TIME-WAIT状态的端口,但是如果ECS和后端服务之间有重传,连接可能会失败,所以建议使用pconnect的方案。

    1. 连接客户端所在ECS实例。
    2. 执行以下命令,查看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
    3. 执行以下命令,修改tcp_max_tw_buckets参数,确保tcp_max_tw_buckets的值比ip_local_port_range范围的值小。

      sysctl -w net.ipv4.tcp_max_tw_buckets=10000

一般情况推荐使用方案一,对于一些特定场景(业务代码牵涉过多组件不易变更等场景),需要更快的满足高并发,可以使用方案二