はじめに
最近、PHP 8.2.18とMySQL 8.0.36を使用したアプリケーションで「Packets out of order. Expected 1 received 0.」というエラーに遭遇しました。
このエラーの詳細とその対処法について記します。
環境
- PHPバージョン: 8.2.18
- MySQLバージョン: 8.0.36
- サーバー設定: php-fpm
エラー発生時の状況
エラーが発生したのは、アプリケーションへのアクセスが一定期間途切れた以下のような状況。
1. 前日の夕方までアプリにアクセス。
2. 翌日朝、アプリにアクセスすると「Packets out of order. Expected 1 received 0.」のエラー。
3. その後、何度かアクセスを試みると正常にアクセスできるように。
エラーの内容
おそらくphp-fpmが古い接続を保持している一方で、MySQLサーバー側でその接続がタイムアウトにより切断されることで発生。
以下流れ
- php-fpmに古い接続が保持: 前日のアクセスで確立された接続がphp-fpmに保持される。
- MySQLの接続タイムアウト: 長時間アクセスがない場合、MySQL側で接続がタイムアウトされる(デフォルトでは8時間)。
- 翌日のアクセス時にエラー: 朝に再度アクセスすると、php-fpmが保持している古い接続を使用しようとするためエラーが発生。
- 新しい接続の確立: しばらくすると新しい接続が確立され、エラーが解消。
対処法
php-fpmのrequest_terminate_timeoutの設定を調整する
/etc/php-fpm.d/www.conf
ファイル内のrequest_terminate_timeout
の値を、MySQLのwait_timeout
の値よりも短く設定する。
例えば、wait_timeout
がデフォルトで8時間である場合、request_terminate_timeout
を6時間に設定することで、php-fpmが古い接続を保持し続けることを防げる。
設定例
# /etc/php-fpm.d/www.conf request_terminate_timeout = 21600s # 6時間
その他の対処法
その他、以下のようなやり方でも対処可能。
- 永続接続の使用を避ける: 永続接続 (PDO::ATTR_PERSISTENT) を無効にすることで、永続接続を使用しない。
- 接続の再試行: エラーが発生した場合に、接続を再試行するように実装を変更
- 設定の調整: MySQLサーバーの設定で、wait_timeoutやinteractive_timeoutの値を可能な範囲で伸ばす。
まとめ
まだ修正が入っていないようなので、今現在では上記のようなやり方でエラー対処する必要がありそうです。
参考リンク:
– PHP Bug #81335
– GitHub Pull Request #13618