
# 使用短连接访问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}']]);
  ```
  ![](https://support.huaweicloud.com/dcs_faq/public_sys-resources/note_3.0-zh-cn.png)
  - 示例中的连接参数请根据业务实现情况修改，${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**
     
   
一般情况推荐使用方案一，对于一些特定场景（业务代码牵涉过多组件不易变更等场景），需要更快地满足高并发，可以使用方案二。
