1
/
5

【TECH BLOG】DynamoDBによるOutboxパターンとCDCを用いたCQRSアーキテクチャの実装〜ZOZOMOでの取り組み

こんにちは。ブランドソリューション開発部プロダクト開発ブロックの岡元です。普段はFulfillment by ZOZOとZOZOMOのブランド実店舗の在庫確認・在庫取り置きサービスの開発、保守をしています。

本記事では、ブランド実店舗の在庫確認・在庫取り置きサービスで実装したCQRSアーキテクチャについて紹介させていただきます。

CQRSの実装においては、データベース(以下、DB)分割まで行い、コマンド側DBにはAmazon DynamoDB(以下、DynamoDB)、クエリ側DBにはAmazon Aurora MySQL(以下、Aurora MySQL)を用いています。また、コマンド側DBとクエリ側DBの橋渡しを担うメッセージングにおいてはOutboxパターンと変更データキャプチャを用いました。DBとメッセージングシステムへの二重書き込みを避けることで障害などのタイミングで顕在化する潜在的なデータ不整合を回避しています。本記事がCQRS実装の一事例として参考になれば幸いです。

ブランド実店舗の在庫確認・在庫取り置きサービスとは

ブランド実店舗の在庫確認・在庫取り置きサービス(以下、店舗在庫連携サービス)は、2021年11月に発表したOMOプラットフォーム「ZOZOMO」が展開するサービスの1つです。お客様は、ZOZOTOWN上でブランド実店舗の在庫を確認できることに加え、在庫の取り置きもできます。ZOZOMOのサービスに詳細ついては、こちらのプレスリリースで紹介しております。

CQRSの概要

店舗在庫連携サービスでは、アーキテクチャにCQRSを採用しました。CQRSは、コマンド(書き込み)とクエリ(読み取り)の操作を分離するパターンです。

CQRSを用いることで、コマンド側のモデルとクエリ側のモデルを分けて管理できます。複雑なビジネスロジックが必要とされることの多い書き込み操作を読み取り操作の関心事から分離することで、それぞれのモデルを比較的シンプルに保つことができます。

コマンドとクエリで共通のDBを用いることもできますが、別々のDBを用いることも可能です。コマンドとクエリでDBを分割した場合はコマンド側のDBからクエリ側のDBに更新を同期する必要があり、システム全体としてはより複雑になります。

CQRSパターンの詳細については、Microsoft社の以下記事で詳しく説明されているので、そちらを参照してください。


CQRS パターン - Azure Architecture Center
CQRS はコマンド クエリ責務分離を表し、データ ストアの読み取りと更新の操作を分離するパターンです。 アプリケーション内に CQRS を実装すると、そのパフォーマンス、スケーラビリティ、セキュリティが最大化される場合があります。 CQRS への移行によって生まれる柔軟性により、システムは時間の経過と共にさらに進化し、更新コマンドでドメイン レベルのマージ競合が発生することを防ぐことができます。 従来のアーキテクチャでは、データベースの更新とクエリに同じデータ モデルが使用されます。 このシンプルな方法
https://docs.microsoft.com/ja-jp/azure/architecture/patterns/cqrs


店舗在庫連携サービスにおけるCQRSの利点

店舗在庫連携サービスではドメイン駆動設計(以下、DDD)を参考に開発しており、ビジネスロジックを反映したドメインモデルをなるべくシンプルに保つという思想で設計を進めました。また、DDDにおける集約の状態の保存にDynamoDBを用いています。DynamoDBを用いている理由についてはメッセージングが関係しています。詳細は後述します。

また、店舗在庫連携サービスは既存のZOZOTOWN内に組み込む形でサービスを提供しており、以下のように利用目的が異なる3種類のサービスから利用される予定がありました。そのため、将来的にも多種多様なクエリを処理できる必要があると予想されました。

  • ZOZOTOWN - お客様が、実店舗の在庫確認、在庫の取り置き依頼などを行う
  • FAANS - 店舗スタッフが、確保が必要な在庫などを確認する
  • ZOZOTOWNのバックオフィスシステム - カスタマーサポートが、お客様や店舗スタッフからの問い合わせを受け、取り置き依頼状況の確認などを行う

これを踏まえ、店舗在庫連携サービスでは、主に以下の点が利点になると考えCQRSを採用しました。

  • DBを分割することによる柔軟なクエリの実現、処理効率の向上
  • モデルを分割することによるモデルの保守性、処理効率の向上

DBを分割することによる柔軟なクエリの実現、処理効率の向上

前述の通り、店舗在庫連携サービスでは、DDDにおける集約の状態の保存にDynamoDBを用いています。

