LoginSignup
6

More than 1 year has passed since last update.

posted at

updated at

AppSync の DynamoDB リゾルバの Scan で意図したデータが取得出来なくなった時の対処法

はじめに

開発中盤で AppSync で開発している最中に追加したデータが、
突然 List Query で取得出来ない事態が発生しました... :scream_cat:

調査したところ、
AppSync のデータソースで DynamoDB のデータソース生成した際に GraphQL を自動生成したのですが、
そこにヒントがあることを発見しました:bulb:

結局の所、DynamoDB への理解不足で片付く話なのですが、、
何となく AppSync を使っていると遭遇してしまう問題だと思います... :punch:

そこで、同じ問題で悩む人を助けられればと思い、
記事に残しておくことにしました :writing_hand:

DynamoDB に登録されているはずのデータが AppSync の List Query で取得したデータに含まれない事象が発生することがある

AppSync で開発を開始した直後や、
登録データ数が少ない間は List Query の filter を用いてデータの絞り込みを行いつつ、
正常に意図したデータが取得出来るはずです :arrow_down:
4a96c5227343327499ec4c380f65b661.png
8b41f67abe2fc998ca2d6e97925d87ec.png

しかし、ある日 DynamoDB にデータが登録されているのに List Query の filter で、
正常に意図したデータが取れない事象が特定の List Query で発生するようになってしまいました... :upside_down:

20b80b348009f35572b930aeb5bbdeb2.png
5492af978c4e56f29e6f8234d999344d.png

DynamoDB には channel_id42713673-eb21-43ef-bdbc-f460989fb505 でデータが 1件登録されていることは確認済みなのに AppSync の List Query では 1件も取得できないのは何故でしょうか。。??:thinking:

DynamoDB データソース追加時に自動生成されたリゾルバを確認してみる

DynamoDB のデータソース登録時に自動で GraphQL 生成にチェックを入れていれば、
AppSync の List Query は自動生成され DynamoDB リゾルバが登録されています :white_check_mark:

原因調査のため AppSync の裏の DynamoDB リゾルバが何を行っているか中を覗いてみます :mag:

9a7d6dcbfb03aab6abfaf21cdf91a20a.png
3a91f0e79dcd05153f6e52543975dcda.png

:arrow_up: を見ると、Scan を用いて filter で検索条件を絞って limit で指定した件数のデータが取得出来るようになっているように見受けられます :mag:

DynamoDB の Scan の仕様を確認する

次に DynamoDB の公式ドキュメント を見て Scan の仕様について確認していきます。
早速公式ドキュメントのトップに Scan についての説明が記載されていました :pencil:

Amazon DynamoDB での Scan オペレーションは、テーブルまたは セカンダリインデックス のすべての項目を読み込みます。デフォルトでは、Scan オペレーションはテーブルまたはインデックスのすべての項目のデータ属性を返します。

:arrow_up: を見ると Scan はデフォでレコードを全件取得するような挙動となるようです。

結果セットの項目数の制限

ドキュメントを読み進めていくと、
次に 結果セットの項目数の制限 の項目が目に止まりました :eyes:

ここで、Scan にフィルタ式を追加するとします。この場合、DynamoDB は返される 6 つの項目にフィルタ式を適用し、一致しない項目を廃棄します。最終的な Scan 結果はフィルタリングされる項目の数に応じて、6 つ以下の項目を含みます。

:arrow_up: を見ると Scanfilter を使用した際の挙動として 一致しない項目を廃棄します とあります :wastebasket:
AppSync の DynamoDB リゾルバを確認した際、Scanlimit はデフォでは 20 でした。

つまり、正常にデータが取得出来なかった AppSync の List Query を元に、
実際に実行された DynamoDB の Scan の挙動を推測すると、
データを 20件取得した中に該当する channel_id のデータが見つからなかったので空を返した
という挙動になりそうです :pencil:

RDBMS の SQL の Where 句のような、
該当する channel_id のデータを 20件まで検索して取得する
という挙動を想定していましたが、それがそもそもの誤りだったようです... :upside_down:

スキャンの読み込み整合性

更にドキュメントを読み進めていくと スキャンの読み込み整合性 という項目も発見しました :eyes:

Scan オペレーションは、結果的に整合性のある読み込みをデフォルトで行います。つまり、Scan 結果が、最近完了した PutItem または UpdateItem オペレーションによる変更を反映しない場合があります。詳細については、「Read Consistency」を参照してください。

強力な整合性のある読み込みが必要な場合は、Scan が開始する時に ConsistentRead パラメータを true リクエストで Scan に設定できます。これにより、Scan が開始する前に完了した書き込みオペレーションがすべて Scan 応答に含められます。

:arrow_up: を見ると RDBMS では保証されている一貫性は無いので、
Scan を実行するタイミングによって取得可能なデータは変動する可能性がある
ということを Scan を用いたデータ取得を行う際は考慮する必要がありそうです :pencil:

対策方法

まず、AppSync の limit がデフォで 20 なので GraphQL クエリの limit100 等の、
一度の Query で filter で絞り込むデータが十分に取得出来そうな数に設定しておきます1 :printer:

8bbf374ac035a470852cad3f425466ab.png

また、Web アプリケーション等でよく使用される、画面最下部までスクロールした際にロードを行う処理の実装等を考慮した場合、nextToken を用いたページネーションの実装も考慮しておく必要があります :white_check_mark:

d3e7bd3b6c78b2c47f1693baa83fca03.png
6e5f9b851e6d2af8b0e83b716f3a6cc3.png

:arrow_up: の流れで List Query を実行するようにしておけば、
画面最下部までスクロールした際のロード処理が実装可能です :thumbsup:

おわりに

結果 AppSync というよりも DynamoDB の仕様にフォーカスに当たった記事内容になりました :writing_hand:

AppSync の DynamoDB リゾルバを雰囲気で扱っていたため起きた問題で、
ステージング環境で実際にデータがある程度追加されてきてから問題が発覚したため、
個人でデバッグしているときには全く気づくことが出来ませんでした... :bomb: :boom:

また保守運用の観点から予め DynamoDB の設計についても考慮しておいたほうが良いと思われます :raised_hand:
公式ドキュメントに DynamoDB の設計のベストプラクティス についての解説ページがあるので読んでおいた方が良さそうです :book:

以上 AppSync を用いる際に DynamoDB リゾルバを自動生成して利用する際は十分にご注意ください :bow:

参考リンク


  1. 大量のデータが登録されている状況であれば Scan の Query から limit は無くしてしまい、一度の Scan で最大の 1.0MBまでのデータを取得するようにして良いかも知れません 

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
6