APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

【AP Tech Blog Week】ChatGPTを使った不具合原因と対策の分析

本記事はAP Tech Blog Week Vol.3のものになります。

始めに

こんにちは、クラウド事業部の藤江です。 Chat GPTを用いて過去に遭遇した不具合の原因と対策の分析を実施した結果を記します。

今回分析する不具合の内容

動作環境や不具合の詳細な内容については記載せず概要のみ記します。

動作環境

不具合が発生したシステムの概要図は下図の通りです。不具合に関係しない部分については省略して記載しています。CentOS7上で複数のTCP/IPサーバプログラムとクライアントプログラムが動作する環境で発生しました。

システム構成図

不具合の内容

TCP/IPサーバプログラムが稀に起動に失敗する事象が発生しました。サーバプログラムがすべて正常起動する場合もあれば、1つもしくは複数のサーバプログラムが起動しない事象がランダムに発生しました。

不具合の原因

サーバプログラムの起動に失敗する原因はポートの競合が原因で発生しました。ただし、TCP/IPサーバプログラム同士でポートが競合したわけではなく、クライアントプログラムとサーバプログラムでポートの競合して発生しました。不具合が発生したケースではサーバ側が使用するポートがクライアントプログラムが通信時に使用するエフェメラルポート領域にある35000〜36000の間のポートを使用していたためです。サーバプログラム実行時にクライアントプログラムに35000〜36000のポートを使用されることを考慮していない結果、不具合が発生しました。

当時の不具合の対策方法

net.ipv4.ip_local_port_rangeの設定を変更し、エフェメラルポート範囲の指定を36001~60999に変更することで対応しました。

分析方法

今回は簡単な質問を行った場合と詳細内容を記して質問を行った場合の2パターンで実施します。必要に応じてChatGPTの回答に対して深堀を行い、良い回答を引き出せるか試してみます。

分析結果

簡単な質問を行った場合の結果

単純にTCP/IPサーバプログラムが起動に失敗した原因について質問してみます。

質問

あなたはLinuxOSとネットワークの知識が豊富なシステムエンジニアです。TCP/IPサーバプログラムが起動に失敗した原因について教えて下さい。

回答

TCP/IPサーバプログラムが起動に失敗する原因として考えられる事項と、それぞれの解決策について詳しく説明します。

1. ポートの競合
原因: 既に別のプロセスが同じポートを使用している場合、サーバはそのポートをバインドできません。

対策:

現在使用中のポートを確認するためには以下のコマンドを使用します。

sudo netstat -tuln | grep LISTEN

2. 権限の問題
原因: プログラムが必要なポートを開く権限がない(特に1024以下のポート)。
対処法: 管理者権限でプログラムを実行するか、1024以上のポートを使用する。

3. 設定ファイルの誤り
原因: 設定ファイルに誤りがある(例:IPアドレス、ポート番号、ファイルパスなど)。
対処法: 設定ファイルを再確認し、正しい形式と値が設定されているか確認する。

4. ネットワークインターフェースの問題
原因: ネットワークインターフェースが正しく設定されていないか、無効になっている。
対処法: ネットワークインターフェースの状態を確認し、有効化する。
## 以下、長くなるため省略

原因として最初に挙がってきたのはポートの競合が上がってきました。実行権限等やネットワークインターフェースの問題も上がっていましたが質問時にTCP/IPサーバプログラムと指定した結果、ポートの競合の方が可能性が高いとChatGPTは判断したと思われます。試しに質問内容を変えて「プログラムが起動に失敗した原因について教えて下さい。」と聞いてみると依存関係の問題等、別の原因を上げてきました。

詳細内容を記して質問を行った場合の結果

質問時に制限をかけないと回答が長くなるため、可能性が高い3つの原因だけ上げるように質問します。

質問1

あなたはLinuxOSとネットワークの知識が豊富なシステムエンジニアです。
下記に記す不具合の考えられる原因について、発生する可能性が高い3つの原因を教えて下さい。

## 不具合の内容

