EC2のマイクロなインスタンスタイプでホストしているWEBサーバーに同時並列リクエストでワークロード負荷を与えると、DBやセッションストアのmemcachedへのTCP接続が稀に失敗する事象に遭遇し、手間取った
-
MySQL / No such file or directory
TCP/IP接続なんだが、UNIXドメインソケットが見つからない系のエラー? - memcached / can not to connect memcached
切り分け調査
- ワークロード
- EC2インスタンスのロードアベレージは余裕で1未満
- EC2のネットワーク帯域は余裕
- コネクション数、パケットロストなどRDS, Elasticacheのメトリクスに異常が見られない
- どこかで蹴られている
- 一応Route53のプライベートホストゾーンから、エンドポイント直に変更してみるが状況変わらず
- VPCのDNSスロットリング制限で蹴られている?いやそこまでいじめてない
Amazon が提供する DNS サーバーは、Elastic Network Interface ごとに 1 秒あたり 1024 パケットの制限を適用します。Amazon が提供する DNS サーバーは、この制限を超えたトラフィックをすべて拒否します。
VPC DNS スロットリングが原因で、Amazon が提供する DNS サーバーへの DNS クエリが失敗しているかどうかを確認するにはどうすればよいですか?
ここまで遠回りして、フレームワークのセッションアダプタからphpネイティブに変更するも失敗するが、きれいに{ホスト}:{ポート}が歯抜けのエラーログが出た
PHP Warning: session_start(): Failed to parse session.save_path (error at offset 0, url was 'tcp://:')
DotEnv
apache mpm_event_module
×スレッドセーフmod_php
な環境で接続コンフィグにDotEnvにImmutableで.envファイルをローディングさせて$_ENV
スーパーグローバルで参照していた
$dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->load();
DotEnvをcreateImmutable
で起動するとputenv/getenvがスレッドセーフではないため、次の順序で並列リクエストの環境変数がタイミングによってクリーンアップされたようだ。
1 番目のリクエスト: 変数が存在しない -> ロード
2 番目のリクエスト: 変数が存在する -> ロードしない
1 番目のリクエスト: 終了、変数をクリーンアップする
2 番目のリクエスト: 変数を使用する -> 変数はもう存在しない、によってクリーンアップされる1回目のリクエスト
https://github.com/vlucas/phpdotenv/issues/248
When you have two or more sites on one server, the sites's .env will affect each other · Issue #219 · vlucas/phpdotenv
Using getenv() and putenv() is strongly discouraged due to the fact that these functions are not thread safe, however it is still possible to instruct PHP dotenv to use these functions. Instead of calling Dotenv::createImmutable, one can call Dotenv::createUnsafeImmutable, which will add the PutenvAdapter behind the scenes. Your environment variables will now be available using the getenv method, as well as the super-globals:
公式にもスレッドセーフでない旨ため注意書きがあった
Immutableモードは定義済みの環境変数のローディングは無視され(2)、リクエストの終了とともに破棄される(4)
一方でMutableモードはリクエストごとに独立したストアに確保するとみえて、スレッド競合の問題は起きなくなった
※createUnsafeImmutable
でv5系の実装で、v4系には存在しなかったのでMutable
で検証
$dotenv = Dotenv::createMutable(__DIR__);
$dotenv->load();