web-dev-qa-db-ja.com

ユーザーにCSVファイルのアップロードを許可し、単純なAPIのデータを埋め込む

将来のエッジケース、バグと落とし穴、パフォーマンス、クラウドの価格設定、構築と保守の容易さ、セキュリティなど、考慮に入れるべき正しいアーキテクチャを探します。

AWSでホストされているサーバーレスアプリがあります。ほとんどのBEロジック( aws-amplify で管理)にLambdaといくつかのDynamoDBテーブルを使用します。

ユーザーがCSVをアップロードし、アプリのテーブルとして表示できる機能を追加し、IDに基づいて1行を取得する単純なパブリックAPIを作成します(より複雑なクエリは必要ありません)。 CSV(列)の構造は、アップロードごとに異なります。

各ユーザーは約0〜10個のCSVを追加し、各CSVには3〜20列と約1k〜100k行が含まれます。 CSVの追加は1か月/週に1回行われ、APIを使用した行の読み取りは1日あたり10k〜100k行われます。

どのように構築すればよいですか? (Lambdas/DynamoDBに限定されません)


私が考えていた解決策は次のとおりです。

1。 CSVのアップロードごとに新しいテーブル(sql/document)を作成し、user.csvs[]にテーブルの名前を保存します。

これにより、大量のテーブルが作成されます。それは合理的な解決策ですか?

2。すべてのCSVデータをドキュメントデータベースに追加します。 -

user { 
name: "john",
csvs: {
  csv123: {
    id345: {col1: 'x', col2: 'y'},
    id678: {...},
    ...
  }
 }
}

最高のパフォーマンスを得るには、このソリューションで何をインデックス化すればよいですか?

3。ファイルをバケットにアップロードし、すべてのリクエストでファイルを開き、リクエストされた行を返すラムダを作成します。 (このオプションはDBインデックス作成をスキップします)


あなたの経験から学ぶことを願っています。

2
yonatanmn

ソフトウェアソリューションに関しては、1つの正しいソリューションが存在することはほとんどありません。私はあなたのオプションのいくつかといくつかのヒントについていくつかの確認を提供するつもりです。

これはDynamoでかなり簡単に行うことができ、すでに使用しているため、ニーズに十分に対応できるソリューションである可能性があります。弾力性があり、意図したとおりに機能するように設計すると、パフォーマンスが向上します。おそらく最大の利点の1つは、拡張性が高いため、ユーザーベースが拡大しても、再設計する必要がないことです。それまでは、使用した分だけお支払いいただきます。私が見つけた最大の欠点は、ストレージの無料利用枠を超えると、GBあたりのコストが最も安くはないということです。テーブルごとに月額のオーバーヘッドがあるため、ここでは1つのテーブルが最も費用対効果の高いソリューションです。

あなたはこの解決策に関して尋ねます:

最高のパフォーマンスを得るには、このソリューションで何をインデックス化すればよいですか?

シンプル:クエリを実行しているものにインデックスを付ける必要があります。あなたは前に言う:

... IDに基づいて1行をフェッチする単純なパブリックAPI(より複雑なクエリは必要ありません)。

これがDynamoが本当に良い解決策となる主な理由の1つですが、CSV IDではなく、ユーザーIDを意味していると思います。 CSV IDをパーティションキーにできる場合は、追加のインデックスは必要ありません。パーティションキーによるクエリは、パフォーマンスとコストの点で最良のソリューションです。ただし、このキーはテーブル全体で一意である必要があります。これは パーティションキーの選択 に関するドキュメントです。

ユーザーごとにCSVをプルできるようにする必要がある場合は、グローバルセカンダリインデックス(GSI)を追加する必要がある場合があります。使用するかどうかにかかわらず、インデックスの作成と保持には追加のコストがかかることに注意してください。

表示する構造に関しては、ユーザーごとに1つのレコードを作成し、それにすべてのCSVを追加する必要があるようです。これはおそらく私が行く方法ではありません。代わりに、CSVごとにレコードを作成し、変更しないでください。唯一の注意点は、CSVのすべてが本当に小さい場合(例:1 KB未満)、コストの観点からは非効率的です。

Idがユーザーのものである場合は、ランダムUUIDなどのパーティションキーとして、よく分散されたランダムキーを使用します。ほとんどがランダムではないため、UUID(GUID)に注意してください。使用する場合は、「バージョン4」のUUIDを使用してください。別のオプションは、ユーザーをパーティションキーとして、ドキュメントIDをソートキーとして使用して、複合パーティションキーを作成することです。これにより、すべてのユーザーのドキュメントが同じパーティションに配置されます。トレードオフはありますが、ユーザーあたりのCVSの数が妥当であり、同時に1人のユーザーの多数のCSVにアクセスしようとしない限り、これは問題なく機能する可能性があります。

ユーザーが同時にアップロードしたすべてのCSVを開きたいとは思わないでしょう。ドキュメントIDをパーティションキーとして使用する場合は、ユーザーIDにGSIを作成し、ユーザーがどのCSVのパーティションキーと共に表示するかを決定するために必要なレコードの値のみを投影します。予測を制限することで、インデックスの費用対効果が向上します。ユーザーが表示したいCSVを選択すると、パーティションキーを使用してそれを取得します。注:ダイナモのレコードのマップまたはリスト内の値にインデックスを付けることはできません。これは、レコードを構造化するときに考慮することが重要です。複合パーティションキーを使用する場合、パーティションキー(つまり、ユーザーID)を直接照会できるため、これは必要ありません。

まず、各レコードを構造化する方法を次に示します。

{ 
user: "john",
id: "csv123"
columns ['x', 'y'],
data [
  [100, 200],
  [200, 300],
  ...
],
}
2
JimmyJames

CSVは、設計時に列ラベルが不明なテーブルです。 CSVの明確な仕様はないと思いますが、カンマ区切りで、最初の行に列ラベルがあると仮定しましょう。

first,last,age
john,doe,52
sue,mary,42

私のMVPは単一のテーブル/コレクションを使用することになります

userid fileid rowid content
100    1      1     first,last,age
100    1      2     john,doe,52
100    1      3     sue,mary,42

行のクエリには、行1とユーザーが探している行の2回の読み取りが必要です。クエリ時に、列のラベルと値から応答JSONを作成します。実際には、出力形式が何であるかを言っていません。

ここにはいくつかのインメモリ文字列処理がありますが、影響はごくわずかです。

繰り返しアクセスできる場合は、応答JSONまたは選択した応答形式をDBに書き戻し、コンテンツが処理されたことを示すフラグを導入できます。

このソリューションの鍵は、クエリを必要とせず、単一行のアクセスだけを制約に含めることです。したがって、動的なテーブルマジックは必要ありません。データベースは、データの構造に関する知識を持っている必要はありません。クエリ時にメモリ内の非常に小さなデータセットを処理できます。データベースに行を見つけさせます。

2
Martin K