- TCP/IP通信を行うサーバプログラムが複数起動する環境で、サーバプログラムがランダムに起動が失敗する事象が発生した。
- 動作環境はcentos7で複数のTCP/IPのサーバプログラムと、外部のサーバに接続するTCP/IPクライアントアプリで構成されている。
- サーバプログラムのリッスンポートは設定ファイルで変更することができ、実行中のサーバプログラムのポートはすべて異なるポートが指定されている。
- サーバプログラムはすべて同一のバイナリイメージを使って起動している。
- サーバプログラムのリッスンポートは35000〜36000の間のポートを利用している。
- ファイアウォールが停止状態でもサーバプログラムが起動しない場合があった。
- サーバプログラムはクライアントから接続されると、常時接続を維持し、基本的にサーバから切断することはない。
- クライアントプログラムは接続を維持するプログラムと、データ送受信後に切断するプログラムの2種類が存在する。

回答1

この不具合の発生原因として考えられる主な要因は以下の3つです。

1. ポートの競合
複数のサーバプログラムが同時に起動しようとする際に、設定ファイルで指定されたリッスンポートが競合している可能性があります。
特定のポートが既に他のプロセスによって使用されている場合、新たに起動しようとするサーバプログラムはポートをバインドできずに失敗します。
この競合は、システムのリソース管理や起動タイミングの問題で発生することがあります。

2. ファイルディスクリプタの枯渇
サーバプログラムが多数のクライアントと接続を維持する場合、使用するファイルディスクリプタの数が増加します。
CentOS 7では、デフォルトのファイルディスクリプタの上限が設定されており、この上限に達すると新たな接続やポートのバインドができなくなります。
ulimitコマンドやシステム設定を確認し、必要に応じてファイルディスクリプタの上限を引き上げることが必要です。

3. システムリソースの不足
サーバプログラムの同時起動や多数のクライアント接続により、システムのCPUやメモリなどのリソースが枯渇している可能性があります。
特に、サーバプログラムがリソースを大量に消費する場合や、システム全体の負荷が高い場合にこの問題が発生します。
topやvmstatコマンドを使用してシステムリソースの使用状況を監視し、リソースの不足がないか確認することが必要です。

これらの原因を調査するためには、システムログの確認やリソース使用状況のモニタリング、ポートの使用状況のチェックを行うことが重要です。
また、起動スクリプトや設定ファイルの内容を再確認し、必要に応じて調整を行うことも検討してください。

詳細内容を記して質問の回答結果もポートの競合が最も可能性として高い要因として挙がってきました。 詳細事項を記載した結果より具体的な原因が回答として返ってきました。

回答内容について深堀するため追加で質問をしてみます。

質問2

TCP/IPサーバプログラム同士で受信ポートの競合はありませんでした。
TCP/IPサーバプログラムとクライアントプログラムでポートが競合する可能性はありますか。

回答2

TCP/IPサーバプログラムとクライアントプログラムでポートが競合する可能性は低いですが、
いくつかの特殊な状況で発生する可能性があります。以下の点を確認することをお勧めします:

1. Ephemeral Portsの使用
クライアントプログラムが外部サーバに接続する際に使用するエフェメラルポート(動的ポート)が、
サーバプログラムのリッスンポートと競合する可能性があります。
エフェメラルポートは通常、システムによって動的に割り当てられる範囲内にあり、CentOS 7ではデフォルトで32768〜61000の範囲です。
この範囲にサーバプログラムのリッスンポート(35000〜36000)が含まれているため、競合が発生する可能性があります。

1. クライアントのポート指定
クライアントプログラムが特定のポートを使用するように設定されている場合、
そのポートがサーバプログラムのリッスンポートと競合する可能性があります。
通常、クライアントはランダムなエフェメラルポートを使用しますが、特定のポートを指定している場合には注意が必要です。

1. リバインドの問題
一度使用されたポートがクライアントプログラムによって再度使用される場合、TIME_WAIT状態のためにそのポートが一時的に使用不可になることがあります。
この状態がリッスンポートと競合することは稀ですが、システム設定やプログラムの実装によっては問題を引き起こす可能性があります。

確認方法
1. エフェメラルポートの範囲確認と変更

sysctl net.ipv4.ip_local_port_rangeコマンドで現在のエフェメラルポートの範囲を確認し、必要に応じて変更します。

