emahiro/b.log

Drastically Repeat Yourself !!!!

DynamoDB で Update GSI しようとしてやらかした話

Overview

タイトルの通りなのですが、DynamoDB の Global Secondary Index(以下 GSI) を更新するにあたり、更新方法でミスったのでことの顛末を備忘録として記載しました。

何をしたのか?

terraform で DynamoDB の構成を変更する、今回はすでに運用されてる DynamoDB の Table に対して GSI を更新するというオペレーションを実行しました。

resource "aws_dynamodb_table" "hoge_table" {
  hash_key     = "$HashKey1"
+ range_key    = "$RangeKey"
}

+attribute {
+   name = "$RangeKey"
+   type = "S"
+}

global_secondary_index {
   name            = "AlreadyExistIndex_1"
   hash_key        = "$HashKey1"
+  range_key       = "$RangeKey"
   projection_type = "ALL"
}

global_secondary_index {
   name            = "AlreadyExistIndex_2"
   hash_key        = "$HashKey2"
+  range_key       = "$RangeKey"
   projection_type = "ALL"
}

terraform の定義ファイルとしては上記のような感じで構成して terraform apply しました。

何が起きたか

GSI を更新するときに Index の recreate が発生し、すでにアプリケーションで使用していた AlreadyExistIndex_1 を Key にした Query オペレーションが ValidationException: The table does not have the specified index: AlreadyExistIndex_1 status code: 400 ... で落ちてアプリケーションが正常に動作しなくなりました。

どうして起きたか?

GSI を複数?(複数が関係してるかどうかわかりませんが、)更新するにあたり delete -> create の順で Index の更新が発生し、先に AlreadyExistIndex_1 と AlreadyExistIndex_2 が削除され、改めて Create されるというオペレーションにおいて AlreadyExistIndex_1 をアプリケーションが使用していたために、Create してる最中にもアクセスしてしまい 400 エラーが発生してしまいました。

公式のドキュメントにも

You can create or delete only one global secondary index per UpdateTable operation.

ref: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html#API_UpdateTable_RequestParameters

とあり、更新がタイミングごとに GSI の Delete と Create のオペレーションは1度ずつしか呼ばれません。

これだけだと即時で入れ替えがされそうにも読めますが、今回の挙動とこのドキュメントを参照する限り GSI の更新にあたり UpdateTable で既存の GSI を更新するときにはまず先に Delete Operation が実行され、その後に Create がされるようです。その後に Create がされるようです。つまり Terraform Apply で複数の Index を更新する場合、処理としてはそれは可能だけど既存の Index を全部先に削除(= 更新対象の 2 つとも削除)し、その後新しく Index を生成する、という挙動になるようです。

先に全削除が走ってしまうため、削除したタイミングで AlreadyExistIndex_1 をアプリケーション側で参照していたために、アクセスしてしまいエラーが発生した、と言うのが一連の流れでした。

今後どうすればいいか

すでに運用されてる GSI の更新をする場合には以下の手順で行うといいと思います。

  1. 変更先となる Index を新しい Index として定義して先に Create。
  2. aws dynamodb query ... コマンドを使って新しい Index が意図する動作になってるか確認する。
  3. アプリケーションの参照してる Index を新しい方に変更。
  4. 更新前の Index を Delete。

RDB を運用してる時と似てますね。

まとめ

定期的にやらかすことがあるんですが、今回は久しぶりに知識として知らないまま操作を行なってしまって焦りました。
DynamoDB についてまた一つ詳しくなることができました。