[解決済み] git リポジトリをデータベースのバックエンドとして使用する
質問
構造化文書データベースを扱うプロジェクトをやっています。私はカテゴリのツリー(〜1000カテゴリ、各レベルで〜50カテゴリまで)を持っており、各カテゴリは数千(最大、〜10000)の構造化されたドキュメントを含んでいます。各ドキュメントは、何らかの構造化された形式(私はYAMLを好むが、JSONまたはXMLであってもよい)の数キロバイトのデータです。
このシステムの利用者は、いくつかの種類の操作を行います。
- IDによる文書の検索
- ドキュメント内の構造化された属性の一部からドキュメントを検索する。
- 文書の編集(すなわち、追加/削除/名前変更/マージ);各編集操作は、何らかのコメントとともにトランザクションとして記録されるべきである。
- 特定の文書の変更履歴の閲覧(誰が、いつ、なぜ文書を変更したか、以前のバージョンを取得し、要求があればおそらくこのバージョンに戻すことを含む)。
もちろん、伝統的なソリューションは、この問題のためのドキュメントデータベース(例えばCouchDBまたはMongoなど)のいくつかの並べ替えを使用しているだろう - しかし、このバージョンコントロール(履歴)の事はワイルドなアイデアに私を誘惑 - なぜ私は使用すべきではありません。
git
このアプリケーションのデータベースのバックエンドとして、リポジトリを使用することはできますか?
一見すると、次のように解決できそうです。
- カテゴリ = ディレクトリ, ドキュメント = ファイル
- IDによる文書の取得 => ディレクトリの変更 + 作業コピーのファイルの読み込み
- 編集コメント付きドキュメントの編集 => 様々なユーザーによるコミットの作成 + コミットメッセージの保存
- 履歴 => 通常のgitログと古いトランザクションの取得
- 検索 => これは少し難しい部分で、定期的にカテゴリをリレーショナルデータベースにエクスポートして、検索可能なカラムのインデックスを作成する必要があると思います。
このソリューションには、他によくある落とし穴がありますか?このようなバックエンドをすでに実装しようとした人はいますか(例えば、RoR、node.js、Django、CakePHPなど、人気のあるフレームワークの場合)?このソリューションは、パフォーマンスや信頼性に影響を与える可能性がありますか?つまり、gitが従来のデータベースソリューションよりもずっと遅くなることが証明されていますか?私は、互いのリポジトリをプッシュ/プルするこのようなサーバのクラスタは、かなり堅牢で信頼できるはずだと推測しています。
基本的に、以下のことを教えてください。 もし このソリューションが機能し なぜ ということでしょうか?
解決方法は?
私自身の質問に答えることは、ベストなことではありませんが、最終的にこのアイデアを取り下げたので、私のケースでうまくいった根拠を共有したいと思います。この論理的根拠がすべてのケースに当てはまるとは限らないので、アーキテクトの判断に委ねられることを強調しておきたいと思います。
一般的に、私の質問が見逃している最初の主なポイントは、私が扱っているのは マルチユーザーシステム 私のサーバーとシンクライアント(つまりウェブブラウザだけ)を使って、並行、同時進行で作業しています。このように、私は 状態 を全てに適用します。これにはいくつかのアプローチがありますが、どれもリソースに負担がかかりすぎたり、実装が複雑すぎたりします(そのため、そもそも難しい実装をすべてgitにオフロードするという本来の目的が失われているようなものです)。
-
1ユーザー=1ステート=1リポジトリの完全な作業コピーで、サーバーがユーザーのために維持します。たとえ、かなり小さな文書データベース(例えば、100s MiBs)であっても、〜100K人のユーザーに対して完全なリポジトリクローンを維持すると、ディスク使用量が一気に増えます(つまり、100K人のユーザー×100MiB〜10TiB)。さらに悪いことに、100MiB のリポジトリを毎回クローンするには、かなり効果的な方法(つまり、git や解凍・再パッキングを使用しない)で行ったとしても、数秒の時間がかかり、これは許容できません、IMO。さらに悪いことに、メインツリーに適用したすべての編集は、すべてのユーザーのリポジトリにプルされなければなりません。
基本的に、ディスク使用量としてはO(編集数×データ数×ユーザー数)くらいになるかもしれませんし、そのようなディスク使用量は自動的にCPU使用量がかなり多くなることを意味しています。
-
アクティブユーザーのみ"アプローチ: アクティブユーザーのみの作業コピーを維持します。この方法では、一般に、ユーザーごとに完全なレポ・クローンを保存するのではなく、以下のような方法で保存します。
- ユーザーがログインすると、リポジトリのクローンを作成します。これは数秒かかり、アクティブなユーザーあたり ~100 MiB のディスクスペースが必要です。
- ユーザーがサイト上で作業を続けるときは、与えられた作業コピーで作業する。
- ユーザーがログアウトすると、彼のリポジトリクローンはブランチとしてメインリポジトリにコピーバックされ、未適用の変更のみが保存されます(もしあれば)。
この場合、ディスクの使用量はO(編集数×データ数×アクティブユーザー数)でピークに達し、通常、総ユーザー数の~100.1000分の1になりますが、ログインごとにユーザーごとのブランチを複製し、ログアウト時またはセッション終了時にこれらの変更を戻す必要があるため、ログイン/ログアウトはより複雑で遅くなります(これは取引的に行われるべきです => 別の複雑さのレイヤーを追加)。絶対的な数字としては、私の場合、10TiBsのディスク使用量を10...100GiBsに減らすことができ、それは許容範囲かもしれません。 小さい のデータベースは100MiBsです。
-
"スパースチェックアウト"アプローチ:アクティブユーザーごとに本格的なレポクローンではなく、"スパースチェックアウト"を作成しても、あまり役に立ちません。ディスクスペースの使用量を10倍程度削減できるかもしれませんが、履歴を含む操作のCPU/ディスクの負荷が高くなり、目的を達成できません。
-
ワーカープールのアプローチ:アクティブな人のために毎回本格的なクローンを作成するのではなく、すぐに使用できるようにワーカープールを保持しておくとよいでしょう。この方法では、ユーザーがログインするたびに、そのユーザーはひとつの "worker" を占有し、メインリポジトリから自分のブランチをそこに引き込み、ログアウトすると、その "worker" を解放し、賢い git ハードリセットをして再びただのメインリポジトリクローンとして、別のユーザーがログインしたときに使えるようにします。ディスク使用量にはあまり貢献しませんが(まだかなり高いです - アクティブなユーザーごとにフルクローンしかありません)、少なくともログイン/ログアウトをより速くすることはできます。
とはいえ、私は意図的にかなり小さなデータベースとユーザーベースの数字を計算したことに注意してください。100Kユーザー、1Kアクティブユーザー、データベースと編集履歴の合計が100MiBs、作業コピーが10MiBsです。もしあなたがもっと著名なクラウドソーシング・プロジェクトを見るなら、そこにはもっと高い数字があるはずです。
│ │ Users │ Active users │ DB+edits │ DB only │
├──────────────┼───────┼──────────────┼──────────┼─────────┤
│ MusicBrainz │ 1.2M │ 1K/week │ 30 GiB │ 20 GiB │
│ en.wikipedia │ 21.5M │ 133K/month │ 3 TiB │ 44 GiB │
│ OSM │ 1.7M │ 21K/month │ 726 GiB │ 480 GiB │
もちろん、これだけの量のデータやアクティビティがあれば、この方法はまったく受け入れられないでしょう。
一般的には、ウェブブラウザを "thick" クライアントとして使用し、git 操作を発行して、サーバー側ではなくクライアント側にチェックアウトのほとんどを保存できれば、うまくいったでしょう。
その他にも見落としている点はありますが、最初に比べればそれほど悪いものではありません。
- ActiveRecord、Hibernate、DataMapper、Towerなど、通常のORMの観点からすると、ユーザーの編集状態を"thick"にするパターンそのものが論外です。
- 私が探した限りでは、人気のあるフレームワークからgitにそのアプローチを行うための既存のフリーなコードベースはゼロです。
- 少なくとも、どうにかしてそれを効率的に行っているサービスがあります - それは、明らかに ギズーブ - しかし、残念ながら彼らのコードベースはクローズドソースであり、内部では通常の git サーバーやレポの保存技術を使用していない、つまり基本的に代替の "big data" git を実装していると強く推測されます。
それで ボトムライン : それは です。 可能ですが、現在のほとんどのユースケースでは、最適な解決策にはほど遠いでしょう。あなた自身のドキュメント編集履歴をSQLに変換する実装をロールアップするか、既存のドキュメントデータベースを使用する方が、おそらく良い選択肢になるでしょう。
関連
-
[解決済み] Git で直近のローカルコミットを取り消すには?
-
[解決済み] Gitブランチをローカルやリモートで削除するには?
-
[解決済み] git pull」と「git fetch」の違いは何ですか?
-
[解決済み] コミット前に 'git add' を取り消すにはどうすればよいですか?
-
[解決済み] リモートのGitブランチをチェックアウトするには?
-
[解決済み] Git リポジトリを以前のコミットに戻すにはどうすればよいですか?
-
[解決済み] Git リポジトリでのマージの衝突を解決するには?
-
[解決済み] リモート Git リポジトリの URI (URL) を変更するには?
-
[解決済み】"git pull" でローカルファイルを強制的に上書きするには?
-
[解決済み】ローカルのGitブランチの名前を変更するには?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
MySQLデータベースのクエリ機能を使用する際に、グループ関数の使用が無効である問題の解決方法
-
ORA-65096 無効な共通ユーザー名またはロール名
-
MySqlエラー解析'where節'の未知の列'xxx'
-
mysql import error [Err] 1273 - Unknown collation: 'utf8mb4_0900_ai_ci'.
-
Linuxでmysql-5.7.30をインストールするための詳細な手順
-
SQLSERVER エラーのリターンコードの意味一覧表
-
[c3p0] Error: c3p0プールの初期化中... ComboPooledDataSource [ acquireIncrement...
-
[解決済み] ファイル拡張子.DB - 正確にはどのようなデータベースなのですか?
-
[解決済み] PostgreSQLデータベースへのSQLダンプのインポート
-
[解決済み] データベースフィールドの標準的な長さのリスト