yasutomogのブログ

作業の備忘録としてリンクと一緒に簡単な説明を残す

App Service(Microsoft Azure)とAzure SQL DatabaseのReconfiguration対応

概要

  • Azure環境でシステム開発している中で、Reconfigurationという現象に遭遇したので、その時の対応についてまとめる

Reconfigurationについて

  • Azure SQL Databaseには、サービスの仕様としてReconfigurationというものがある
  • Reconfigurationが発生すると、数秒〜数十秒の間、DB接続ができなくなる
  • Reconfigurationは、不定期で発生する(現状だと1ヶ月に2、3度)
  • Reconfigurationそのものは、安定したDBの稼働のために必要なものらしい
  • Azure SQL Databaseを使用するには、Reconfigurationが発生することを前提で開発する必要がある

[SQL Database] Reconfiguration (リコンフィグレーション) は悪ではない。 – Microsoft SQL Server Japan Support Team Blog

環境

本番環境

開発環境

Microsoftの公式ドキュメントの対処方法

  • Microsoftの公式ドキュメントでは、Reconfgiuration発生を検知し、wait後にリトライを実装する流れを推奨。
  • Reconfiguration発生時に使用した接続は使用できないため、改めて接続し直す必要がある。

[SQL Database] アプリケーション作成における推奨事項について (Microsoft Azure SQL Database) – Microsoft SQL Server Japan Support Team Blog

テスト方法

  • 基本的には、Reconfigurationは不定期に発生するが、意図的に発生させることも可能。
  • Azure SQL Databaseのプランを変更することで、プランが切り替わる間の数秒間だけReconfigurationが発生。
  • Azure Portal上からプラン変更して、SQL実行を連続して実行することでテスト可能。

ハマるポイント

Reconfigurationの判断

  • 本番でDB接続エラーが発生したときに、それがReconfigurationによるものなのかは現在MSサポートに問い合わせる必要がある。 以前までは、sys_event.logに出力されていたらしいが、現在は出力されない。

V12 の Azure SQL Database の sys.event_log に reconfiguration が記録されない (Document Version 1.0) – Microsoft SQL Server Japan Support Team Blog

  • Microsoft公式ドキュメントでは、Reconfiguration発生の判断をSQLのERRCODEで制御する方法を記載しているが、コネクションプーリングが有効になっていると古いコネクションを使用することでERRCODEに値が入らないことがある、そのときには、SQLSTATEしか入っていないため、そちらで判断する。(これはPHP以外の言語では大丈夫かも。ドライバの問題な気がする。)

リトライ処理をしても同様の接続エラーが発生

  • Lumenでは、リクエスト単位でPDOをキャッシュする機構がある
  • Lumenの機構を改修して、Recofiguration発生時にのみ、PDOを再生成して失敗したSQL実行という流れを単純に作って対応したが、 Reconfiguration発生時と同様の接続エラーが発生
    • Azure App Service(Windowsサーバ)上では、コネクションプーリングがデフォルトで有効になっている
    • Linux環境では、コネクションプーリングの設定はデフォルト無効となっている(開発環境はCentOSだったため、本番のみ再現することでハマる、、)
  • PDOを再生成しても内部ではReconfiguration発生時のプールを使用しているため、エラーが発生する

App Serviceのコネクションプーリングの制御

  • App Serviceのプラン(サーバスペック)によって、プールの最大数などが決まる仕様になっている
  • PHPからプールを破棄するAPIなどは用意されていない
  • PHPからアクティブなプール数を取得するAPIなどは用意されていない
  • コネクションプーリングを無効化すると、その都度確実に接続しにいくため、エラーが発生し続けることはない
    • 但し、遅くなる。

最終的な対応方法

  • 基本方針として、コネクションプーリングを一律無効化するのは、パフォーマンスの観点からNGなため、デフォルトはプールを有効化
  • 現状は対応1でも問題なく動いているため、様子見。これでも駄目な場合、別途キューのプロセス管理が必要になるが、対応2を検討

対応1

  • Reconfigurationを検知したときに、wait後、コネクションプーリングを無効化したPDOを生成し失敗時のSQLを再実行

対応2

  • Reconfigurationを検知したときに、システム全体でコネクションプールを無効化するように制御(PDO生成周りの処理改修)
  • キューに90秒後コネクションプールを有効化する処理を追加(プールの生存期間が60秒なため、若干の余裕を持たせる)