sysctl net.ipv4.ip_local_port_range="1024 32767"

2. 使用中のポート確認

netstat -tulnやss -tulnコマンドで現在使用中のポートを確認し、競合がないかチェックします。

netstat -tuln

または

ss -tuln

3. クライアントのポート指定確認

クライアントプログラムの設定ファイルやコードを確認し、特定のポートを使用するように設定されていないか確認します。

対策
・サーバプログラムのリッスンポートをエフェメラルポート範囲外に設定する。
・エフェメラルポートの範囲をサーバプログラムのリッスンポートと重ならないように調整する。
・クライアントプログラムが特定のポートを使用しないように設定を見直す。

これらの確認と調整により、サーバプログラムとクライアントプログラムのポート競合の可能性を低減させることができます。

質問の結果クライアントプログラムとサーバプログラムでポートが競合する可能性について回答がありました。 確認方法や対策についても追加で回答がありnet.ipv4.ip_local_port_rangeポートレンジの変更で対応できることが分かりました。

さらに追加で質問を行いnet.ipv4.ip_local_port_rangeの変更方法について確認してみます。

質問3

エフェメラルポートの変更方法について教えてください。ただし下記に記す設定の条件を満たす設定方法について教えてください。
設定の条件
- 35000〜36000の間をエフェメラルポートから除外する。

回答3

エフェメラルポートの範囲を設定する際に、特定の範囲(35000〜36000)を除外する方法は、通常の単一範囲設定では直接的に対応できません。
通常、エフェメラルポートの範囲は1つの連続した範囲として設定します。

しかし、設定の条件を満たすために、エフェメラルポートの範囲を2つの範囲に分割する方法を検討できます。
CentOSでは、/proc/sys/net/ipv4/ip_local_reserved_portsファイルを使用して特定のポートをエフェメラルポートから除外することができます。

手順
エフェメラルポート範囲の設定:
エフェメラルポート範囲を設定しますが、35000〜36000を除外するように範囲を調整します。
例えば、エフェメラルポート範囲を32768〜34999と36001〜60999に設定します。

特定のポートをエフェメラルポートから除外:
/proc/sys/net/ipv4/ip_local_reserved_portsを使用して、35000〜36000をエフェメラルポートから除外します。

コマンド例
以下の手順で設定を行います。

1. エフェメラルポート範囲の設定

# 現在のエフェメラルポート範囲の確認
cat /proc/sys/net/ipv4/ip_local_port_range

# エフェメラルポート範囲の設定 (32768-34999 と 36001-60999)
echo "32768 60999" > /proc/sys/net/ipv4/ip_local_port_range

2. 特定のポートをエフェメラルポートから除外

# 35000〜36000の範囲をエフェメラルポートから除外
echo "35000-36000" > /proc/sys/net/ipv4/ip_local_reserved_ports

# 設定を確認
cat /proc/sys/net/ipv4/ip_local_reserved_ports

これにより、エフェメラルポートの範囲は32768〜34999および36001〜60999になり、35000〜36000の範囲は除外されます。

永続化
上記の設定は再起動後に消えてしまうため、永続化する必要があります。以下の手順で設定を永続化します。

1. sysctl.confの編集

# /etc/sysctl.confファイルを編集
sudo nano /etc/sysctl.conf

# 以下の行を追加
net.ipv4.ip_local_port_range = 32768 60999
net.ipv4.ip_local_reserved_ports = 35000-36000

2. 設定の反映

# sysctl設定の反映
sudo sysctl -p

質問を深堀した結果、以前実施した不具合対策に加え一定範囲のポートレンジを除外する方法も回答を受けることができよりよい不具合対策案を知ることが出来ました。

まとめ

今回は過去に遭遇した不具合をChatGPTを使い分析してみました。簡単な質問内容でもある程度範囲を絞ることで不具合原因に近い回答をChatGPTから得ることが出来ました。また詳細な質問をした結果から得られた回答を深堀することで精度の良い回答を得ることが出来ました。ただし別の日に同様の質問をしても異なる回答が返ってくる場合もあり、回答を鵜吞みにせず回答内容のチェックが必要であると思いました。

参考