こんにちは!
みそ汁の美味しさに目覚めた、エンジニアの山元です。
この記事では、先日実施した求人閲覧履歴データのRedisからDynamo DBへの移行についてご紹介したいと思います。
移行の背景
OpenWorkは現在(2022年11月現在)約48000件の求人情報を掲載しております。 そして、求人情報に関連したネイティブアプリの機能として「求人閲覧履歴機能」があります。
この求人閲覧履歴ですが、求人閲覧後すぐに履歴に反映される必要があるため、データアクセスが高速なNoSQLであるRedis上に保存されていました。
しかしRedisは揮発性のDBであり、障害が発生したり再起動を行ったりした場合にはデータが削除されます。
この機能の実装当初は動作速度を最優先しており、閲覧履歴が消えるということのデメリットをあまり考慮していませんでした。
近々バージョンアップに伴うRedisの再起動が予定されており、改めてユーザさんが自らの閲覧履歴を見れなくなるという状況について議論になりました。
結果、バージョンアップまでに既存の求人閲覧データを永続化可能なNoSQLであるAmazon DynamoDBに移行することとなった、というのが大まかな経緯です。
私は、
- 求人閲覧履歴機能のコードをDynamoDB用に修正
- 求人閲覧履歴データのRedisからDynamoDBへのマイグレーションバッチの作成
- 本番環境へのリリース作業
を担当することになりました。
移行する上での問題点
既存の機能は止められない & 移行中の履歴も取得しなければならない
今回は新機能の実装ではなく、稼働中の機能のリファクタリングおよびデータベースの移行であるため、特に以下の2点が問題となります。
- データの移行のために求人閲覧履歴機能を止めることはできない。
- データ移行作業中の求人閲覧履歴含め全ての閲覧履歴がDynamoDBに入っている必要がある。
しかしどのような方法でリリースしても、マイグレーション作業中のログが取れなかったり、一部の期間の履歴しか閲覧できなくなるなどの不都合が発生します。 今回のタスクにおいては、マイグレーション作業中に一時的に過去の閲覧履歴が閲覧できなくなる状態を許容することとしました。
そのためリリースの手順は、
- DynamoDBテーブルの作成。
- プロダクトコードをリリースし、履歴の保存・参照先をRedisからDynamoDBに切り替える
- 既存のデータをRedisからDynamoDBへ移行。
となりました。
batchWriteItemが少々使いづらい
AWS SDK for PHP にはDynamoDBへデータを登録するためのメソッドが複数用意されています。 しかし、一度のリクエストで複数の項目をまとめて登録することができるのはbatchWriteItemです。(1リクエストにつき最大25件の項目を登録可能) データのマイグレーションという状況であれば、大抵の場合はbatchWriteItemを使用することになるはずです。 今回のタスクでもこちらのコマンドを使いました。
1回のリクエストで1、2件登録に失敗してもエラーを吐かない
ただ気をつけなければいけないのは、batchWriteItemが書き込みに失敗した場合です。
書き込みに失敗した場合でもリクエストした全ての書き込みが失敗しない限り例外を返さず、そのまま処理を続行してしまいます。 batchWriteItemは返り値として、UnprocessedItemsという処理に失敗したリクエストを返すので、UnprocessedItemsが空でなければ改めて同じリクエストを投げる、という処理が必要になります。
単純に書き込むことしかできず、同じキーの項目が存在しても上書きしてしまう
また、batchWriteItemは登録時に「同じキーの項目が存在したら登録しない」のような設定をすることができません。 リクエストされた項目を単純に書き込むだけなので、同じキーでvalueの異なる項目が存在して場合は上書きしてしまいます。
例えば今回の移行のケースでは、マイグレーション作業中に既存の閲覧履歴の閲覧日時が更新されても、batchWriteItemによってマイグレーション作業直前のデータで上書きされるので、閲覧日時が巻き戻ってしまうということが考えられました。
しかし今回に関しては
- 閲覧の日付が巻き戻り履歴の並び順は不正確なものになるが、閲覧したという履歴そのものがなくなるわけではない
- マイグレーション作業中に、すでに見たことのある企業の求人を再び閲覧した場合のみ発生する事象のため、多発はしないと想定される
という状況であったため、batchWriteItemを使うことができました。
データの性質やテーブル設計によっては、クリティカルな影響を及ぼすかもしれないため注意が必要でした。
工夫したこと、大変だったこと
データ登録中のログの出力
当然ではあるのですが、データ移行では既存のすべてのデータが漏れなく移行されている必要があります。 ただ前述の通り、batchWriteItemは項目の登録に失敗しても全件失敗でない限りエラーを吐きません。 データの登録には失敗していないか、失敗した場合はその後のリトライはうまくいったのか、しっかり監視できるよう移行中のログはわかりやすく出力されるよう工夫しました。
移行作業の負荷検証
移行用バッチの作成は終わっても、このバッチが実環境で問題なく稼働しなくては意味がありません。
移行の負荷が大きすぎてDynamoDBのスループットを食い潰さないか、リクエスト数の増加にスケーリングは追いつくのかなど、実行に関連して気にしなくてはいけないことはいくつもありました。
そこで、インフラエンジニアに作成してもらった開発環境のDBを使用して、移行の負荷検証を行いました。
複数のデータセットでバッチの実行を繰り返し、計算上は負荷は問題ないレベルだろうということを確認することができました。
しかし、あくまで開発環境であり、本番と同じスペックの環境ではありません。本当に本番環境でうまくいくのかはやってみないと分からない訳で、その部分の不安は残ったままでした。
まとめ
リリース前のテストには結構苦労し時間もかかりましたが、しっかりテストを行ったおかげで、本番の作業では大きな問題も発生せず滞りなくデータ移行を完了させることができました。
新しいコードとDB、移行したデータは、現在もOpenWorkのサービス上で問題なく稼働しています。
リファクタリングとデータ移行という、外からは見えない部分のタスクではありましたが、二つのDBを対象にした作業だったため学びの多い貴重な経験となりました。
最後に、弊社ではエンジニアを募集しています、今回の記事を読んで興味を持っていただけましたら、採用サイトの方もご覧いただけると嬉しいです。