Movatterモバイル変換


[0]ホーム

URL:


$30 off During Our Annual Pro Sale. View Details »
Speaker DeckSpeaker Deck
Speaker Deck

データの整合性を保つ非同期処理アーキテクチャパターン / Async Architecture...

Avatar for mokuo mokuo
February 14, 2025

データの整合性を保つ非同期処理アーキテクチャパターン / Async Architecture Patterns

Developers Summit 2025 公募セッション "データの整合性を保つ非同期処理アーキテクチャパターン"
https://event.shoeisha.jp/devsumi/20250213/session/5585
---

1つの業務が一連のイベント(出来事)から構成されるシステムというものがあります。非同期処理を含むこともあるでしょう。
このような機能を開発・運用していると、以下のような課題に直面することがあります。

・処理の流れが把握し辛い
・変更を行うのが困難
・データの整合性を担保するのが難しい

しかし、適切に設計を行うことで、これらの課題を回避することができます。
本セッションでは、弊社が運営する B/43 アプリのカード発行フローなどを例に、上記の課題を解消するアーキテクチャのパターンを紹介します。

Avatar for mokuo

mokuo

February 14, 2025
Tweet

More Decks by mokuo

See All by mokuo

Other Decks in Programming

See All in Programming

Featured

See All Featured

Transcript

  1. データの整合性を保つ
 非同期処理アーキテクチャパターン 
 2025.2.14


  2. 自己紹介
 2

  3. 3 SmartBank, Inc. 
 Engineer 
 木田 悠一郎
 @mokuo_
 @mokuo


    SIer : 基幹業務システム → Rails 受託開発
 → Sansan株式会社 : データを扱う部署で複数システム
 → 株式会社スマートバンク : カード決済 / あとばらい領域

  4. 4

  5. 5

  6. 6 6

  7. 7 7

  8. 本日お話しすること
 8

  9. 本日お話しすること
 一連のイベント から構成される業務
 9 例) B/43 カード発行処理のイメージ(実際のフローとは異なります)
 非同期処理 を含むこともある


  10. ç ç ç 10 本日お話しすること
 処理の流れ が
 把握し辛い
 変更を行うのが
 難しい


    データ整合性の
 担保が困難
 直面する課題

  11. 11 本日お話しすること
 適切に設計を行うことで、
 これらの課題を回避することができます
 本日は、上記の課題を解消する
 アーキテクチャのパターン を紹介します
 ❏ 処理の流れが把握し辛い
 ❏

    変更を行うのが難しい
 ❏ データ整合性の担保が困難

  12. 12 アジェンダ
 1. イベントを正しく保存する
 2. イベント間の整合性を保つ
 3. データベースとメッセージキューの整合性を保つ
 4. メッセージのスキーマを定義する


    ポイントは4つ!

  13. イベントを正しく保存する
 13

  14. 14 非同期処理の前後では何らかのデータを
 保存することが多い
 モノリスでもマイクロサービスでも、
 まずはしっかりモデリング を行うことが大切
 イベントを正しく保存する


  15. イベントを正しく保存する
 • イベント
 ◦ 日付を生成条件としているモノ 
 • リソース
 ◦ イベント以外のモノ


    モノを2種類に分ける
 15 出典: 事業分析・データ設計のためのモデル作成技術入門:書籍案内|技術評論社 https://gihyo.jp/book/2022/978-4-297-12946-0

  16. 16 イベントを正しく保存する
 • 出来事の結果として生起した、持続するモノに帰属している日付
 ◦ ❌ 従業員入社日、部門設立日など
 • データ管理のための将来日
 ◦

    ❌ 有効日、適用日など
 • データ管理のための過去日
 ◦ ❌ 登録日、更新日など
 イベントに帰属する日付は事象が生起した過去日
 ※ 以下はイベントの日付ではない
 = 受注日、発送日、請求日、入金日 など

  17. イベントを正しく保存する
 ※ 便宜上、実際のカード発行フローを簡略化したものになっていますので、ご注意ください
 17

  18. イベント毎にテーブルを作成する
 イベントを正しく保存する
 関連イベントID の持ち方にはいくつかのパターン があります
 18

  19. • 👍 メリット
 ◦ イベントの順序が明確になり、外部キー制約などを活用できる
 • 👎 デメリット 
 ◦

    イベントの関連を1つずつ辿っていく必要がある
 パターン① : 1つ前のイベントのIDを持つ
 19 イベントを正しく保存する

  20. ※ 便宜上、実際のカード発行フローを簡略化したものになっていますので、ご注意ください
 フローが分岐する場合
 20 イベントを正しく保存する


  21. パターン② : 最初のイベントのIDを持つ
 21 • 👍 メリット
 ◦ イベント分岐に対応できる、関連イベントを一気に引ける
 •

    👎 デメリット 
 ◦ イベントの順序をテーブルだけで表現できない
 イベントを正しく保存する

  22. ※ 便宜上、実際のカード発行フローを簡略化したものになっていますので、ご注意ください
 複雑なフローの場合 
 
 22 イベントを正しく保存する


  23. パターン③ : ロングタームイベント
 23 最新のステータス 
 各イベントのスーパータイプ 
 • 👍

    メリット
 ◦ 最新のステータスを管理できる、複雑なイベント分岐に対応可能
 • 👎 デメリット 
 ◦ テーブルだけでイベント順序を表現できない
 イベントを正しく保存する

  24. 『WEB+DB PRESS Vol.130』の特集1
 第4章で紹介されているパターン
 パターン③ : 
 ロングタームイベント
 出典: WEB+DB

    PRESS Vol.130|技術評論社 https://gihyo.jp/magazine/wdpress/archive/2022/vol130
 24 イベントを正しく保存する

  25. 25 パターン④ : ツリー構造で持つ
 イベントを正しく保存する
 辿ってきたイベントのIDをスラッシュ区切りでカラムに持たせる
   例) 入金待ち   : カード発行申請ID/入金待ちID
   例)

    カード発行審査: カード発行申請ID/入金待ちID/カード発行審査ID

  26. • 👍 メリット
 ◦ 関連するイベントを柔軟に引くことができる
 • 👎 デメリット 
 ◦

    ライブラリがない言語では実装にコストがかかる
 Ruby では ancestry という gem があり
 簡単に導入することができる
 出典: stefankroes/ancestry: Organise ActiveRecord model into a tree structure https://github.com/stefankroes/ancestry
 26 パターン④ : 
 ツリー構造で持つ
 イベントを正しく保存する

  27. 書籍『SQL アンチパターン』で 経路列挙モデル として紹介されている手法
 パターン④ : 
 ツリー構造で持つ
 27 出典:

    SQLアンチパターン - O'Reilly Japan https://www.oreilly.co.jp/books/9784873115894/
 イベントを正しく保存する

  28.    関連するイベントの数や複雑さに応じて、
 
 
 
   の順に検討してみる!
 パターンまとめ
 28 パターン① : 1つ前のイベントのIDを持たせる


    パターン② : 最初のイベントのIDを持たせる
 パターン③ : ロングタームイベント
 要件によって 
 ”パターン④:ツリー構造で持たせる”パターンも検討すると良い
 イベントを正しく保存する

  29. 複数の責務、概念が混ざり合っている
 
 null カラムが生じる
 イベントを正しく保存する
 NGパターン: 全部盛りモデル
 29 カード発行
 PK


    ID
 ユーザーID
 カードID
 ステータス
 カード名義
 配送先
 申請日時
 発行日時
 発送日時
 利用開始日時

  30. イベントを正しく保存する
 • 仕様変更に対応しやすくなる
 ◦ 例) 複数カードまとめて発行したい
 Q. テーブルが増えると
   複雑になるのでは?


    30
  31. イベントを正しく保存する
 • 複雑さを分けて考える
 ◦ 一つのモデルに含まれる複雑さは分割す ることで回避できる 
 ◦ 複数のモデルが持つ複雑さは業務本来 が持つ複雑さなので回避できない

    
 Q. テーブルが増えると
   複雑になるのでは?
 31
  32. イベントを正しく保存する
 • テーブルを更新する際はロックで排他 制御を行う必要がある
 ◦ 更新が必要なテーブルと不要な テーブルを分けることでロックの開 放待ち発生しにくくなる
 Q. JOIN

    が増えてクエリが  遅くならない?
 32
  33. モデリングについては、こちらも合わせてご参照ください
 33 https://speakerdeck.com/mokuo/shui-gazuo-cheng-sitemo1tunogou-zao-ninarumoderinguzuo-cheng-ji-shu-theory-of-models-nimeng-wojian-ru


  34. イベント間の整合性を保つ
 34

  35. 35 非同期メッセージングを導入する目的
 可用性
 を上げる
 パフォーマンス 
 を上げる
 イベント間の整合性を保つ


  36. 「可用性」 の定義
 
 ” システムがどれくらいの期間利用できるか 
 (24 時間 365 日稼働する場合には、障害が発

    生した場合に迅速にシステムを稼働できるよう にするための措置が必要となる) ”
 
 出典:ソフトウェアアーキテクチャの基礎 - O'Reilly Japan https://www.oreilly.co.jp//books/9784873119823/
 36 イベント間の整合性を保つ

  37. 37 例) B/43 システムアーキテクチャ
 イベント間の整合性を保つ


  38. 例) カード発行処理を簡略化して説明
 カード管理
 システム
 アプリ
 バックエンド
 家計簿
 アプリ
 38 イベント間の整合性を保つ


  39. ユーザーに待ち時間が発生
 39 カード管理
 システム
 アプリ
 バックエンド
 家計簿
 アプリ
 同期通信の場合
 イベント間の整合性を保つ


  40. カード管理システムで障害が発生
 した場合、依存する機能が停止 する
 40 カード管理
 システム
 アプリ
 バックエンド
 家計簿
 アプリ


    同期通信の場合
 イベント間の整合性を保つ

  41. 41 裏側で非同期通信を行うことで、
 パフォーマンス と可用性が向上する
 
 カード管理
 システム
 アプリ
 バックエンド
 家計簿


    アプリ
 非同期通信の場合
 非同期
 イベント間の整合性を保つ

  42. 42 裏側で非同期通信を行うことで、
 パフォーマンス と可用性が向上する
 
 カード管理
 システム
 アプリ
 バックエンド
 家計簿


    アプリ
 非同期通信の場合
 非同期
 ⚠ ただし、デメリット もある
 イベント間の整合性を保つ

  43. 43 DBトランザクションの
 ACID 特性
 • 原子性(Atomicity)
 ◦ 全て成功 or 失敗


    • 一貫性(Consistency)
 ◦ 全ての制約が満たされた状態
 • 独立性(Isolation)
 ◦ 直列に実行した場合と結果が同じ
 • 耐久性(Durability)
 ◦ コミット完了したデータが消失しない
 出典:理論から学ぶデータベース実践入門 ―― リレーショナルモデルによる効率的な SQL|技術評論社 https://gihyo.jp/book/2015/978-4-7741-7197-5
 
 イベント間の整合性を保つ

  44. 44 どちらか一方のみ失敗することがある
 カード管理
 システム
 アプリ
 バックエンド
 家計簿
 アプリ
 非同期通信の場合
 非同期


    イベント間の整合性を保つ

  45. ç ç ç 45 リトライ
 最初から
 実行し直す 
 ロールバック 


    (もとに戻す)
 非同期処理に失敗した時、以下のいずれかの対応を行う必要がある
 イベント間の整合性を保つ

  46. 46 イベント間の整合性を保つ
 出典:Saga パターン - Azure Design Patterns | Microsoft

    Learn https://learn.microsoft.com/ja-jp/azure/architecture/patterns/saga
 • コレオグラフィ
 • オーケストレーション
 整合性担保のための2つのアプローチ
 マイクロサービス における概念だが、モノリスでも参考にできる

  47. 47 • 👍 メリット
 ◦ 調整ロジックが不要
 ◦ 単純なフローに適している
 • 👎

    デメリット 
 ◦ ステップが増えると複雑になる
 コレオグラフィ
 イベント間の整合性を保つ
 出典:Saga パターン - Azure Design Patterns | Microsoft Learn https://learn.microsoft.com/ja-jp/azure/architecture/patterns/saga

  48. 48 オーケストレーション
 イベント間の整合性を保つ
 出典:Saga パターン - Azure Design Patterns |

    Microsoft Learn https://learn.microsoft.com/ja-jp/azure/architecture/patterns/saga
 • 👍 メリット
 ◦ 全体を管理しやすい
 ◦ 複雑なフローに適している
 • 👎 デメリット 
 ◦ オーケストレーターにロジックが集中する

  49. 49 オーケストレーション
 イベント間の整合性を保つ
 出典:Saga パターン - Azure Design Patterns |

    Microsoft Learn https://learn.microsoft.com/ja-jp/azure/architecture/patterns/saga
 オーケストレーターとして
 マネージドサービスを導入する
 • AWS
 ◦ AWS Step Functions
 • GCP
 ◦ Workflows
 • Azure
 ◦ Azure Logic Apps

  50. 50 オーケストレーション
 イベント間の整合性を保つ
 出典 : chaps-io/gush: Fast and distributed workflow

    runner using ActiveJob and Redis https://github.com/chaps-io/gush
 ちなみに・・・
 Ruby には gush という gem があり、
 Redis か ActiveJob を使ってワークフローを組 むことができる

  51. オーケストレーターとして使えるマネージドサービス
  ※ 右図はイメージです
   実際の B/43 カード発行フローとは異なるためご注意ください
 51 例) AWS Step

    Functions
 ECS タスク実行や SQS メッセージ送信なども 可能

  52. オーケストレーターとして使えるマネージドサービス
 AWS マネジメントコンソールで実行状況が分か りやすく表示される
 52 例) AWS Step Functions
  ※

    右図はイメージです
   実際の B/43 カード発行フローとは異なるためご注意ください

  53. オーケストレーターとして使えるマネージドサービス
 53 例) AWS Step Functions
 • どこでエラーになったか分かる
 • リトライやエラーハンドリング

    可能
  ※ 右図はイメージです
   実際の B/43 カード発行フローとは異なるためご注意ください

  54. データベースとメッセージキューの
 整合性を保つ
 54

  55. 55 DBトランザクションの
 ACID 特性
 • 原子性(Atomicity)
 ◦ 全て成功 or 失敗


    • 一貫性(Consistency)
 ◦ 全ての制約が満たされた状態
 • 独立性(Isolation)
 ◦ 直列に実行した場合と結果が同じ
 • 耐久性(Durability)
 ◦ コミット完了したデータが消失しない
 出典:理論から学ぶデータベース実践入門 ―― リレーショナルモデルによる効率的な SQL|技術評論社 https://gihyo.jp/book/2015/978-4-7741-7197-5
 
 データベースとメッセージキューの整合性を保つ

  56. 56 DB にデータを保存しつつ
 メッセージを送信したいことがある
 
 カード管理
 システム
 アプリ
 バックエンド
 家計簿


    アプリ
 非同期通信の場合
 非同期
 データベースとメッセージキューの整合性を保つ

  57. DB トランザクションとメッセージ送信はどちら か一方だけ失敗する可能性がある
 57 データベースとメッセージキューの整合性を保つ


  58. DB トランザクションとメッセージ送信はどちら か一方だけ失敗する可能性がある
 58 データベースとメッセージキューの整合性を保つ


  59. DB トランザクションとメッセージ送信はどちら か一方だけ失敗する可能性がある
 59 データベースとメッセージキューの整合性を保つ


  60. 60 システム間で整合性が 取れない状態になる
 カード管理
 システム
 アプリ
 バックエンド
 家計簿
 アプリ
 どちらか一方のみ失敗


    非同期
 データベースとメッセージキューの整合性を保つ

  61. データベースとメッセージキューの整合性を保つ
 出典: マイクロサービスパターン 実践的システムデザインのためのコード解説 - インプレスブックス
 https://book.impress.co.jp/books/1118101063
 61 “ データベーストランザクションの一部として

    データベースの OUTBOX テーブルにイベン トやメッセージを保存することによってメッ セージをパブリッシュする “ (https://microservices.io/patterns/data/transactional- outbox.html 参照)
 Transactional outbox
 パターン

  62. 62 OUTBOX テーブルを読み、メッセージ をパブリッシュする方法として、さらに2 つのパターンがある Transactional outbox
 パターン
 データベースとメッセージキューの整合性を保つ
 出典:

    マイクロサービスパターン 実践的システムデザインのためのコード解説 - インプレスブックス
 https://book.impress.co.jp/books/1118101063

  63. ワーカー常時起動、バッチ定期実行など
 63 “ データベースの OUTBOX テーブルを ポーリングしてメッセージをパブリッシュす る ” (https://microservices.io/patterns/data/polling-pub

    lisher.html 参照)
 パターン① : 
 Polling publisher
 OUTBOX テーブルからメッセージをパブリッシュする方法
 出典: マイクロサービスパターン 実践的システムデザインのためのコード解説 - インプレスブックス
 https://book.impress.co.jp/books/1118101063

  64. 64 “ トランザクションのログをテーリングして データベースに加えられた変更をパブリッ シュする ” (https://microservices.io/patterns/data/transaction -log-tailing.html 参照)
 パターン②

    : 
 Transaction log tailing
 出典: マイクロサービスパターン 実践的システムデザインのためのコード解説 - インプレスブックス
 https://book.impress.co.jp/books/1118101063
 例) MySQL の binlog、
   PostgresQL の WAL など
 OUTBOX テーブルからメッセージをパブリッシュする方法

  65. 65 出典: マイクロサービスパターン 実践的システムデザインのためのコード解説 - インプレスブックス
 https://book.impress.co.jp/books/1118101063
 いくつかの例が書籍で紹介されている
 • Debezium

    / Eventuate Tram
 ◦ DB への変更を Apache Kafka にパブ リッシュ
 • LinkedIn Databus
 ◦ Oracle トランザクションログ
 • DynamoDB streams
 OUTBOX テーブルからメッセージをパブリッシュする方法
 パターン② : 
 Transaction log tailing

  66. 66 補足: 重複するメッセージの処理
 例) Amazon SQS
 出典 : サーバーレスにおけるべき等性の実装 (メッセージ編)|

    AWS 
 https://aws.amazon.com/jp/builders-flash/202106/serverless-idempotency-implementation/
 • 標準キュー 
 ◦ At-Least-Once Delivery
 • FIFOキュー
 ◦ Exactly-Once-Processing
 どちらのタイプでもメッセージ削除に
 失敗すると複数回処理されることがある

  67. 67 補足: 重複するメッセージの処理
 対処方法は2つ
 1. べき等なメッセージハンドラを作る
 2. 重複するメッセージを捨てる
 出典: マイクロサービスパターン

    実践的システムデザインのためのコード解説 - インプレスブックス
 https://book.impress.co.jp/books/1118101063

  68. メッセージのスキーマを定義する
 68

  69. メッセージのスキーマを定義する
 非同期メッセージングを行う場合
 JSON 形式を使うことが多い
 69

  70. メッセージのスキーマを定義する
 JSON Schema でスキーマを定義し、バ リデーション を行うことで堅牢な非同期 処理を実現できる
 (https://json-schema.org/ 参照)
 70

  71. メッセージのスキーマを定義する
 https://json-schema.org/tools から 探すことができる
 例えば Ruby には json-schema とい う

    gem ライブラリがある
 (https://github.com/voxpupuli/json-schema 参照)
 71 JSON Schema バリデーター

  72. おわりに
 72

  73. おわりに
 一連のイベント から構成される業務
 73 例) B/43 カード発行処理のイメージ(実際のフローとは異なります)
 非同期処理 を含むこともある


  74. ç ç ç 74 おわりに
 処理の流れ が
 把握し辛い
 変更を行うのが
 難しい


    データ整合性の
 担保が困難
 直面する課題

  75. 75 おわりに
 1. イベントを正しく保存する
 2. イベント間の整合性を保つ
 3. データベースとメッセージキューの整合性を保つ
 4. メッセージのスキーマを定義する


    ポイントは4つ!

  76. ç ç ç 76 おわりに
 開発生産性 
 保守運用コスト 
 事業成長スピード

    
 これらの改善にもつながる

  77. 77 ご清聴ありがとうございました!



[8]ページ先頭

©2009-2025 Movatter.jp