公開:2025年6月5日

10分で読めます

GitLabリポジトリのバックアップを48時間から41分に短縮した方法

15年前のGit関数のパフォーマンス上のボトルネックを追跡して修正し、効率性の向上、より強固なバックアップ戦略の導入、リスクの軽減を実現した方法をご紹介します。

リポジトリのバックアップは、いかなる堅牢なディザスタリカバリ戦略においても不可欠な要素です。しかし、リポジトリのサイズが大きくなるにつれて、信頼性の高いバックアップの作成プロセスはますます難しくなります。GitLabでは、Railsリポジトリのバックアップに48時間かかっていました。そのため、バックアップ頻度かシステムパフォーマンスのどちらを優先するかを選ばないといけないという難しい状況にありました。お客様のため、そして社内ユーザーのためにこの問題に取り組むことにしました。

最終的に、15年前に作成したGit関数でO(N²)レベルの複雑なアルゴリズムが使われていたのがこの問題の原因であることを突き止め、アルゴリズムを変更して修正したところ、__バックアップ時間が大幅に短縮__されました。その結果、コストの削減、リスクの軽減とともに、コードベースに合わせて実際にスケールするバックアップ戦略を実施できるようになりました。

これは、大規模なリポジトリのユーザーなら誰にでも起こりうるGitのスケーラビリティの問題であることが判明しました。この問題をどのように追跡して修正したかをご説明します。

大規模なバックアップ

まずは、問題について詳しく見ていきましょう。組織においてリポジトリのサイズが大きくなり、バックアップが複雑化するにつれて、以下のような課題が生じる可能性があります。

  • 時間がかかるバックアップ:非常にサイズの大きいリポジトリを使用している場合、バックアップの作成に数時間かかる可能性があるため、定期的なバックアップを行うのが難しくなりがちです。
  • リソースの集中:長時間のバックアップ処理には大量のサーバーリソースが必要となることがあるため、他のオペレーションに影響を及ぼす可能性があります。
  • バックアップの実施期間:24時間体制で業務を行っているチームにとって、このような長時間の処理を行える適切なメンテナンス期間を確保するのは難しい場合があります。
  • 失敗するリスクの増大:バックアップ処理に長時間かかると、ネットワークの問題、サーバーの再起動、システムエラーなどによる中断の影響を受けやすくなります。そのため、場合によっては長時間かかるバックアップ処理を最初からやり直さざるを得なくなります。
  • 競合状態:バックアップの作成に時間がかかるため、その間にリポジトリが大きく変更される可能性があります。結果として、使用できないバックアップが作成されたり、オブジェクトにアクセスできなくなってバックアップ処理が中断されたりすることがあります。

このような課題によって、バックアップの頻度や完全性を妥協せざるを得なくなる可能性があります。しかしながら、データ保護という観点では妥協すべきではありません。バックアップの実施期間が長くなると、顧客は回避策を取らざるを得なくなることがあります。その場合、外部ツールの導入やバックアップ頻度の削減などが行われますが、結果として、組織全体で一貫したデータ保護戦略を維持できなくなる可能性があります。

では、GitLabがどのような方法でパフォーマンス上のボトルネックを特定し、解決策を見つけ、バックアップ時間を短縮するためにどのように導入したかを詳しく見ていきましょう。

技術的な課題

GitLabのリポジトリバックアップ機能では、git bundle createコマンドを使用しています。このコマンドは、ブランチやタグのようなすべてのオブジェクトと参照を含むリポジトリの完全なスナップショットをキャプチャします。このバンドルは、リポジトリを正確な状態で再作成するための復元ポイントとして機能します。

しかしながら、このコマンドの実装には参照数に関連するスケーラビリティの低さの問題があり、パフォーマンス上のボトルネックとなっていました。リポジトリ内の参照数が増えるにつれて、処理時間が飛躍的に増加していました。当社の一番大きなリポジトリでは数百万個の参照が含まれますが、バックアップ処理に48時間以上かかることもありました。

根本原因分析

そこで、このパフォーマンス上のボトルネックの根本原因を特定するために、実行中のコマンドのフレームグラフを分析しました。

実行中のコマンドが示されたフレームグラフ

フレームグラフは、スタックトレースを使用してコマンドの実行パスを表示します。各バーはコード内の関数に対応しており、バーの幅はその特定の関数内でコマンドの実行に費やされた時間を示します。

10,000個の参照が含まれるリポジトリで実行されたgit bundle createコマンドのフレームグラフを調べたところ、実行時間の約80%がobject_array_remove_duplicates()関数に費やされていました。この関数は、コミットb2a6d1c686(バンドル:同じ参照を複数回指定できるように許可、2009年1月17日)でGitに導入されたものです。

この変更内容を理解するには、git bundle createを使用すると、バンドルに含める参照を指定できることを把握する必要があります。完全なリポジトリバンドルの場合、--allフラグを指定するとすべての参照がパッケージ化されます。

このコミットは、ユーザーがコマンドラインから重複した参照を指定(例:git bundle create main.bundle main main)すると、重複したmain参照を適切に処理せずにバンドルが作成されてしまうという問題に対処したものでした。Gitリポジトリでこのバンドルをアンバンドルすると、同じ参照を二度書き込もうとするため、壊れてしまいます。そのため、重複回避を目的として、すべての参照で重複の特定処理が繰り返されるようにネストされたforループを用いたコードが実装されました。このようなO(N²)アルゴリズムは、参照数が多いリポジトリではパフォーマンス上の重大なボトルネックとなり、かなりの処理時間がかかっていました。

