XAMPP 環境にて作業を行っていたところ、MySQL 接続がやたらと遅く辟易したため、原因を調査してみた。 少々ハマってしまったので、ここに書いておきます。誰かの役に立てば幸いだ。
ことの発端
現象
現象としては、PHP から MySQL への接続に1秒以上かかるというもの。 ソースコードは下記のたった1行のみ。
mysqli_connect('localhost', 'user', 'password', 'dbname');
ごらんの通り、ただ MySQL に接続するだけのコードである。 たったこれだけで1秒以上かかってしまう。どう考えても遅すぎる。 ちなみに正常な場合は、遅くても 0.01 秒ほど。 空いた口が塞がらなくて顎が外れそうだ。
環境
調査して判明したことだが、この問題はかなり特殊な環境依存問題なので、ここにバージョンを記しておく。 結論からいえば、この問題は Windows Vista/7 + PHP + MySQL という組み合わせ、 つまりは Windows Vista/7 上の XAMPP 環境で発生する。
OS | Windows 7 64bit |
---|---|
XAMPP | 1.8.0 |
PHP | 5.4.4 |
MySQL | 5.5.25a |
原因
判明した原因は下記の通り。
Windows Vista/7 では、 localhost の名前解決に DNS が使われるようになった
hosts ファイルにはこう書いてあり、localhost の記述はコメントアウトされている。
# localhost name resolution is handled within DNS itself. # 127.0.0.1 localhost # ::1 localhost
Windows Vista/7 では、localhost の名前解決は DNS によって行われるようになっているよう(デフォルトの hosts ファイルでは)。 これはどうも Windows Vista/7 時代からのようで、XP 時代では無かったことのようです。 IPv4 か IPv6 のどちらかのコメントアウトを外すことで、外した方を使用することが可能なりますが、 両方ともコメントアウトされていると、IPv6 の方が優先され、ダメなら IPv4 でというような動作となっているようです。
理由は、現在は IPv4 と IPv6 の過渡期なので同時稼働ということになってはいますが、 将来的には IPv4 は無効化されるということが強く想定されているためとのこと。 IPv4 が無効な状態のときに、IPv4 のアドレスに解決されてしまうと困るので、 DNS で解決するようにして切り替えられるようにということらしい。
IPv4 アドレス | IPv6 アドレス | 動作 |
---|---|---|
両方ともコメントアウト(もしくは両方とも有効?) | DNS によって IPv6 と IPv4 を動的に解決 | |
有効 | 無効(コメントアウト) | hosts ファイルに従って IPv4 アドレスを使用 |
無効(コメントアウト) | 有効 | hosts ファイルに従って IPv6 アドレスを使用 |
ここで注目なのは、両方ともコメントアウト状態だと、DNS が使われるということです。
DBサーバーへの接続にも名前解決が必要
IP 上で動作している以上は当たり前なのかもですが、 Web サーバーから DB サーバーへの接続の際に、接続先の DB サーバーをホスト名で指定した場合、 そのホスト名を名前解決する必要があります。
そして今回の原因はまさにその接続先のホスト名に "localhost" と指定することによって、 DNS によって名前解決される必要性が発生し、その結果、処理の遅延が発生したと考えられます。
試しに、接続先のホスト名に "127.0.0.1" と指定した場合には、名前解決をする必要が無いため処理の遅延は発生しません。 また、接続先のホスト名を "localhost" と指定したままの状態で、hosts ファイルの IPv4 のコメントアウトを外した場合も、 DNS が使用されないため、処理の遅延は発生しません。
まとめ
再現方法
- 1. OS が Windows Vista/7 である。
- 2. hosts ファイルの "localhost" の指定が IPv4、IPv6 共にコメントアウトされている。
- 3. PHPからMySQLへの接続先のホスト名に "127.0.0.1" ではなく "localhost" と指定している。
上記の条件が全て満たされた場合に、この現象は再現します。
解決方法
ということは、上記のいずれかの条件を満たさないようにすれば良いわけです。 1 は OS を変えなければならないのでそう簡単ではなく、 2 は IPv4 のコメントアウトを外せば解決しますが、IPv6 を外すと今度は繋がらなくなります。 問題の局所性を考えればあまりお勧めしません(この変更はシステム全体に影響するので)。 ということで 3 をなんとかするのが一番簡単な解決方法かと。
つまり...
// これを mysqli_connect('localhost', 'user', 'password', 'dbname'); // こう変更すれば良い... mysqli_connect('127.0.0.1', 'user', 'password', 'dbname');
ナ ナンダッテー!!
Ω ΩΩ
補足
my.cnf で skip-name-resolve を有効にするという方法もあるようです。
参考サイト
関連記事
記事検索
アーカイブ
2021
-
XAMPPでメールをテキストファイルに保存する方法(04/02)
NEW
-
Windows サンドボックス(その2:構成ファイル)(03/29)
NEW
-
Windows サンドボックス(03/28)
NEW
-
Composer 再入門(その4:便利コマンド)(03/21)
NEW
-
Composer 再入門(その3:オートローダーの最適化)(03/20)
NEW
-
Composer 再入門(その2:スクリプト)(03/19)
NEW
-
Composer 再入門(03/18)
NEW
2019
-
XAMPP に Redis をインストールする方法(01/20)
2018
-
セマンティック バージョニング(04/05)
-
Node.js と npm 再入門(その4:便利コマンド)(03/30)
-
Node.js と npm 再入門(その3:npm-scripts)(03/30)
-
Node.js と npm 再入門(その2:パッケージの更新)(03/29)
2017
-
Node.js と npm 再入門(12/24)
2016
2015
2014
-
Ajaxでポップアップブロックを回避する方法(01/06)
2013
-
JavaScriptファイルに動的にパラメータを渡す方法(11/24)
2012
-
XAMPPでMySQL接続がやたらと遅い件(09/26)