バッチで稼働していたシステムをワーカーに置き換えました

f:id:kmotoki:20191205151832p:plain

この記事はBASE Advent Calendar 2019 9日目の記事です。

devblog.thebase.in

こんにちは、BASE株式会社 ランニング部部長の元木です。

フルマラソンのサブスリー達成を目指して日々トレーニングに励む傍ら、Owners Marketingというチームでサーバーサイドエンジニアもやっております。

前書き

弊社が提供するネットショップ作成サービス「BASE」(以下「WEB」)とショッピングアプリ「BASE」(以下「アプリ」)では、Amazon CloudSearch(以下「CloudSearch」)を利用して商品の検索機能を提供しております。

当記事では、 CloudSearch のインデックスを更新する処理を、どのようにバッチからワーカーに置き換えたのかをご紹介させていただきます。

この記事は、「BASE Advent Calendar 2019」の9日目の記事です。

バッチの何が問題だったのか

商品データは、ショップオーナーさんや購入者のアクションによって刻々と変化していきます。
BASEのシステムは、その商品データの変化を捉えて CloudSearch のインデックスを更新していくこととなります。
CloudSearch のインデックスを更新するのは比較的時間がかかる処理であることと、 CloudSearch には
「更新の頻度が10秒に1回を超えると、スロットリングが発生する場合がある」
という制限があるため、BASE ではバッチプログラムを用いて、非同期でこの処理を実行しておりました。

しかし、バッチ処理には

  • インデクシングが必要な商品数は日々増えていくが、処理をスケールできない
  • DBへの負荷が高い

という問題がありました。

試験的に、アプリ側には Amazon SQS (以下「SQS」)をポーリングして CloudSearch のインデックスを更新するワーカーが導入されておりましたが、一部のアクション(商品の登録・更新・削除)しかカバーしておりませんでした。

以下が、切り替え前のシステム構成です。

f:id:kmotoki:20191205152852p:plain

弊社CTOの @dmnlk と話した結果、これを以下のような構成に変更することが決まりました。

  • SQS の前段に Amazon SNS (以下「SNS」)を配置する。
  • WEB用の SQS を新たに追加する- アプリ側、WEB側ともに、バッチをワーカーに完全に置き換える

以下が、目標とするシステム構成です。

f:id:kmotoki:20191205153229p:plain

ちなみにこの時の私の Amazon SNS に対する理解度は、こんな感じでした。

f:id:kmotoki:20191205153354p:plain

次からは、どのような段取りでシステム構成を切り替えていったのかをご説明します。

バッチからワーカーへ

手順1 : Amazon SNS の配置

  まず、SQS の前段に SNS を配置し、商品データが更新された際の通知先を SQS から SNS に切り替えました。

f:id:kmotoki:20191205153458p:plain

アプリケーションの変更点としては、インデックスの更新が必要になるアクションが発生した際の通知先を SQS から SNS に切り替えるだけです。

手順2 : WEB用のワーカーとSQSの配置

次に、WEB用のワーカーと SQS を配置し、ポーリングを開始しました。

f:id:kmotoki:20191205153627p:plain

まだ、一部のアクションしか SNS に通知されない状況ですので、引き続きワーカーとバッチを並行稼動させています。

WEB用のワーカーを実装する際には、バッチとワーカーが同じ動作をすることを保証するために

  • バッチのテストコードを書く(それまでは無かった)
  • バッチのテストコードとワーカーのテストコードとでデータプロバイダーを共通化し、入力と出力が一致することを保証する

といった工夫も行ないました。

SNS と WEB用の SQS を連携させる際も、いきなり全てのイベントを通知させるのではなく、 SNS のメッセージ・フィルタ機能 を利用して通知するイベントを徐々に増やしていくようにしました。

手順3 : Amazon SNS に通知するアクションを増やしていく

次に、SNSに通知するアクションを徐々に増やしていき、最終的に CloudSearch のインデックスを更新する必要のある全てのアクションが SNS に通知されるようにしました。

f:id:kmotoki:20191205153830p:plain

ここでも、一気に全アクションを通知するよう変更するのではなく、段階的に通知するアクションを増やしていくようにしました。

実は、手順2, 3 を実施していく過程で何度かWEB用のワーカーに不具合が見つかり、改修を行なっております。 しかし、バッチとの並行稼動を続けていたことと、ワーカーの仕事量を少しずつ増やしていくようにしていたため、大きな問題に発展することはありませんでした。

手順4 : バッチの退役

全てのアクションが SNS に通知されるようになったところでバッチを退役させ、すべての作業が完了しました。

f:id:kmotoki:20191205153923p:plain

まとめ

サービスが成長していくにつれて、以前は問題なかったシステムから問題が生じるようになることは往々にしてありえます。

一方で、システム構成の変更は比較的リスクが高い上に(何か新しい機能を提供するわけではないため)地味な作業であるため、ついつい、問題が大きくなるまで放置してしまいがちです。

私としては、作業の段取りを工夫することでリスクを最小限に抑えつつ、サービスの成長に応えられるシステムを構築し続けていきたいと考えております。