しかし、多種多様で複雑なクエリを処理するのが困難なDynamoDBでこのようなクエリを実現しようとすると非効率な実装をせざるを得ない懸念がありました。同様に、モデルの観点からも、集約を処理の基本単位とするドメインモデルで集約をまたぐクエリを実現しようとすると非効率な実装となる懸念がありました。

CQRSを用いることでコマンド側とクエリ側のDBを分割し、それぞれ別々のDBを用いることができるようになります。クエリ側のDBにはAurora MySQLを用いることで、柔軟なクエリを実現できるだけでなく効率的にクエリを処理できると考えました。

モデルを分割することによるモデルの保守性、処理効率の向上

前述の通り、店舗在庫連携サービスでは、ビジネスロジックを反映したドメインモデルをなるべくシンプルに保つという思想で設計を進めました。

しかし、多種多様な要件を持つクエリの関心事にドメインモデルが巻き込まれることで、必要以上にモデルが複雑となる恐れがありました。

CQRSを用いることで、ドメインモデルからクエリの関心事を分離し、コマンドとクエリでそれぞれ別々のモデルを作成できます。モデルを分割することで、それぞれ以下のような利点があると考えました。

  • ドメインモデル(コマンド側)- ビジネスロジックに集中することで、モデルをより洗練させることができる
  • クエリモデル(クエリ側)- シンプルなモデルになり、効率的に処理を行うことができる

店舗在庫連携サービスにおけるCQRSの実装

以下に店舗在庫連携サービスの構成図を示します。

上図の通り、店舗在庫連携サービスでは、コマンド側DBとクエリ側DBにそれぞれDynamoDBとAurora MySQLを用いています。DynamoDBからAurora MySQLへのデータの同期にはAmazon Kinesis Data Streams for DynamoDB(以下、Kinesis Data Streams for DynamoDB)を用いました。

各モデルについては、コマンド側のドメインモデルはクエリの関心事を気にせず実装できたことで、より洗練されたモデルにできました。クエリ側のモデルもDBにAurora MySQLを用い、リクエストに対応するSQLをほぼそのまま実行し、結果を返すような構成にすることでよりシンプルで効率的なモデルになりました。

また、今回、非同期的な処理ではDDDにおけるドメインイベントを参考にしました。ドメインイベントを用いることで、ドメイン内で発生する何かの出来事についても重要なドメインモデルの一部として扱うことができました。ドメインイベントはKinesis Data Streams for DynamoDBによって送出され、クエリ側DBの更新に用いられています。それだけでなく、メール送信や外部サービスへの連携などのドメインイベントを契機に発生する処理の実行にも利用できました。

CQRSにおけるコマンド側の構成概要

以降では、店舗在庫連携サービスの開発で特に工夫したコマンド側の構成について紹介させていただきます。

メッセージングのためのDynamoDB

店舗在庫連携サービスで行う処理には以下のようなものがあります。

  • 在庫の取り置きがされたとき

・お客様へ、取り置き依頼を受け付けた旨のメールを送信する
・FAANSのシステムへ、店舗在庫の確保を依頼する旨の通知を送る
・外部サービスへ、取り置き依頼された商品の在庫情報を連携する

  • 店舗で商品の在庫が確保されたとき

・お客様へ、来店の準備が完了した旨のメールを送信する

これらはドメイン内で発生する出来事であるドメインイベントが契機となり、非同期的に実行される処理です。こういったイベントの発生を元に実行される処理は、店舗在庫連携サービスにおいて多く存在しました。

そこで、DynamoDBの変更データキャプチャ機能(今回はKinesis Data Streams for DynamoDB)とトランザクション書き込みを利用したOutboxパターンによってメッセージングを実現しました。

コマンド側DBにDynamoDBを用いたのは、以下のような理由からです。

  • 変更データキャプチャが第一級のインタフェースとしてサポートされており、容易に利用できる
  • 複数テーブルをまたぐトランザクション書き込みをサポートしているため、Outboxパターンと変更データキャプチャによるメッセージングを容易に実現できる

変更データキャプチャやOutboxパターンは他のDBでも実現できます。しかし、変更データキャプチャを第一級のインタフェースとしてサポートしないDBでは、効率的な変更データキャプチャを利用するためにDebeziumなどのツールや追加のサービスを導入する必要があります。このようなツールやサービスの導入により追加のメンテナンスコストが発生してしまう懸念があったため、店舗在庫連携サービスではDynamoDBを利用しました。

続きはこちら

株式会社ZOZO's job postings

AWS

Weekly ranking

Show other rankings
If this story triggered your interest, go ahead and visit them to learn more