このトピックでは、クライアントが短時間接続で Tair (Redis OSS-compatible) インスタンスにアクセスする際に発生する Cannot assign requested address エラーのソリューションについて説明します。
原因
このエラーは通常、PHP-FPM と PhpRedis を組み合わせたアーキテクチャで発生します。高コンカレンシーのシナリオでは、多数の TCP 接続が TIME-WAIT 状態になります。これにより、クライアントに新しいポートを割り当てることができなくなり、Cannot assign requested address エラーが発生します。
ソリューション
connect の代わりに pconnect を使用 (推奨)
connect の代わりに pconnect を使用すると、TCP 接続の数が減り、リクエストごとに接続が再確立されるのを防ぐため、レイテンシーが短縮されます。
次の例は、`Connect` 接続を示しています。
$redis->connect('[$Hostname]', [$Port]);
$redis->auth('[$Inst_Password]');パラメーターの説明:[$Hostname]、[$Port]、[$Inst_Password] は、それぞれ Tair (Redis OSS-compatible) インスタンスのエンドポイント、ポート番号、パスワードを示します。詳細については、「エンドポイントの表示」をご参照ください。
次のコードは、pconnect を使用してインスタンスに接続する方法の例を示しています。この方法では、短時間接続の代わりに持続的接続が確立されます。
$redis->pconnect('[$Hostname]', [$Port], 0, NULL, 0, 0, ['auth' => ['[$Inst_Password]']]);
// phpredis のバージョンが 5.3.0 以降の場合は、切断時の NOAUTH エラーを防ぐために pconnect を使用することを推奨します。
// 必要に応じて、timeout、persistent_id、retry_interval、read_timeout パラメーターの値を変更してください。クライアントをホストする Elastic Compute Service (ECS) インスタンスのカーネルパラメーター tcp_max_tw_buckets の変更
ビジネスコードに多くのコンポーネントが含まれており、変更が困難なシナリオでは、このソリューションを使用して高可用性 (HA) を迅速に実現できます。
このソリューションでは、tcp_max_tw_buckets の値を直接変更します。ただし、サーバーが 5 次元ルールを含むパケットを再送信するときに LAST-ACK 状態のままである場合、接続の確立に失敗します。したがって、pconnect ソリューションを使用することを推奨します。
クライアントがデプロイされている ECS インスタンスにログインします。
次のコマンドを実行して、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次のコマンドを実行して、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_reuse と tcp_tw_recycle の値の変更を必要とするソリューションは、NAT または Linux Virtual Server (LVS) を使用するサービスには適用できなくなりました。このようなソリューションは使用しないことを推奨します。