文档

Cannot assign requested address报错

更新时间:

本文介绍当客户端通过短连接访问Redis实例时,报错Cannot assign requested address的解决方案。

问题原因

该报错通常出现在客户端使用PHP-FPM与PhpRedis组合的架构中,这种架构在高并发场景时,处于TIME-WAIT状态下的TCP连接数较多,客户端无法分配出新的端口,则会出现Cannot assign requested address报错。

解决方案

使用Pconnect替换Connect(推荐)

用长连接替代短连接,该方案可减少TCP连接,同时可以避免每次请求都会重新建立连接的问题,减少延时。

例如Connect连接代码示例如下:

$redis->connect('[$Hostname]', [$Port]);
$redis->auth('[$Inst_Password]');

参数说明:[$Hostname]、[$Port]和[$Inst_Password]分别为Redis实例的连接地址、端口号和密码,如何查看请参见查看连接地址

使用Pconnect替换Connect,即使用Persistent Connection的方式连接,示例如下:

$redis->pconnect('[$Hostname]', [$Port], 0, NULL, 0, 0, ['auth' => ['[$Inst_Password]']]);
// 若PhpRedis版本大于等于5.3.0,建议使用Pconnect初始化方式,避免断连时出现no auth。
// timeout、persistent_id、retry_interval和read_timeout等参数根据业务实现情况修改。

修改客户端所在ECS实例的tcp_max_tw_buckets内核参数

对于一些特定场景,例如业务代码牵涉过多组件不易变更等,您可以使用此方案,快速实现高可用。

此方案将直接修改tcp_max_tw_buckets参数,但如果服务端因为重传对应五元组仍然处于LAST-ACK状态时,建立连接会失败。因此,更推荐您使用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范围的起始值小。

    例如本示例中,ipv4.ip_local_port_range的范围是32768~61000,需修改tcp_max_tw_buckets的值小于32768,示例如下:

    sysctl -w net.ipv4.tcp_max_tw_buckets=10000

注意事项

由于tcp_tw_recycle已在Linux 4.12上被弃用,请忽略所有修改tcp_tw_recycle和tcp_tw_reuse的方案,这些方案对于使用了NAT或LVS的服务均不适用。

适用于