修正方法:O(N²)アルゴリズムを効率的なマッピングに置き換える

GitLabは、明らかになったパフォーマンスの問題を解決するために、ネストされたループをマップデータ構造に置き換えるアップストリーム修正をGitにコントリビュートしました。これにより、各参照がマップに追加され、各参照の単一のコピーのみが処理目的で自動的に保持されるようになりました。

この変更により、git bundle createのパフォーマンスが劇的に向上し、参照数の多いリポジトリのスケーラビリティが大幅に改善されました。10,000個の参照があるリポジトリでベンチマークテストを行った結果、パフォーマンスが6倍向上することが明らかになりました。

Benchmark 1: bundle (refcount = 100000, revision = master)
  Time (mean ± σ): 	14.653 s ±  0.203 s	[User: 13.940 s, System: 0.762 s]
  Range (min … max):   14.237 s … 14.920 s	10 runs

Benchmark 2: bundle (refcount = 100000, revision = HEAD)
  Time (mean ± σ):  	2.394 s ±  0.023 s	[User: 1.684 s, System: 0.798 s]
  Range (min … max):	2.364 s …  2.425 s	10 runs

Summary
  bundle (refcount = 100000, revision = HEAD) ran
	6.12 ± 0.10 times faster than bundle (refcount = 100000, revision = master)

パッチは承認され、アップストリームのGitにマージされました。GitLabでは、次のGitバージョンがリリースされる前にお客様がすぐに恩恵を受けられるように、この修正をバックポートしました。

結果:バックアップ時間の大幅な短縮に成功

この改善によるパフォーマンスの向上は、まさにこれまでの状況を一変させるものでした。

  • バックアップ時間が48時間から41分に短縮:GitLab最大のリポジトリ(gitlab-org/gitlab)のバックアップを従来のわずか1.4%の時間で作成できるようになりました。
  • 一貫したパフォーマンスの維持:この修正はリポジトリのサイズに関係なく機能し、安定してスケールします。
  • 効率的なリソースの利用:バックアップ処理中のサーバー負荷が大幅に軽減されました。
  • 幅広い適用性:もっとも劇的な改善が見られるのはバックアップの作成ですが、多数の参照を処理するすべてのバンドルベースの操作においてメリットがあります。

GitLabを利用するお客様にとってのメリット

GitLabを利用する組織は、この改善によって、リポジトリのバックアップとディザスタリカバリ計画方法に関して、即座に次のような具体的なメリットを得られます。

  • バックアップ戦略の変革
    • 企業チームは、開発ワークフローに影響を与えたり、長期にわたるバックアップ期間を確保したりすることなく、夜間に実施する完全バックアップのスケジュールを確立できます。
    • 長期のバックアップ専用の時間を設けなくとも、夜間スケジュール中にバックグラウンドでシームレスに実行できます。
  • 事業継続性の向上
    • バックアップ時間が数日から数分に短縮されたことで、組織は回復ポイント目標(RPO)を大幅に最小化できます。これはビジネスリスクの軽減につながります。災害が発生した場合でも、数日かからず、数時間の作業で復旧できる可能性があります。
  • 運用負荷の軽減
    • サーバーリソースの消費を抑えられ、メンテナンス期間が短縮されます。
    • バックアップ時間が短縮されるため、コンピューティングコストも削減します。特に処理時間が延びると、コストの増加に直結するクラウド環境においては顕著です。
  • 将来にわたって活用できるインフラストラクチャ
    • リポジトリの規模が大きくなっても、バックアップ頻度とシステムパフォーマンスのどちらを優先するか選ぶ必要はもうありません。
    • コードベースの拡大にあわせて、バックアップ戦略もシームレスに拡張できます。

組織は、パフォーマンスや完全性を犠牲にしなくても、より堅牢なバックアップ戦略を実施できるようになりました。以前は難しいトレードオフに直面していたものの、今では簡単な方法で運用できます。

GitLab 18.0のリリース以降、ライセンスプランに関係なく、GitLabをご利用のお客様は全員、ご紹介した改善点を利用してバックアップ戦略の立案および実施を行えるようになりました。設定を変更する必要はもうありません。

今後の展望

今回の革新的な改善は、スケーラブルでエンタープライズグレードなGitインフラの提供に向けた、当社の継続的な取り組みの一環です。バックアップの作成時間が48時間から41分に短縮されたことは重要なマイルストーンとなりましたが、引き続きスタック全体においてパフォーマンス上のボトルネックを特定し、対処しています。

今回の改善をGitのアップストリームプロジェクトにコントリビュートでき、GitLabユーザーだけでなく、広範なGitコミュニティにメリットをもたらせたことを特に誇りに思っています。このような協調的なアプローチにより、改善に対する徹底的なレビューおよび幅広いテストの実施が行われ、誰もがそのメリットを得られるようになります。

GitLabではパフォーマンスを最適化するために、このような深いレベルでインフラに取り組んでいます。ぜひGitLab 18のオンラインリリースイベントにご参加ください。ほかにどのような根本的な機能強化が行われたかをご紹介します。今すぐご登録ください!

ご意見をお寄せください

このブログ記事を楽しんでいただけましたか?ご質問やフィードバックがあればお知らせください。GitLabコミュニティフォーラムで新しいトピックを作成してあなたの声を届けましょう。
Share your feedback

フォーチュン100企業の50%以上がGitLabを信頼

より優れたソフトウェアをより速く提供

インテリジェントなDevSecOpsプラットフォームで

チームの可能性を広げましょう。