GitHubはこの2月、同サービスに8時間以上の影響を与えた、複数回に及ぶサービス中断の原因に関する内部調査の完了を発表した。根本的な原因は、予期していなかったデータベースの負荷変動と、データベースの設定上の問題にあった。
インシデントはすべて、GitHubのメインデータベースクラスタであるmysql1
に影響するものであった。このデータベースはGitHubにとって、かつては唯一のMySQLクラスタだったものだ。
時間の経過とともに、mysql1は大規模で高負荷になったため、テーブルを機能的にグループ分けして新たなクラスタ群に分割すると同時に、新機能用にも新たなクラスタを用意しました。それでもコアデータセットの大部分は、依然としてオリジナルのクラスタ内に残っていたのです。
最初のインシデントは、GitHubのエンジニアが不注意から、リソースを大量に消費するクエリを読み取り専用のレプリカではなく、データベースマスタに送信してしまったことで発生した。この結果として、接続プールを管理するProxySQLが過負荷になり、クエリ処理の一貫性が失われ始めた。
同様の問題が2日後、潜在的な問題を調査する目的で実施されたマスタデータベースの計画的な拡張作業において、作業中にマスタが一時的に読み込み専用になったことが原因で発生した。この時も同じように予想外の負荷が発生し、同様にProxySQLがフェールしている。
どちらのケースも、ロードを削減すれば、障害を解消するには十分だった。
さらに重大だったのは3回目のインシデントで、2時間にわたって発生した。このケースでは、またもProxySQLが障害点となった。アクティブなデータベース接続数が所定のしきい値を越えたことが原因だった。
このケースでの大きな問題は、復旧作業を行った後も、アクティブなコネクションが臨界しきい値を越えたままだったことだ。このためシステムは縮退状態に陥ることになった。ProxySQLが不適切に設定されていたことと、クラッシュによる影響から、システム全体とプロセスローカルのディスクリプタの最大値を設定するLimitNOFILE
が65536
にダウングレードされたのだ。
第4の障害は、GitHubアプリケーションのロジック変更が原因で発生した。この変更がクエリを生成し、mysql1
マスタの負荷が急激に上昇したため、依存するサービスすべてに影響を与えることになった。
GitHubの技術者によると、いずれの障害も根本原因さえ判明すれば簡単に修正できたのだが、システム間のインタラクションはいつも即座に理解できるとは限らない。結果として同社では、最初に改善すべき最重要領域を可観測性とし、続いて、より完全なシステム統合と、プロダクション展開前のパフォーマンステストに置くことにした。
しかしながら、問題の核心に進むためには、mysql1
クラスタマスタのロードを低減するためにデータパーティションを改善する必要がある、とGitHubのエンジニアたちは考えている。このことは、ゼロダウンタイムの要件を満足する上で有効であるとともに、将来的なインシデント発生時にユーザへの影響を低減することも可能になる。
特に作業の対象となったのは、ablities
というテーブルだった。このテーブルはすべての認証要求で使用されるため、パフォーマンスの中心となっているのだ。2ヶ月間の作業を経て、それまではシステム内の他のテーブルから独立(読み取り、JOIN
不要)する必要のあったabilities
テーブルが、現在では独自のクラスタ内で実行されるようになった。この変更のみでmysql1
クラスタマスタのロードを20パーセント低減することができた、とGitHubのエンジニアは語っている。
データベースのパーティション化作業はまだ継続中で、mysql1
クラスタの書き込み負荷の60パーセント低減と、12のスキーマドメインの外部への移動を次の目標としている。その他にも改善に向けた数多くの取り組みが、GitHubのエンジニアたちによって立ち上げられている。具体的には、データがレプリカから取得可能である場合のマスタ読み込み回数の低減、問題を確認したコード変更を無効にするための機能フラグの導入、GitHub内部のダッシュボード改善によるデプロイメント上の問題の識別性向上、水平拡張性を改善するためのシャーディングの使用、などだ。