JMDC TECH BLOG

JMDCのエンジニアブログです

サーベイメール一斉送信の負荷対策

こんにちは。@dtaniwakiこと谷脇です。

今年、JMDCではアドベントカレンダーに参加しています。

qiita.com

本記事は、JMDC Advent Calendar 2023 24日目の記事です。

私は産業保健向けのサービス「Pep Up for WORK」の開発に携わっています。「Pep Up for WORK」は社員一人ひとりを元気にし、活気ある組織作りを実現することを目的としたサービスです。

Pep Up for WORKの機能の1つとして、パルスサーベイというものがあります。継続的に簡易的なアンケートを取得することで、組織や従業員のリアルタイムな状態の変化を把握し、組織の改善施策に活かすことができる機能です。

この機能では従業員に対して一斉にメールを送信してアンケートの回答を集めるため、平常時に比べてアクセスが短時間に集中してしまうという特徴があります。アクセスが集中してサービスが落ちてしまうと、せっかくアンケートを配信しても回答ができなくなってしまいます。
一度でも回答に失敗すると、ユーザは回答する気が失せてしまい、アンケートの回収率が下がって本来の目的が達成できなくなってしまいます。

そのため、負荷によってオートスケールさせて対応したいところですが、急な分間10,000アクセスをリアルタイムにスケールさせて捌くことは難しいですし、サービス特性上、普段のアクセスが多くないため、常時スタンバイさせておくのは非常にコスパが悪いです。

今回、初手の手軽な対応として配信直前に先にスケールさせておく方法を導入したので紹介します。

前提知識

SendGrid

SendGridはクラウド型メール配信サービスです。

メール送信の個別の成否やリトライの手間を省くため、一斉メール送信ではSendGridのスケジュール配信を使います。
大量のメール送信をあらかじめ予約しておき、同時刻に一斉に送信することができます。

ECS (Fargate)

ECSはAWSのコンテナ実行・管理サービスです。

コンテナ数のスケールはイベント駆動やAPIで簡単に行うことができます。
ECSの実行環境には、実行されるコンテナの数・大きさに応じて自動でスケールしてくれる Fargate を使います。

負荷対策前

導入前の流れから説明します。

  1. 人事部がサーベイを作成する。
  2. 非同期ジョブが実行される。
  3. SendGridのバッチレコード作成をする。
  4. SendGridでバッチIDを付与してサーベイ開始時刻でメール予約をする。
  5. SendGridがサーベイ開始時刻にに一斉にメール送信を行う。
  6. メールを受信した従業員がサーベイに回答する。

この場合、ECSのスケールとアクセス数/タイムアウト数の関係は以下のグラフのようになります。

このグラフでは、1タスク500アクセスくらい捌けると仮定しています。
負荷によるオートスケールがアクセス数の増加スピードに間に合わず、かなりの数のタイムアウトが発生してしまっています。

「後ほどアクセスしてください」というエラーを出せばいいというのはごもっともなのですが、せっかくサーベイに答えようとしてくれたユーザのモチベーションを損ねてしまいます。
サーベイ回答にネガティブな印象を持たれることにより、今回だけでなく次回以降の回答率も低下する可能性もあります。

負荷対策後

導入後の流れです。

  1. 人事部がサーベイを作成する。
  2. 非同期ジョブが実行される。
  3. SendGridのバッチレコード作成をする。
  4. SendGridでバッチIDを付与してサーベイ開始時刻でメール予約をする。
  5. Workerがサーベイ開始時刻の少し前に、メール送信数を元にECSをスケールアウトする。
  6. SendGridがサーベイ開始時刻に一斉にメール送信を行う。
  7. メールを受信した従業員がサーベイに回答する。
  8. Workerが一定時間後にECSをスケールインして元のタスク数に戻す。

負荷に依存しないタスク数の下限値に、一時的に下駄を履かせるようなイメージです。

ECSのタスク増加数は1タスクでどのくらいのアクセスを捌けるかによるので、パラメータとして設定できるようにしておきます。

一斉メール送信後に全てのユーザがアクセスしてくるわけではないので、アクセス数の減衰スピードを想定し、スケールインは段階的に元のタスク数に戻すような工夫を入れています。

この場合、ECSのスケールとアクセス数/タイムアウト数の関係は以下のグラフのようになります。

アクセス数を十分に捌けるタスクを一時的に確保するのでやや無駄は出ますが、タイムアウトを出さずに回答を集めることができます。

実際はこれに加えて負荷によるオートスケールも組み合わせることで、想定外のアクセス増加もある程度捌けるようにしています。

今後の改善

今回導入した手法だと、タスクの増減はメール送信数に基づく見込みアクセス数を十分に捌けるタスク数にしました。

かし、それでは送信数が少ない場合には増加タスクの無駄が発生しますし、無駄を抑えるために閾値による増加数の切り捨てを行うと、同一時刻に複数サーベイが重なった場合に合算によるアクセス数増加に対応することができません。

そのため今後の改善としては、サーベイごとにタスク数を指定してスケールさせるのではなく、各サーベイの増加予定アクセス数を合算するプールを作り、それを元にタスク数の増減を決めてスケールさせることを考えています

まとめ

本記事ではサーベイのような一斉メール送信時に回答を取りこぼさないための負荷対策について紹介しました。

明日25日目の最終日は、小原さんです!お楽しみに。

 

Pep Up for WORKでは、メンタルヘルスケア領域の課題解決に一緒に取り組んでいただける方を積極採用中です!

hrmos.co

hrmos.co

hrmos.co

 

JMDCではPep Up for WORKの他にも様々なサービスを開発していますので、もしご興味ありましたら下記の募集一覧からご確認ください。

hrmos.co

★最新記事のお知らせはぜひ X(Twitter)をご覧ください!

https://twitter.com/jmdc_tech