今回読んだ記事はこちらです。
mercari engineering 「メルカリShops 注文システム反省会」
■ リリース当初の注文システムの設計
-
メルカリShopsでは、注文受付システムをマイクロサービスで構成している
-
リリース当初は以下のように設計されていた。
- オーケストレーションを行うCloud wokkflowから、注文処理を行うOrder Serviceを呼び出す
- Order Serviceは以下のマイクロサービスを非同期的に呼び出す
- 在庫を確保する(Product Service)
- 配送先情報を登録する(Shopping Service)
- 購入代金を仮押さえする(Payment Service)
- 購入代金を確定する(Payment Service)
- メールを送信する(Notification Service)
- 注文を確定する
-
「データベースが瞬間的に利用不可」などのRetryableなエラーが発生した場合は、API処理をリトライする
-
以下のような場合に、注文取消処理を行う
- クレジットカードの残高不足などnon-retryableなエラーが発生した場合
- リトライの上限回数に達した場合
- 処理がタイムアウトした場合
■ リリース当初の設計の問題点
-
大抵の場合はこの設計で問題なかったが、いくつか修正されるべき問題も見つかった。
1. 店舗に商品発送依頼メールが送信されたのに、注文が取り消しされる-
注文処理の最後のフェーズでは、店舗に商品発送依頼メールを送信した後、データベースを「注文確定」のステータスに更新している
-
瞬間的な大量のアクセス増を受けた際にデータベースが不安定になり、注文メールが送信された後にデータベースの更新に失敗したままリトライ回数の上限に達し、注文が取消される事象が発生した。
→ 店舗に商品発送依頼メールが送信されているのに、注文が取り消しされているという不整合が生じている。
2. 注文取消の発生率が上がる
- non-retryableなエラーが発生した場合に注文取消処理を行うように設計していたが、中長期的な運用を考えると以下の問題がある
- 注文処理の改修で呼び出すAPIは増えていくことになるが、呼び出すAPIが増えていくたびに注文処理全体の成功率が低下していき、注文取消の発生率が上がる構造になっている
- そもそもエラー1つで注文取消される仕組みは機会損失を増やす構造になっている
3. 購入代金の決済のキャンセルに失敗することがある
-
決済時に行われる購入代金の仮押さえ処理(チャージ処理)は決済代行会社の処理にも依存していて、比較的時間がかかる
→ 場合によってはリクエストの処理時間内で終了せず、処理中のままタイムアウトになってしまう -
以下のようにして問題が発生する
-
チャージ処理でタイムアウトになった場合にAPI処理がリトライされるが、チャージ処理中の状態が続き、やがてリトライの上限回数に達する
→ 注文取消処理が実行される -
注文取消処理の中でチャージ処理のキャンセルも行われるが、まだチャージ処理中で、未確定のチャージをキャンセルできないのでリクエストが失敗する
→ リトライが行われるが、ここでもリトライ上限回数に達するかタイムアウトで、注文取り消し処理自体が失敗して終了する -
その後、非同期に行われていたチャージ処理が成功し、購入代金が仮押さえされた状態で注文が残ってしまうという不整合が生じる
-
-
■ 注文システムの設計の改修案
-
注文システムを見直し、設計の改修案を考える
-
注文システムを構成する処理は次のように分類される
- リソースを仮押さえする(仮押さえ)
- 仮押さえに成功したものを確定する(確定)
- キャンセルを行い、仮押さえを取り消す(取り消し)
- 注文確定後、付帯的な処理を行う(付帯処理)
-
購入代金を仮押さえする処理は注文の成否に影響を与える
→ 購入代金の仮押さえがエラーになる場合(例: 残高不足)は注文不成立となり、仮押さえに成功した場合は注文成立となる
→ この処理のみ、タイムアウトのエラーを考慮する -
購入代金の仮押さえ処理後は既に注文が成立しているため、確定処理/取消処理/付帯処理はリクエスト成功完了までリトライを行うようにした方が良い
-
-
上記の設計案で、リリース当初の設計の問題が解決されるのか確認する
1. 店舗に商品発送依頼メールが送信されたのに、注文が取り消しされる- メール送信を付帯処理として実行するが、この段階では注文確定後の状態なので注文取消されることはない
2. 注文取消の発生率が上がる
- 仮押さえ処理のみリクエスト成否を考慮し、注文取消につながるAPIの数を最小に絞っている
→ 新たにAPIが追加されても、注文確定後に実行される付帯処理として実行するので、注文の成功率に影響を与えない
3. 購入代金の決済のキャンセルに失敗することがある
- 注文取消処理は成功するまでリトライを重ねるように変更したため、チャージ処理後のタイミングまで取消処理がリトライされるようになっている
■ 設計の改修計画
- 新たなアーキテクチャに移行すれば問題は解決するが、実際に行うにはコストもリスクも大きいため計画的に進める必要がある
→ 以下の対応を行なっている- 注文システムリリース当初の設計の問題点を洗い出し、タスクに分解
- インシデントリスクの高いものやお客様影響のあるものなど、投資効果の高い順にタスクを消化していく