見出し画像

15分単位で借りられる予約システムを作った時の技術的トピック紹介

こんにちは。
スペースマーケット エンジニアの西尾です。

スペースマーケットでは長らく1時間単位でしか利用することができなかったのですが、最近15分単位で利用できるようにシステムを大きく改修しました。
今日はそれを実現する際に合わせて予約のカレンダー周りで抱えていた課題を解消したのでその取り組みの一部を紹介したいと思います。

抱えていた課題 その1 反映時間を早くしたい

スペースマーケットでは予約する時にどこが空いているか?その時間の各種プランの料金はいくらなのか?を表示する際に全てをリアルタイムで計算しているのではなく一部はあらかじめ計算しておいたキャッシュ情報を利用しています。

画像1

キャッシュを利用しているため画面表示は早いのですが、何かカレンダーに影響がある要素に変更があった場合の反映に少し時間がかかっていました。

これは変更があったというのを定期的に確認して更新するという仕組みであったためです。
キャッシュ情報がずれているからと本来予約できないところが予約できてしまった等は起こらないようにはしていたため、反映に少し時間がかかっても影響はなかったのですが、やはり反映時間はなるべく短くしたいという思いがありました。

画像3

抱えていた課題 その2 定期的な全件再計算がしたい

予約カレンダーにはキャッシュを利用していますが、たまにキャッシュずれが発生していました。
何かしらカレンダーに影響がある要素が更新されれば再度あるべき姿には戻るのですが、更新がないとずれたままになってしまう。

これを防ぐために定期的な全件再計算をしてズレを解消するという仕組みを入れたかったのですが、更新されたものを抽出 -> 更新 -> 抽出 -> 更新 というジョブフローのため、全件再計算をさせるために更新されたものを抽出する部分が大量にあると1回目の抽出・更新中に発生した間に変更があったものが処理されるタイミングが遅くなってしまいます。

例えば、全件更新のために1時間かかったとしたらその間新規の差分反映が1時間後になってしまう。
このような理由から定期的な全件再計算処理がしにくい状態でした。
今回の改修では合わせて定期的な全件再計算処理ができるようにしたいという思いがありました。

画像3

抱えていた課題 その3 処理は早く、サーバー費用は安く

大量の差分反映が必要なときは処理を早くするためになるべくよいサーバーで早く処理をさせたいです。
しかし、常によいサーバーが稼働し続けているとサーバー費用が高くなってしまいます。

今回の対応を行うまではキャッシュの反映時間を短くするためによいサーバーを利用していましたが、常によいサーバーが動き続けている必要はなく、必要なタイミングでは多くのリソースを投入、そうでない場合は少ないリソースを投入できるようにしてサーバー費用を抑えたいという思いがありました。

課題への対応 その1 反映時間を早くしたい

定期的に差分を確認するという仕組みから変更が起こったことをトリガーとしてキャッシュ情報を更新するという仕組みに変更しました。
具体的にはAWS Batch、StepFunctionでジョブを回し続ける仕組みからFargate, SQSを使った常駐起動の仕組みに変更を行いました。

画像4

Fargateバッチでは常にSQSを監視し続け(ロングポーリングで)、何か変更があった場合に処理するようにしています。
これにより、カレンダーに影響がある要素に変更があった場合は即時処理されるようになり、今まで数分〜10分程度かかっていた反映が大量更新でない限りはほぼ一瞬になりました。

課題への対応 その2 定期的な全件再計算がしたい

SQS, Fargateで反映時間は早くなりましたが、キューが1つだと定期的な全件更新を行うためにキューイングすると全件更新中は後続の処理が詰まってしまいます。

全件更新で更新される場合はキャッシュがずれている場合で頻度は非常に少なく優先度が低い。対して差分更新で更新されるものは何かしらカレンダーに影響がある要素が変わったのでキャッシュを更新したいものであるため優先度が高い。

そのため、キューを1つにしてしまうと優先して処理すべきものが遅れてしまいます。

画像6

このことに対応するために今回はキューとFargateを高優先、低優先の2つに分けることにしました。
こうすることで全件更新を行っているであっても優先度が高い差分更新の処理が遅れないようにしました。

画像5

課題への対応 その3 処理は早く、サーバー費用は安く

Fargateによる常駐起動になりましたが、全件更新では量が多いため多くのリソースが必要になる。逆に差分更新では少ないリソースで良い。
以前は大きいインスタンスを動かし続けていましたが、今回は小さなインスタンスでたくさん処理すべき時はスケールさせ、そうでない場合は少なくするように処理すべき数(SQSのキュー数)に応じて自動でスケールする仕組みを採用しました。

画像7

Fargateのサービス定義を更新する際にService Auto Scalingがあるためそれを設定して実現しています。
CloudWatchイベントでSQSのキュー数が一定数超えたらアラームを発報する。それが閾値をどれだけ超えているかでタスク数を変動させています。

画像8

画像9

このような仕組みを入れることで、大量処理の場合は多くのリソースを、そうでない場合は少ないリソースで動くようにしました。

また、バッチにFargateを取り入れることに合わせて今回はFargate Spotも利用するようにしました。Fargate SpotはEC2のスポットインスタンスのようなもので最大70%割引で利用できることと今回のバッチの性質上途中で中断されたとしてももう一度処理すれば良いものであるため取り入れることにしました。

画像10

これによりたくさんのインスタンスを動かしたとしても安く処理できるようにしています。
最終的にはオートスケールの仕組みとFargate Spotを利用したことにより今までの3分の1の値段で動かせるようになり、結果にはとても満足しています。

終わりに

今回は予約を15分単位でできるようにする改修に合わせて取り組んだ技術的トピックについて紹介させていただきました。

今までガッツリインフラ周りを触ることが自分は少なかったので今回の開発はとても身になることが多かったです。
今後もスペースマーケットがより良いサービスになるように改良を続けていきます。

この記事が気に入ったらサポートをしてみませんか?