2024.12.02
業務時間外攻撃から守る、侵入を防ぐための最適解 誰も教えてくれない攻撃者目線のセキュリティ対策
オンライン即売会を支えた技術(全1記事)
リンクをコピー
記事をブックマーク
金川祐太郎氏(以下、金川):「オンライン即売会を支えた技術」。BOOTH部の金川がお話します。よろしくお願いします。
「BOOTH」では、突然の決済スパイクに頭を抱えていました。決済スパイクは、例えば有名なクリエイターの期間限定販売や、「YouTube」などVTuberの配信中に商品が公開された時、あとは最近行われるエアコミケといったオンライン即売会などで発生します。
決済スパイクが起きる時、BOOTHでは同じ商品に注文が集中します。この時に何に困るかというと、これはBOOTHで以前行われていた処理なのですが、同じトランザクションの中で在庫処理と決済処理を同時に行っています。まず商品で悲観的ロックを取り、在庫の減算を行い、注文の確定を行ってから決済確定APIを呼び出します。この時、同じ商品で注文が殺到してしまうと、注文を1つずつしか捌けないため、時間のかかる処理が行われていた場合、トランザクションが詰まってしまいます。
実際にこれは同じ商品に注文が殺到したケースで、ピクシブ株式会社では「DataDog」というツールを使って処理のかかっている時間を見られるのですが、この決済処理には約13秒ほどの時間がかかっていて、そのほとんどが在庫ロック待ちで使われていました。
そこでスパイクを捌くためのアプローチとして、3つの方法を考えました。まず1つ目が、在庫1個ごとにレコードを用意する方法。2つ目が、決済されるごとに「Sidekiq」にジョブを積んで非同期で処理を行う方法。3つ目が、トランザクションを分割するという方法です。
まず、在庫1個ごとにレコードを用意する方法です。これは最初に考えた方法で、「在庫 ロック」などで検索を行うと出てくる事例です。在庫ごとにレコードを作って、個別にロックを取ればいいという方法なのですが、BOOTHの在庫数をsumで取ってみたところ数億になったので、さすがにこれは現実的ではないと断念しました。
2つ目は、決済されたらSidekiqにジョブを積んで非同期で決済を行う方法です。決済が完了したらメールやポーリングなどを使ってユーザーに通知します。しかしこれを行うと、決済を確定するボタンを押してからその結果を知るまで、その決済の注文の状態がわからなくなる時間が増えてしまいます。
例えば決済に2秒かかるとして、一気に1,000個注文が入った場合、注文が1個ずつしか処理されないので、1,000個注文目の人は30分近く結果を待たされてしまいます。なので、これも断念しました。
採用した方法は、トランザクションの分割です。在庫の減算と決済の2つにトランザクションを分割します。在庫の減算は悲観的ロックを取りながら在庫を減らすというトランザクションで、これは数百ミリ秒ぐらいの処理時間です。もう1つが悲観的ロックを取らずに決済確定APIを叩くトランザクションです。これはロックを取らないので並列に実行できますが、約2秒ほど長い時間がかかります。
この2つのトランザクションに分けることで、体験を変えずに決済処理を並列で行えるようになりました。
この処理の詳細な流れを説明します。1つ目が在庫管理トランザクションです。2つ目が決済確定トランザクションです。1つ目の在庫管理トランザクションでは、商品を管理している棚をイメージしてください。棚から商品を取り出せるのは1人ずつです。その棚からレジの横に商品を確保しておくというイメージで、在庫確保テーブルに商品情報を挿入します。
そのあと在庫減算を行って、いったんその処理をコミットします。次に在庫確保レコードを削除して、注文確定状態にして、決済確定APIを呼び出します。ここは、レジの横にどけておいた商品を実際にレジで決済を行うというイメージです。なので、ここは悲観的ロックが必要ありません。
これは正常系の流れです。ここでエラーが起きた時の流れをちょっと考えてみましょう。マイクロサービスパターンのSagaパターンの中に補償トランザクションがあるのですが、それと同じイメージで、決済トランザクションで失敗した時に、在庫トランザクションはすでにコミットされているので、それを手動で取り消す必要があります。
例えば決済トランザクションの最後で、決済APIが失敗したというケースを考えます。この場合、決算トランザクションは自動でロールバックされるのですが、在庫管理トランザクションはロールバックできないので、在庫管理トランザクションで行った処理の逆順の処理をすればOKです。なので、まず在庫で悲観的ロックを取ってから商品情報を削除して、在庫を加算します。
ここでもう1つ考えないといけないのは、この補償トランザクションで失敗した時のケースです。例えばRDBの障害などが考えられます。この場合、補償トランザクションが失敗してしまうので、べき等な操作にしておいて再実行可能にしておく必要があります。今回の場合、バッチで長時間残っている在庫を確保した商品については、もう一度同じ補償トランザクションを再実行するという方法で解決しています。
改善を入れる前は、最大分間注文数がだいたい400件ぐらいしか捌けなかったのですが、この改善によって分間2,000注文を捌けるようになりました。めでたしめでたしですね。
これは後日談なのですが、ある日突然BOOTH全体が重くなりました。注文自体は捌けていたのですが、CPUが100パーセント張り付くという障害が起きてしまいました。slimのレンダリングに時間がかかっていたことが原因でした。今まで注文が捌ききれていなかったので、ボトルネックになるところが移動したという感じです。
ここの処理を追いかけたところ、slimが遅いことがわかりました。ユーザーの設定によって表示する内容が変わるため部分的なキャッシュも難しく、今後はフロントで組み立てる方向に寄せていく予定です。
最後にまとめです。悲観的ロックを取るトランザクションの中で、時間のかかる処理をしないのが最善です。ただ、どうしても必要な場合があるので、その場合はトランザクションの分割を検討します。最後にDOMの組み立てはけっこう大変なので、今後はフロントにDOMの組み立ての処理を寄せていくのがよいかなと思っています。以上です。ありがとうございました。
司会者:金川さんの発表は以上です。ではこれから質疑応答に入っていきたいと思います。「決済と在庫の最終的な結果整合性はどうやって確認できているんですか?」とという質問です。
金川:整合性は、問い合わせベースがあるのと、もう1つ、スライドの中でも語っていたんですが、きちんとロールバックが行われているかを定期的なジョブで確認しているので、そこで「おかしいぞ?」となったらアラートが上がるようにしています。
司会者:ありがとうございます。次「使っているRDBは何ですか?」という質問がありました。
金川:弊社は基本的にMySQLを使っています。バージョンとしては5.6だったかな?
司会者:ありがとうございます。ではこちらの質問もお願いします。「整合性が取れなくなってしまう頻度はどの程度なのでしょうか?」
金川:整合性を2つの方法で確認していると話したと思うんですが、まず問い合わせベースはほぼ来たことがないです。トランザクションが失敗したケースも今まで1回起きたぐらいで、あとは自然に解消されています。
司会者:ありがとうございます。「ダミーのカードデータで大量に購入して、決済確定が失敗しまくった場合、在庫をゼロにできてしまう攻撃ができそうな気がしたのですが、在庫側のロールバックはどの程度の時間で完了するのでしょうか?」という質問が来ています。
金川:まず失敗した段階で、レスポンスを返すのと同じリクエストの中で一緒にロールバックをやっちゃおうという方針にしていて、そこで失敗しなかったケアとして、非同期でもう一度補償トランザクションを走らせるというかたちになっているので、その攻撃はたぶん成り立たないはずです。
司会者:なるほど。そのリクエスト中で失敗する確率はそこまで高くないだろうという感じですね。
金川:そうですね。DBとの接続が切れない限りという感じですね(笑)。
司会者:どうもありがとうございます。ここで金川さんの発表は終わりにしたいと思います。
2024.11.26
タスクの伝え方が部下のモチベーションを左右する マッキンゼー流、メンバーが動き出す仕事の振り方
2024.11.25
仕事はできるのに、なぜか尊敬されない人が使いがちな言葉5選 老害化を防ぐために大切な心構えとは
2024.11.27
何もせず月収1,000万円超…オンラインゲームにハマって起こした事業 大学中退し4社立ち上げ・2社売却した起業家人生
2024.11.25
論理的に「詰める」マネジメントでは本質的な解決にならない マッキンゼー流、メンバーの理解と納得を得る接し方
2024.11.28
管理職の「疲弊感」がメンバーに伝わるリスク 部下の「働きがい」を育む6つのポイント
2024.11.29
「明日までにお願いできますか?」ちょっとカチンとくる一言 頭がいい人に見える上品な言い方に変えるコツ
2024.11.27
部下に残業させられず、自分の負担ばかり増える管理職 組織成長のカギを握る「ミドル層」が抱える課題
2024.11.27
仕事中の「今ちょっといいですか」が苦痛… いしかわゆき氏が語る、ADHD気質にマッチした働き方のヒント
2024.11.26
仕事の質を左右する「ムダな習慣」トップ5 忙しくなる前に棚卸ししたい“やめたほうがいいこと”とは
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
ログミーBusiness リニューアル記念イベント開催
2024.11.29 - 2024.11.29
品がある人、育ちがいい人の見える 人のセリフ 3選
2022.11.30 - 2022.11.30
ミドル層が組織成長のキーになる!〜働きがいを高める、一生働きたい職場の作り方〜
2024.09.25 - 2024.09.25
新しい事業創出のヒントはスタートアップにあり! ~著者に聞く、今こそ知りたいスタートアップの世界~
2024.10.23 - 2024.10.23
Next Innovation Summit 2024 in Autumn
2024.11.01 - 2024.11.01