0

私はキャリア全体を非正規化リレーショナル データベースに費やしてきました。「App Store」のような個人的なプロジェクトで特定のアクセス パターンをいくつか処理できる単一テーブルの設計を実装するために、そのすべてを学ぶのに苦労しています。

これが簡単なERDです。プラットフォーム (iOS、Android) とバンドル ID によって識別されるアプリ モデルと、新しいバージョンを作成するときに使用されるデフォルト マップがあります。各アプリには、バージョン番号 (一連の数値であり、アプリのコンテキスト内で一意) で識別される 0 から多数のバージョンを含めることができます。バージョンには、他のいくつかの属性 (名前、リリース ノート、バイナリ パスなど) と共に IsReleased 属性があります。

アクセスパターン

  1. すべてのアプリの最新バージョンを一覧表示します。
  2. 特定のプラットフォーム用のすべてのアプリの最新バージョンを一覧表示します。
  3. IsReleased が 1 であるすべてのアプリの最新バージョンをリストします。
  4. IsReleased が 1 である特定のプラットフォームのすべてのアプリの最新バージョンを一覧表示します。
  5. 特定のアプリの最新バージョンを取得します。
  6. IsReleased が 1 である特定のアプリの最新バージョンを取得します。
  7. 特定のアプリのすべてのバージョンを取得します。
  8. IsReleased が 1 である特定のアプリのすべてのバージョンを取得します。
  9. 特定のアプリのデフォルト属性を取得します。

1 から 4 に問題があります。このテーブルは私が向かった場所です。並べ替え順で 1 つのバージョンのすべてのアプリアイテムを提供する GSI を入手するのに苦労しています。

パック sk デフォルト アプリ名 バージョン 解放されます その他の属性
app_ios_com.app.one defaults { ... json ... }
app_ios_com.app.one version_1 アプリワン 1 1
app_ios_com.app.one version_2 アプリワン 2 1
app_ios_com.app.one version_3 アプリワン 3 1
app_ios_com.app.two defaults { ... json ... }
app_ios_com.app.two version_1 アプリ 2 1 1
app_ios_com.app.two version_2 アプリ 2 2 0
app_ios_com.app.two version_3 アプリ 2 3 0

たとえば、アクセス パターン 1 の場合、次のようにします。

パック sk デフォルト アプリ名 バージョン 解放されます その他の属性
app_ios_com.app.one version_3 アプリワン 3 1
app_ios_com.app.two version_3 アプリ 2 3 0

たとえば、アクセス パターン 3 の場合、次のようにします。

パック sk デフォルト アプリ名 バージョン 解放されます その他の属性
app_ios_com.app.one version_2 アプリワン 3 1
app_ios_com.app.two version_1 アプリ 2 1 1

覚えておく必要があるいくつかのデータ制約:

  • 現在、アプリは 10 ~ 20 個しかありませんが、数百個をサポートできるようにする必要があります
  • ほとんどのアプリには 100 から 200 のバージョンがあり、20 から 30 のリリース バージョンがあります。最大のアプリには 1000 のバージョンがあり、そのうち 50 がリリースされています。
  • バックエンドでは、IsReleased フラグは通常 0 から 1 に切り替えられますが、0 から 1 に切り替えられることもあります。
  • 平均バージョン アイテムは約 2 KB です。
  • IsReleased が 1 であるアクセス パターン バリエーションは、かなりの差でより頻繁に使用されます。

解決策はすぐ目の前にあるような気がしますが、指を置くことはできません。

4

1 に答える 1

0

TLDR; 頭に浮かぶ解決策は、アプリの最新バージョンを個別のレコードにキャッシュするリーダーボード パターンです。新しいバージョンが追加されるたびに、DynamoDB ストリームは変更をイベントとしてラムダに送信し、ラムダは非正規化された最新レコードを更新します。

: あなたの優れた記事には 1 つの情報がありませんでした: どのくらいの頻度でlatestクエリを実行する必要がありますか? それほど頻繁でない場合は、現在のボリュームに対して「スキャンして完了」で問題ありません。答えがlatest1 分あたり 1,000 クエリである場合、それは別の話です。良いニュースは、基本的なテーブルのデザインがしっかりしていることです。 Latestクエリの最適化は、パフォーマンス/コストの問題が発生したときに、テーブルの設計をいじることなく段階的に実装できます。

最新バージョンの非正規化

最新バージョンの非正規化されたコピー、別の罪深い響きのDynamoDB パターンを保持します。ストリームによってトリガーされるラムダは、バージョンが追加されるか、リリース ステータスが変更されると、更新 API を使用してこれらのレコードを更新します。最新のバージョン情報を保存する方法は? いくつかのオプションがあります。

  1. すべてのlatestデータをマップ属性を持つシングルトン レコードに格納します{app1: {latest version copy}, app2: ...}。アイテムを処理するためのロジックをレコードに追加するisReleasedか、単にレコードを取得してバックエンドでフィルター処理することができます。
  2. アプリごとに 1 つのレコードを持つグローバル セカンダリ インデックスを使用します。各レコードには、 の GSI1PK と GSI1SK として「latest」がありapp_idます。レコードには、#1 と同じ情報が含まれています。
  3. アプリごとに複数のレコードを持つ GSI として使用します。このようなものがうまくいくようです。たとえば、クエリ #4 は次を使用します。GSI1PK=Latest#Released AND begins_with(GSI1SI, "IOS")
GSI1PK              GSI1SK
Latest              app_ios_com.app.one
Latest              IOS#app_ios_com.app.one
Latest#Released     app_ios_com.app.one
Latest#Released     IOS#app_ios_com.app.one

: クエリの量が多く、カーディナリティが低い場合、これらの「リーダーボード」タイプの非正規化パターンでホット パーティションが問題になる可能性があります。これが問題になる場合は、各「最新」レコードの複数のコピーを保持することで対処できlatest-copy1ます。Amazonでは、計算されたサフィックスを使用したこのパターン シャーディングを呼び出します。latest-copy2latest-copy3

于 2021-12-02T09:56:22.963 に答える