MongoDBの無駄なスペースを削減するための戦略
Appboyは、モバイルアプリ向けの世界をリードするマーケティング自動化プラットフォームです。ユーザーがお客様のモバイルアプリで何をしているかを追跡し、ユーザーの行動や人口統計に基づいて、ユーザーがメール、プッシュ通知、アプリ内メッセージをターゲットにできるようにすることで、毎月数十億のデータポイントを収集しています。 MongoDBは、ほとんどのデータベーススタックを強化し、ObjectRocketの複数のクラスターで数十のシャードをホストしています。
MongoDBの一般的なパフォーマンス最適化戦略の1つは、ドキュメントで短いフィールド名を使用することです。つまり、次のようなドキュメントを作成する代わりに…
{first_name: "Jon", last_name: "Hyman"}
…ドキュメントが次のようになるように、短いフィールド名を使用します…
{fn: "Jon", ln: "Hyman"}
MongoDBには列や事前定義されたスキーマの概念がないため、データベース内のすべてのドキュメントでフィールド名が複製されるため、この構造は有利です。それぞれに「first_name」フィールドがある100万のドキュメントがある場合、その文字列を100万回保存しています。これにより、ドキュメントあたりのスペースが増え、最終的にはメモリに収まるドキュメントの数に影響し、MongoDBはドキュメントを読み取るときにドキュメントをメモリにマッピングする必要があるため、大規模な場合はパフォーマンスにわずかに影響する可能性があります。
Appboyを使用すると、イベントデータを収集するだけでなく、「カスタム属性」と呼ばれるものを各ユーザーに保存することもできます。たとえば、スポーツアプリはユーザーの「お気に入りのプレーヤー」を保存したいのに対し、雑誌や新聞のアプリは顧客が「年間購読者」であるかどうかを保存したい場合があります。 Appboyには、追跡するアプリのエンドユーザーごとのドキュメントがあり、その上に、名前や名前などのフィールドと一緒にそれらのカスタム属性を保存します。スペースを節約し、パフォーマンスを向上させるために、ドキュメントに保存するすべてのフィールド名を短くします。事前にわかっているフィールド(名、メール、性別など)については、独自のエイリアシングを行うことができます(たとえば、「fn」は「名」を意味します)が、カスタム属性の名前を予測することはできません。お客様が記録すること。顧客が「スーパーカリフラジリスティックエクスピアリドーシャス」という名前のカスタム属性を作成することを決定した場合、それをすべてのドキュメントに保存する必要はありません。
これを解決するために、「ネームストア」と呼ばれるものを使用してカスタム属性フィールド名をトークン化します。事実上、これはMongoDBのドキュメントであり、「FavoritePlayer」などの値を一意で予測可能な非常に短い文字列にマッピングします。このマップは、MongoDBのアトミック演算子のみを使用して生成できます
ネームストアドキュメントスキーマは非常に基本的です。顧客ごとに1つのドキュメントがあり、各ドキュメントには「リスト」という名前の配列フィールドが1つだけあります。配列にはカスタム属性のすべての値が含まれ、特定の文字列のインデックスがそのトークンになるという考え方です。したがって、「Favorite Player」を短く予測可能なフィールド名に変換する場合は、「list」をチェックして、配列内のどこにあるかを確認します。そこにない場合は、アトミックプッシュを発行して、要素を配列の最後に追加できます(db.custom_attribute_name_stores.update({_ id:X、list:{$ ne:“ Favorite Player”}}、{$ push:{list:“ Favorite Player”}}))、ドキュメントをリロードしてインデックスを決定します。理想的には、$ addToSetを使用しますが、$ addToSetは順序を保証しませんが、$pushはデフォルトで末尾に追加するように文書化されています。
したがって、この時点で、「FavoritePlayer」のようなものを整数値に変換できます。その値を1と言います。そうすると、ユーザードキュメントは次のようになります。
{
fn: "Jon",
ln: "Hyman",
custom: {
1: "LeBron James"
}
}
フィールド名は短くて整頓されています!これの大きな副作用の1つは、ドル記号やピリオドなど、MongoDBがエスケープせずにサポートできない文字を使用している顧客について心配する必要がないことです。
さて、MongoDBは絶えず増大するドキュメントに注意を払い、ネームストアドキュメントは無制限に増大する可能性があると考えているかもしれません。実際には、実装を少し拡張して、顧客ごとに複数のドキュメントを保存できるようにしました。これにより、新しいドキュメントを生成する前に許可する配列要素の数に適切な上限を設けることができます。最良の部分は、MongoDBのみを使用してこれらすべてをアトミックに実行できることです。これを実現するために、「leastvalue」と呼ばれる別のフィールドを各ドキュメントに追加します。 「最小値」フィールドは、このドキュメントが作成される前に以前のドキュメントに追加された要素の数を表します。したがって、「leastvalue」100と[「SeasonTicketHolder」「FavoritePlayer」]の「list」を含むドキュメントを見ると、「FavoritePlayer」のトークン値は101になります(ゼロを使用しています)。ベースのインデックス付け)。この例では、新しいドキュメントを作成する前に、「list」配列に100個の値のみを格納しています。ここで、挿入するときに、プッシュをわずかに変更して、「最小」のドキュメントを操作します。 value」の値であり、「list.99」が存在しないことも確認します(「list」配列のインデックス99には何もないことを意味します)。そのインデックスに要素がすでに存在する場合、プッシュ操作は何もしません。その場合、すべてのドキュメントに存在する要素の総数に等しい「least_value」を使用して、新しいネームストアドキュメントを作成する必要があることがわかります。アトミックな$findAndModifyを使用して、新しいドキュメントが存在しない場合は作成し、それをフェッチして、$pushを再試行できます。
お客様がカスタム属性をいくつか持っているだけではない場合、すべてのネームストアドキュメントを読み戻して値からトークンに変換すると、帯域幅と処理の点でコストがかかる可能性があります。ただし、特定のフィールドのトークン値は、計算されると常に同じであるため、変換を高速化するためにトークンをキャッシュします。
アプリケーションのさまざまな部分に「名前ストアトークン」パラダイムを適用して、柔軟なスキーマを引き続き使用しながら、フィールド名のサイズを削減しました。また、値にも役立ちます。ラジオ局のアプリに、ユーザーが聴いているトップ50のパフォーマンスアーティストの配列であるカスタム属性が格納されているとします。 50個の文字列を含む配列を使用する代わりに、無線局名をトークン化し、代わりに50個の整数の配列をユーザーに格納できます。特定のアーティストが好きなユーザーのクエリには、2つのトークンルックアップが含まれるようになりました。1つはフィールド名用、もう1つは値用です。ただし、値からトークンへの変換をキャッシュするため、キャッシュレイヤーでマルチ取得を使用して、任意の数の値を変換するときにキャッシュへの単一のラウンドトリップを維持できます。
この最適化は確かに間接参照と複雑さを追加しますが、Appboyのように何億人ものユーザーを保存する場合、それは価値のある最適化です。このトリックにより、数百ギガバイトの高価なSSDスペースを節約できました。
もっと知りたいですか? 9月18日にCiprianiで開催されるRackspaceSolveNYC Conferenceで、AppboyでDevOpsについて話し合う予定です。
-
MongoDBの主なユースケース
元々は2018年6月13日にObjectRocket.com/blogで公開されました 一貫して優れたカスタマーエクスペリエンスを作成することは、多くの組織にとって重要な課題になっています。現実には、優れたカスタマーエクスペリエンスが何であるかについての私たちの期待は、過去数年間で劇的に高まっています。以前はクールで異なっていたものが今では標準になっています。データの集約は、これらの素晴らしい体験の鍵です。 この投稿では、私たちが遭遇する最も一般的なMongoDB®のユースケースのいくつかと、これらの選択に影響を与えるさまざまな特性について説明します。 顧客分析 データ集約は、すばら
-
MongoDBのスペース使用量を理解する
MongoDBを初めて使用する方にとって、MongoDBのスペース使用量は非常に混乱しているように思われるかもしれません。この記事では、MongoDBがスペースを割り当てる方法と、ObjectRocketダッシュボードのスペース使用量情報を解釈して、インスタンスを圧縮する必要がある場合や、インスタンスで使用可能なスペースを増やすためにシャードを追加する必要がある場合を判断する方法について説明します。 まず、単一の5GBシャードで構成される新しいMediumインスタンスから始めましょう。このインスタンスに「ocean」という名前のデータベースのテストデータを入力します。テストデータを追加し、い