Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ウォレットアプリKyashの先 〜 Kyash Directのアーキテクチャ

ウォレットアプリKyashの先 〜 Kyash Directのアーキテクチャ

builderscon tokyo 2019で登壇した際の資料です。

Kyash Directのアーキテクチャについて
- スクラッチ開発を決めた経緯
- アーキテクチャ決定までの試行錯誤
- 関連トピック
- Microservices
- DDD
- AsyncMessaging
- Choreography
- EventDriven
- EventSourcing
- SagaPattern

岩藤圭介

August 30, 2019
Tweet

More Decks by 岩藤圭介

Other Decks in Technology

Transcript

  1. 1 Intro / Logo ウォレットアプリ Kyash の先 Kyash Direct のアーキテクチャ

    株式会社 Kyash 岩藤 圭介(keisuke iwado) twitter: @k315k1010
  2. 2 • DDD、CleanAcrchitecture等にお ける個々の設計トピックの詳細な掘 り下げ • 具体的な実装方法、コーディング ウォレットアプリ Kyash の先

    Kyash Direct のアーキテクチャ • KyashやKyash Directに興味を もっていただく • 実務を通じて感じたMicroservices アーキテクチャのハマりどころ、注意 した方が良いことを抑えていただく この発表のゴール お話ししないこと
  3. 目次 01. 株式会社 Kyash について 02. ウォレットアプリ Kyash について 03.

    Kyash Direct について 04. Kyash Direct のスクラッチ開発を決意するまで 05. 設計の試行錯誤 06. どう実現しているか 07. まとめ 08. 質疑応答(?) 3
  4. 目次 01. 株式会社 Kyash について 02. ウォレットアプリ Kyash について 03.

    Kyash Direct について 04. Kyash Direct のスクラッチ開発を決意するまで 05. 設計の試行錯誤 06. どう実現しているか 07. まとめ 08. 質疑応答(?) 4
  5. 目次 01. 株式会社 Kyash について 02. ウォレットアプリ Kyash について 03.

    Kyash Direct について 04. Kyash Direct のスクラッチ開発を決意するまで 05. 設計の試行錯誤 06. どう実現しているか 07. まとめ 08. 質疑応答(?) 10
  6. 12 カード(クレジット/デビット) コンビニ 銀行 ポイント/ ギフト / リワード チャージ Kyash

    の特徴 • いろいろな方法でチャージ(コンビニ・ ATM・カード(手動/自動)・ポイント) • 一瞬で送金 • Visa加盟店でお買い物 • 利用状況をリアルタイムに • キャッシュバックがあって お得
  7. 目次 01. 株式会社 Kyash について 02. ウォレットアプリ Kyash について 03.

    Kyash Direct とは 04. Kyash Direct のスクラッチ開発を決意するまで 05. 設計の試行錯誤 06. どう実現しているか 07. まとめ 08. 質疑応答(?) 14
  8. 15 Kyash Direct とは • 企業向けのSaaS製品です • オリジナルデザインの Visaカードを、多様な形態で、安価かつスピーディに発行することができます •

    会員管理、カード発行、残高管理、取引履歴照会、等の機能を WebAPIで提供します • 法人向けカードの発行も可能です 物理カード モバイルペイメント バーチャルカード
  9. 16 プロセシング アプリケーション・プログラム カード発行ライセンス及び当局の資金決済法に 基づいた登録・各種ガイドライン遵守 国内外のVisaカード加盟店からの決済処理を 司るプロセシングシステムの構築・運用 エンドユーザーが利用する アプリケーションの構築・提供 イシュイング

    当局許認可 スタートアップ システムベンダー 銀行・ カード会社 Kyash Direct の特徴 その1 • パートナー企業はエンドユーザー向けアプリケーションの構築に注力 できます • カード会員向けに必要な機能の実装には Kyash Direct API を利用できます • 既存のアプリケーションに組み込むことも容易です
  10. 17 パートナー企業が管理する ファンディングソース チャージ カード発行 決済 国内外5,390万の VISA加盟店 Kyash Direct

    の特徴 その2 • 売上金、銀行預金、与信、ポイント、仮想通貨といった、 パートナー企業の管理下にあるユーザーの金融資 産やバリューを資金源(ファンディングソース)とすることができます • ユーザー資産をダイレクトに Visa決済に利用できるようになり、 流動性を高める効果が期待できます カード決済に関わる実務・システムを垂直統合しているからこそ実現可能
  11. 目次 01. 株式会社 Kyash について 02. ウォレットアプリ Kyash について 03.

    Kyash Direct について 04. Kyash Direct のスクラッチ開発を決意するまで 05. 設計の試行錯誤 06. どう実現しているか 07. まとめ 08. 質疑応答(?) 18
  12. 19 Kyash と Kyash Direct は似ている プロセシング アプリケーション・プログラム カード発行ライセンス及び当局の資金決済法に 基づいた登録・各種ガイドライン遵守

    国内外のVisaカード加盟店からの決済処理を 司るプロセシングシステムの構築・運用 エンドユーザーが利用する アプリケーションの構築・提供 イシュイング 当局許認可 8割方は同じであるかに見えると思います
  13. 20 Kyash - α + β => Kyash Direct ?

    そう考えていた時期が僕たちにもありました(今年のはじめ頃) CTO
 椎野 孝弘
 (入社間もない頃)
 エンジニア チーム
 まずは現状のウォレットとの Fit&Gap を洗い出しましょう。 既存の資産で使えるものは使うとして、追加しなきゃならな い機能開発がどれくらいあるか、、、 、、、ハイ! ※わかりやすさのため、一部演出を加えてお伝えしております。
  14. 21 Kyash と Kyash Direct で違うところ ※ごく大雑把に Kyash Kyash Direct

    顧客 エンドユーザー(to C) パートナー企業(to B) マルチテナント対応 不要 必要 エンドユーザー向けアプリ 必要 パートナー企業が提供 エンドユーザー認証 必要 パートナー企業が提供 法人ユーザー対応 不要 必要 ファンディングソースの拡張性 追加開発できれば良い 相当な柔軟性がないと厳しい 経理・財務上必要な集計 自社分のみ パートナー企業ごと 管理系機能 社内向け 社内+パートナー企業向け … Kyashに機能を追加して対応する場合、影響範囲がとても大きいことが予想されるもの
  15. 22 これは…かなり無理ゲー厳しいかもしれない… • どこをどうイジる必要があるか、洗い出すのが大変 ◦ ドキュメント類の不在/陳腐化 ◦ メンバーの入れ替わり ◦ 安定しているがゆえに誰も触ったことがない部分も

    • ウォレット単体で見ても設計的に無理が出てきている ◦ 無理やり機能追加したら近い将来、収集がつかなくなりそう ◦ 負債を積み増してる感があって精神的にキツイ • 流用できた部分についても、要件の違いから乖離が発生していく可能性が高 い(ダブルメンテは避けられない) • 新規に作る部分についても既存の設計の制約を受ける Kyashの拡張 厳しそう Points
  16. 26 いっそのこと、ゼロから作るとしたら …? • 作らなければならないモノが圧倒的に増える • アーキテクチャの刷新を試みる場合、失敗のリスクが相応にある • 新しいことを試みるので、必要な時間の見積もりが困難 •

    社内に完全に別系統のシステムを2つ抱えることになる スクラッチ開発 Cons. リソースが限られているスタートアップとして、 かなり受け入れがたい
  17. 29 (再掲)Kyash と Kyash Direct は似ている プロセシング アプリケーション・プログラム カード発行ライセンス及び当局の資金決済法に 基づいた登録・各種ガイドライン遵守

    国内外のVisaカード加盟店からの決済処理を 司るプロセシングシステムの構築・運用 エンドユーザーが利用する アプリケーションの構築・提供 イシュイング 当局許認可 8割方は同じであるかに見えると思います
  18. 目次 01. 株式会社 Kyash について 02. ウォレットアプリ Kyash について 03.

    Kyash Direct について 04. Kyash Direct のスクラッチ開発を決意するまで 05. 設計の試行錯誤 06. どう実現しているか 07. まとめ 08. 質疑応答(?) 33
  19. 36 ウォレットアプリ Kyash のシステム構成 Microservices 的に複数のサービスに分かれています(※簡略化しています) API Internet カード発行 入金

    家計簿連携 通知 ユーザー検索 Processing CardNetwork DB ユーザー認証 管理系機能 Internet 決済 外部サービス 外部サービス Internet Internet 社内管理 バッチ処理 Kyash
  20. 37 なぜ Microservices …? 以下、個人的な推察です • Monolith にするには巨大で複雑すぎる • 部分的な変更が全体に影響を及ぼすのを避けたい

    ◦ 例:アプリで障害が起きてもカードは使える、等 ◦ 障害発生時のインパクトが部分ごとに大きく異なる(例:決済>通知) ◦ 部分ごとに変更の頻度が大きく異なる(例:API>決済) • 部分ごとに負荷が大きく異なる ◦ 部分的にスケールさせたい(の問題も) • 外部サービスとの接続部分を切り離しておきたい ◦ 提携先に影響が及ぶのは避けたい • 機能追加のスピードは極力落としたくない Kyash が Microservices を選択した理由
  21. そもそも Micerservices を選択すべき? 39 Kyash Direct 設計時に考えたこと その1 • もともと人数が足りていなかったところに

    Kyash Direct を開発するためにエンジニア チームを分割 • ウォレットチームのギリギリ感をヒシヒシと感じる日々… • 直近の増員は。。。
  22. 40 • 巨大かつ複雑すぎる一枚岩 • 部分的な変更が全体に影響 ◦ 外部サービスとの接続部分(=提携先)にも影響 • 部分的なスケールは不可能 •

    機能追加の難易度は。。。 向き合うことになるであろうモノたち じゃあ Monolith でやるとしたら…? どっちにしても地獄。。。なのか?
  23. 41 冷静になって Microservices v.s. Monolith 目下の課題で比較 • 変更がどんどん難しくなる • スケールが難しい

    • デプロイが超ハイリスク • エンジニアの人数が足りていない • 運用管理がつらい(実体験として) • 障害調査がつらい(実体験として) Microservices Monolith
  24. 42 冷静になって Microservices v.s. Monolith 目下の課題で比較 • 変更がどんどん難しくなる • スケールが難しい

    • デプロイが超ハイリスク • エンジニアの人数が足りていない • 運用管理がつらい(実体験として) • 障害調査がつらい(実体験として) Microservices Monolith 後で変えるのは相当困難 • 変更難 → ゼロから作る意味がない • スケール → • デプロイ → 祈る 後で変えるのが比較的容易? • エンジニア → 採用がんばる • 運用管理 → ツール • 障害調査 → 仕込み
  25. 43 こちらを選択 • 変更がどんどん難しくなる • スケールが難しい • デプロイが超ハイリスク • エンジニアの人数が足りていない

    • 運用管理がつらい(実体験として) • 障害調査がつらい(実体験として) Microservices Monolith 後で変えるのは相当困難 • 変更難 → ゼロから作る意味がない • スケール → • デプロイ → 祈る 後で変えるのが比較的容易? • エンジニア → 採用がんばる❗ • 運用管理 → ツール • 障害調査 → 仕込み つらみは身に沁みているけれど、 それでもやはり利点の方が大きいと判断
  26. 44 • 設計・実装が難しい • 必要な最低リソース(コンピュータ・人) は多くなる • 運用管理がつらい • 障害調査がつらい

    • 各サービス単体では小さくてシンプル • 変更の影響を局所化できる • スケールしやすい • デプロイしやすい • リソース(コンピューター・人)配分を最適化し やすい Pros. Cons. あえて Microservices を選択するからには メリットは余すところなく享受し、デメリットはできるだけなくしたい❗❗
  27. 45 あえて Microservices を選択するからには メリットは余すところなく享受し、デメリットはできるだけなくしたい❗❗ • 設計・実装が難しい • 必要な最低リソース(コンピュータ・人) は多くなる

    • 運用管理がつらい • 障害調査がつらい • 各サービス単体では小さくてシンプル • 変更の影響を局所化できる • スケールしやすい • デプロイしやすい • リソース(コンピューター・人)配分を最適化し やすい Pros. Cons. ある意味エンジニアの腕の見せどころ
  28. 46 あえて Microservices を選択するからには メリットは余すところなく享受し、デメリットはできるだけなくしたい❗❗ • 設計・実装が難しい • 必要な最低リソース(コンピュータ・人) は多くなる

    • 運用管理がつらい • 障害調査がつらい • 各サービス単体では小さくてシンプル • 変更の影響を局所化できる • スケールしやすい • デプロイしやすい • リソース(コンピューター・人)配分を最適化し やすい Pros. Cons. Microservices のメリットを最大限引き出すためには 各サービスの独立性を高度に保つことが必須
  29. いかにして Microservices の独立性を保つか? 47 Kyash Direct 設計時に考えたこと その2 今こそウォレットアプリ Kyash

    の開発・運用を通じて感じてきたつらみ 培ってきたノウハウを活かすとき…!
  30. 49 ふたたび、ウォレットアプリ Kyash を振り返る ※簡略化しています API Internet カード発行 入金 家計簿連携

    通知 ユーザー検索 Processing CardNetwork DB ユーザー認証 管理系機能 Internet 決済 外部サービス 外部サービス Internet Internet 社内管理 バッチ処理 Kyash
  31. 50 今だから見える課題1:サービス境界がユースケース寄り API Internet カード発行 入金 家計簿連携 通知 ユーザー検索 Processing

    CardNetwork DB ユーザー認証 管理系機能 Internet 決済 外部サービス 外部サービス Internet Internet 社内管理 バッチ処理 Kyash ※簡略化しています
  32. 52 今だから見える課題2:共有データの存在 API Internet カード発行 入金 家計簿連携 通知 ユーザー検索 CardNetwork

    DB Processing ユーザー認証 管理系機能 Internet 決済 外部サービス 外部サービス Internet Internet 社内管理 バッチ処理 Kyash ※簡略化しています
  33. 54 今だから見える課題3:Orchestrator(指揮者)の肥大 API Internet カード発行 入金 家計簿連携 通知 ユーザー検索 CardNetwork

    DB Processing ユーザー認証 管理系機能 Internet 決済 外部サービス 外部サービス Internet Internet 社内管理 バッチ処理 Kyash ※簡略化しています
  34. 55 今だから見える課題3:Orchestrator(指揮者)の肥大 • 各サービス間の連携を同期的なRequest/Reply方式で行っている。そのため 複数サービスをまたがる処理の起点となるサービスが、以下のことを把握して 全体をコントロールする必要がある ◦ 処理全体の流れ ◦ 各処理をどのサービスが持っているか

    ◦ 各処理の呼び出しに必要なパラメータ ◦ 各処理の戻り値の扱い方 ◦ 正しい処理の呼び出し順序 • 本来なら各サービスに隠蔽すべき詳細情報が呼び出し元に流出しやすい(低 凝集/密結合) 主な問題点
  35. Message Bus Partner User Account Card Processing Clearing Funding 61

    サービスは、自身の内部で何か起きたら Message Bus に所定の Message を送ります (ここでは Message Bus ≒ Pub/Sub 型の何かであると考えてください) Userで何かが起きた
  36. Message Bus Partner User Account Card Processing Clearing Funding 62

    Message Busに届いた Message は、各サービスに Publish されます 全体に伝わる
  37. Message Bus Partner User Account Card Processing Clearing Funding 63

    各サービスは、自身が処理すべき Message が届いたら必要な処理を実行します ❗ Accountが反応
  38. Message Bus Partner User Account Card Processing Clearing Funding 64

    処理する必要のない Message が届いた場合は無視します Partnerは無視 ⚙ Accountは何かしら処理
  39. Message Bus Partner User Account Card Processing Clearing Funding 65

    処理を実行した結果、何か起きたら(大抵は何か起きる)、また所定の Message を送りま す。これが繰り返されます
  40. Message Bus Partner User Account Card Processing Clearing Funding 66

    原則としてサービス間で直接の通信は行いません。必ずMessage Busを経由します ❌
  41. 67 Message Pub/Sub による非同期的な連携 • サービス間の依存が Message および Message Bus

    に一元化される(サービ ス間の相互依存は Message のみとなる) • 起こった結果(Event)のみを気にすれば良く、処理の過程を考慮する必要が ない • 各処理は特定の Event に対する反応として記述するため、比較的小さく収ま る(Event Driven) Pros. サービスを圧倒的に疎結合・高凝集にしやすい
  42. 68 Message Pub/Sub による非同期的な連携 • Message変更の影響が大きい ◦ Messageは公開インターフェースに相当 ◦ 項目の追加程度なら問題はありません

    ◦ 項目の削除や大幅な構造変更には、Version管理、あるいは別Message として新たに定義して対応することになると思います ◦ できるだけコンパイラでチェックできるようにしたいところです • 提供したいのは同期的な WebAPI(HTTP Request/Response)だけど、非同 期メッセージングでどうやる? ◦ 後述します • どこかで障害が発生した場合、データの一貫性をどうやって補償する? ◦ 後述します • 複数サービスにまたがる処理がどう動いているか追跡が困難 ◦ 後述します Cons.
  43. 70 DBどうする問題 案1:Event Sourcing Event Store ① Busに流れるすべてのEventを記録 ② 必要となる都度、過去の

    Eventをすべて再生し て現在の状態を取得 ① ② Message Bus Partner User Account Card Processing Clearing Funding
  44. 71 DBどうする問題 案1:Event Sourcing • 記録が追記のみで作成されるため、データ競合が発生しにくい ◦ 排他制御の問題をある程度クリア • Eventを再生しさえすればどのサービスも結果的に同じ状態を入手できる

    ◦ データの一貫性の問題をある程度クリア • 過去のある時点の状態に戻せる • 監査証跡として有効 • インターフェースはEventなので(SQLではないので)、永続化機構をサービス ごとに分けたりしなくても問題なさそう Pros.
  45. Message Bus Partner User Account Card Processing Clearing Funding 73

    DBどうする問題 案2:各サービスごとにDBを持つ(State Sourcing) DB DB DB DB DB DB DB
  46. 76 DBどうする問題 結論:各サービスごとにDBを持つ+Event Store Event Store ① 各サービスのDBでRead/Write ② Busに流れるすべてのEventを記録

    ③ いざというときピンポイントで 復旧に必要な過 去のEventを再生 ② ③ Message Bus Partner User Account Card Processing Clearing Funding DB DB DB DB DB DB DB
  47. 79 DBどうする問題 • 各サービスごとのDBに対しては排他制御が必要 ◦ 排他制御を行います • 補償トランザクションの仕組みが必要 ◦ 後述します

    • サービスの数だけのDBに加えEvent Store用のストレージが必要() ◦ べらぼうな金額ではないはず…! • 通常ReadはDBから行うが、Eventの再生もありうることを前提とした設計・実 装が必要 ◦ Event Sourcing寄りの設計・実装を行います ◦ 具体的にはAggregateの変更はEvent生成→Event適用の手順を踏むよ うに統一します 結論:各サービスごとにDBを持つ+Event Store Cons.
  48. • WebAPIをどうやって提供する? • データの一貫性をどうやって担保する?(補償トランザクション) • トレーサビリティをどうやって確保する? 80 ここまでのおさらい • Microservices

    でいく • Microservices の利点を最大限引き出すために ◦ サービスは境界づけられたコンテキストで切る ◦ サービス同士の連携はMessage Pub/Subを利用したEvent Drivenな Choreography方式 ◦ 永続化は各サービスごとのDB+Event Store 決まったこと ✅ 未解決の問題
  49. 84 WebAPI に対応する Message • Command ◦ 今からやってほしいこと( Requestに対応) ◦

    実行するサービス側でインターフェースとして定義 ◦ 実行するサービスのみが受け取る Messageの1種 • Document ◦ Commandの結果(Responseに対応) ◦ Commandを定義するサービス側でインターフェースとして定義 ◦ Command送信時に指定された返信先のみが受け取る Messageの1種 Message Event Command Document
  50. 85 WebAPI に対応する Message の例 Command:RegisterUser • Name:Tokichiro Kinoshita •

    Gender:Male • DateOfBirth:YYYY-MM-DD • ReplyTo:api • Command名 • Commandパラメータ • Documentの返信先 • Event名 • 起こった事実の内容 • Document名 • Commandの実行結果 ※Commandパラメータに含まれる情報は持たなくて良い Event:UserRegistered • ID:blii3osllhcp2qsl0ao0 • Name:”Tokichiro Kinoshita” • Gender:Male • DateOfBirth:YYYY-MM-DD • CreatedAt: YYYY-MM-DD Document:RegisterUserResult • ID:blii3osllhcp2qsl0ao0 • CreatedAt: YYYY-MM-DD
  51. 86 API Facade の導入 これでHTTPの世界とMessagingの世界を繋ぎます パートナー企業 サーバー Message Bus Service

    1 Service 5 Service 2 Service 4 HTTP Req. HTTP Res. Command Document Service 3 • API Facade が、WebAPI を公開します • HTTP Request を、API に対応する Command に変換し、Message Bus に送ります • Message Bus から Document が返されたら、HTTP Response に変換し、クライアントに返します API Facade
  52. 87 パートナー企業 サーバー Message Bus Service 1 Service 5 Service

    2 Service 4 HTTP Req. HTTP Res. Service 3 • API Facade は、Requestを受けたセッション内で同期的に 応答を返す必要があります • Commandの送信後、Documentを受信するか、タイムアウトするまで 待機(Block)します • API Facade が複数ノードで構成される場合、 Commandを送信したプロセスと、 Document を受け 取るプロセスを一致させるための仕組み が必要になります API Facade ⏳ Service 1 Command Service 1 Document API Facade の特殊事情
  53. 88 Event と Command / Document の違い パートナー企業 サーバー Message

    Bus Service 1 Service 5 Service 2 Service 4 HTTP Req. HTTP Res. Service 1 Command Service 1 Document Service 3 • Event は、すべてのサービスに対して Publish されます • Command は、Command を提供するサービスに対して Send されます • Document は、Command で指定された返信先( ReplyTo)に対して Send されます API Facade
  54. 89 先に挙げた RegisterUser の例で見てみます パートナー企業 サーバー Message Bus User Service

    5 Service 2 Service 4 POST api/user Response RegisterUser RegisterUserResult Service 3 • Command:RegisterUser → Userサービスに Send • Event:UserRegistered → 全サービスに Publish • Document:RegisterUserResult → API Facade に Send API Facade UserRegistered
  55. 91 先ほどの例で登録したUserの情報を取得する場合 パートナー企業 サーバー Message Bus User Service 5 Service

    2 Service 4 GET api/user/xxx Response GetUser GetUserResult Service 3 API Facade 、、、こうなる・・・? 不可能ではなさそうだけど、つらそう
  56. 92 境界づけられたコンテキストに対応する各サービスが Queryに応答する責務を担う場合 • 複数のサービスにまたがるクエリに答えるのが難しい ◦ 例:法人ユーザー配下の全ユーザーの今月のカード利用明細 • API Facade

    への知識の流出が起こる(例のOrchestrator肥大化) ◦ 各サービスにクエリし、結果を合成する必要がある ◦ どのサービスがどの情報を持っているか、どのキーで結合するか、等の情 報を API Facade が知っておく必要がある • クエリの要件が増えるたびに、関連する各サービスのメンテが発生 ◦ 常にクエリの要件を考慮した設計・実装が必要 • パフォーマンス的にしんどい Cons. Pros.
  57. 94 QueryMaterializer / QueryProcessor の導入 パートナー企業 サーバー Message Bus Service

    1 Query Material izer Service 2 Service 4 HTTP GET Response Service 3 • QueryMaterializer は、他のサービスと同様に Eventを受け取り、必要に応じて QueryDB を更新 します • API Facade は参照系のAPI呼び出しに対して、QueryProcessor の該当処理を呼び出します • QueryProcessor は、QueryDB を参照し、必要な情報を取得して呼び出し元に返します API Facade Query DB Query Process or REST / RPC
  58. 95 • 各サービスは、何らかの変化に対して Event さえ律儀に発行していれば良く、 Queryを意識する必要がない • Queryの要件に特化したデータ構造を採用できる • Queryの応答性能的に有利

    • Queryの要件変更に対して QueryMaterializer/QueryProcessor だけで対応 できる • QueryProcessor については、Messageの世界に囚われることなくQueryに特化 したプロトコルやフレームワークを採用できる • Queryだけスケールできる Pros. CQRSの採用
  59. 99 Sagaパターンの例:決済(オーソリ) Message Bus Processi ng User Account Card 1.

    Processingサービスから「オーソリ要求を受けたよ」 EventがPublishされます
  60. 100 Sagaパターンの例:決済(オーソリ) Message Bus Processi ng User Account Card 2.

    各サービスはMessageBusを経由して「オーソリ要求受けたよ」 Eventを受信します
  61. 101 Sagaパターンの例:決済(オーソリ) Message Bus Processi ng User Account Card 3.

    「オーソリ要求受けたよ」 Eventに対して、何かしらの責務を負っているサービスは、これに反応してそ れぞれに処理を行います。ここでは User、Card、Account とします ❗ ❗ ❗
  62. 102 Sagaパターンの例:決済(オーソリ) Message Bus Processi ng User Account Card 4.

    このとき、各サービスで生成されるトランザクションデータは、 「Trying」状態となります ⚙ ⚙ ⚙ Trying Trying Trying
  63. 103 Sagaパターンの例:決済(オーソリ) Message Bus Processi ng User Account Card 5.

    各サービスは、処理が完了したら、それぞれに結果を EventとしてPublishします 6. その間、Processingは各サービスの結果 Eventを待ちます※ ※つまりProcessingは、自身が結論を下すためにどのサービスのどの Eventが必要かを知ってい なければなりません
  64. 104 Sagaパターンの例:決済(オーソリ) Message Bus Processi ng User Account Card 7.

    Processingは、必要な結果Eventが出揃ったら最終的な判断を行い、
  65. 105 Sagaパターンの例:決済(オーソリ) Message Bus Processi ng User Account Card 8.

    一連のEventの結論として、「オーソリ承認したよ」 EventをPublishし、 9. 同時にクライアントにも 「オーソリOKっす」的なレスポンスを返します
  66. 106 Sagaパターンの例:決済(オーソリ) Message Bus Processi ng User Account Card 10.

    各サービスはMessageBusを経由して「オーソリ承認したよ」 Eventを受信し、
  67. 107 Sagaパターンの例:決済(オーソリ) Message Bus Processi ng User Account Card 11.

    該当するトランザクションデータの 「Trying」の状態を「Confirmed」に書き換え、確定させます。これが Commitに相当します 12. この後に「トランザクションをConfirmedにしたよ」EventをPublishします ❗ ❗ ❗ Confirmed Confirmed Confirmed ⚙ ⚙ ⚙
  68. 108 Sagaパターンの例:決済(オーソリ) Message Bus Processi ng User Account Card いずれかのサービスで結果が

    NGとなったり、エラー等により処理が Failした場合は、その旨を Eventとして Publishします NG/Failの場合
  69. 110 Sagaパターンの例:決済(オーソリ) Message Bus Processi ng User Account Card つまり一連のEventの結論として、「オーソリ拒否したよ」

    EventをPublishし、同時にクライアントに 「オーソリ 無理っす」的なレスポンスを返します NG/Failの場合
  70. 112 Sagaパターンの例:決済(オーソリ) Message Bus Processi ng User Account Card 該当するトランザクションデータの

    「Trying」の状態を「Canceled」に書き換え、確定させます。 これがRollbackに相当します。 もちろん「トランザクションがCanceledになったよ」Eventを投げます。 ❗ ❗ ❗ Canceled Canceled Canceled NG/Failの場合 こういう一連の流れをSagaと呼ぶらしい ⚙ ⚙ ⚙
  71. 113 Sagaパターンのポイント • 補償トランザクションをEvent Drivenに実装できる • 各サービスで作成されるトランザクションデータは、Commit/Rollbackに対応する ためにStateを持つ必要がある • Sagaに関わるEventについてはそれぞれ以下3パターンが必要

    ◦ Success ▪ OK ▪ NG ◦ Failure • Saga単位で一意となるID(SagaID、相関ID)を付与しておくと、いたずらに他 サービスのIDを持つ必要がなくなる上に、Saga単位のCommit/Rollbackの処理 をある程度共通化できる可能性がある
  72. • Sagaに関わるEventについてはそれぞれ以下3パターンが必 要 ◦ Success ▪ OK ▪ NG ◦

    Failure(Error) 114 ここで、気になった方はいらっしゃるでしょうか Eventって状態の変化を表すものなんじゃないの? (NGとかFailureでは状態は変わらないのでは?)
  73. 3. サービスAがCardサービスから発行されるカードの状態変化Eventをすべて拾い、 サービスAのDBに記録してカードの状態をトレースする 4. Queryに問い合わせて結果を取得する 116 まず、 この2つが以下の理由で最初に消えました。 • カードが現在利用可能か否かのチェックは、単なるQueryではなく、Cardドメインのビ

    ジネスロジック ◦ Cardサービス内で行われるチェックの内容は、単なるQueryとは異なる可能性 がある。いずれにしても依頼者は関知すべきではない ◦ チェックを他のサービスで行うことは、ドメインのビジネスロジックが流出してい ることを意味する(低凝集/密結合) • カードの現在の状態を正確に知っているのはCardサービスだけ(タイムラグが存在 する)
  74. 119 SagaパターンでCommandとEventが入り乱れる Message Bus Processi ng Account Card User あれ、なんかEvent

    Drivenっぽくないぞ・・・ Orchestrationっぽくなってきたぞ・・・ ① ① ② ② ③ ❓
  75. 120 思い込みに気づく Event Sourcing の Event と Event Driven の

    Event は違う • Event Sourcing ◦ 起きた出来事(変更)をすべて記録する ◦ 現在の状態は過去の出来事をすべて再生することで得られる • Event Driven ◦ 起きた出来事をトリガーとして処理を起動する ▪ Pub/Sub(Producer/Consumer)型 ▪ Stream型 ごちゃ混ぜに考えていました だって同じ言葉だったので…
  76. 121 Event と一口に言っても種類がある • Command:今からやってほしいこと • Document:Commandの結果 • Event:起きた出来事 ◦

    SourceEvent:起きた出来事+それによる変化の内容 Message Event Command Document Source Event
  77. 122 私たちの選択 これを選択しました もうおわかりかもしれませんが 2. サービスAが「このカードのチェックたのんだ」的なEventを投げ、Cardサービスがそれ を拾い、チェック結果をEventとして返す • 現在は、原則としてCommand/DocumentのパターンはAPI Facadeからのみ利用

    可としています(≒ 原則 WebAPIと1:1 => Applicationの関心事) • Commandを他のCommandやEventと組合わせて使用すると、あっという間に Orchastrator化するため、注意が必要と感じています(Commandは単体で Applicationの要求を満たすよう設計すべき) 例1:あるサービスの処理の中で、あるカードが現在利用可能か否かを確認したい このケースでは
  78. 124 私たちの選択 を選択しました。理由は以下です。 3. サービスAがUserサービスから発行されるUser生成Eventを拾い、サービスAのDBに 記録してユーザーIDの有無をトレースする この場合は • 単なるIDの存在確認は、Userドメインのビジネスロジックとは言えない ◦

    他のサービスでやってもビジネスロジックの流出は起きない • ユーザーIDの存在確認のために都度Eventのやりとりでやるとすると、そういうニー ズが生まれるたびにUserサービスに各Eventに対応するための修正を入れなけれ ばならず、煩雑すぎる
  79. 128 Datadogを選択した理由 • 分散トレーシングの結果をAPM(Application Process Monitoring)でグラフィカルに 確認できる • APMとLogを関連付けて一緒に見ることができる •

    AWS用のプラグインが充実 • 分散トレーシング基盤を自前で用意する余裕はない • 価格面の妥当間(Datadogも安くはないけど他のはもっと高かった) • ウォレットでも使っていてとくに不満がない
  80. 129 Datadogで分散トレーシングするための仕込み • サービステンプレート(後述)に含まれるライブラリに仕込んでいます ◦ Datadogのライブラリを組み込み ◦ フレームワーク的な部分でtracerを起動 ◦ TraceID、SpanIDを引き回す

    ◦ ログにTraceID、SpanIDを出力 • サービステンプレートを利用していればある程度勝手にトレースされます ◦ サービスをまたぐ場合は勝手にSpanが切られる ◦ Spanを切りたいところでStartSpan(...)すれば良い
  81. 目次 01. 株式会社 Kyash について 02. ウォレットアプリ Kyash について 03.

    Kyash Direct について 04. Kyash Direct のスクラッチ開発を決意するまで 05. 設計での試行錯誤 06. どう実現しているか 07. まとめ 08. 質疑応答(?) 130
  82. 133 Kyash と同様にGoを選択した理由 • 現メンバーが使い慣れている(学習コスト:低) • 大きな不満がない ◦ 書きやすさと、実行時のリソース効率・性能のバランスが良い ◦

    強い静的型付け(ないと生きていけない) • Kyashの既存実装をコードレベルで参考にできる • コミュニティが活発 • 言語人口が多そう(採用活動❗) といったところです
  83. 134 サービステンプレート - 構造 • internal ◦ adaptor ▪ MessageHandler(InputPort実装)

    ▪ MessagePresenter(OutputPort実装) ▪ DBアクセス周りの実装 ◦ usecase ▪ Usecase各種 ◦ domain ▪ Model(Entity、VO) ▪ Factory(Model、Event) ▪ Repository ▪ Service Clean Architecture にもとづくレイヤー化と依存性の管理をしています DIにはWireを利用しています 最初はいろいろと迷いましたが、今は各サービスでコードの構造が揃い、見通しが良く なって、修正やレビューがはかどると実感しています • pkg ◦ usecase ▪ Command ▪ Document ◦ domain ▪ Event ▪ VO • cmd ◦ main
  84. 135 サービステンプレート - ライブラリ • log ◦ 基本的にlogrusのwrapper ◦ DatadogAPMのためのプラグイン等

    • errors ◦ twirpのエラーを参考にエラーの分類を規定 ◦ stack情報を持たせやすく • persistence ◦ DB接続とトランザクション管理 • messaging ◦ Message Pub/Subまわりのインターフェース ◦ 各種Message(Event、Command、Document)のインターフェース ◦ AWS SQS/SNS用の実装 ◦ Messageの重複排除、排他制御、リトライなど ◦ DatadogAPMのための仕込み 以下のライブラリを自作して、基本的にすべてのサービスで利用しています
  85. 137 サービスのインフラ これが複数存在し、各々が PublicなEvent用のSNSをSubscribeしています Event SNS • SQSはFIFOにしていない(At Least Once)ため、重複排除を行います

    • 複数のServerProcessが同一のMessageを受信しても問題ないよう排他制御も行います • 現在はこのためにDynamoDBを利用しています Service 1 Service 2 Service 3
  86. 138 全体像 Command系とQuery系に別れています API Facade Event SNS Query • Commandは、対象サービス専用の

    SNS Topicに送られ、そのサービスでのみ Subscribeされます ◦ API FacadeはEventには関与しません • Queryは、MaterializeのためにEventをSubscribeするためにSQSだけ持っています • API FacadeとQueryのやりとりは、MessagingではなくRPC(PBベース)となっています Query Command
  87. 139 大量のAWSリソースを複雑に組み合わせて使っているので、 ふつうにconfigとかでやっていたら なので、 Event SNS Query • 明確なリソース命名規約 ◦

    環境とサービスが決まればすべてのリソース名が推移的に決定 ◦ 規約に基づくオーケストレーションとAppからのリソースアクセス • 個人的に「SREチーム神」と思ったポイントです Query Command API Facade
  88. 目次 01. 株式会社 Kyash について 02. ウォレットアプリ Kyash について 03.

    Kyash Direct について 04. Kyash Direct のスクラッチ開発を決意するまで 05. 設計での試行錯誤 06. どう実現しているか 07. まとめ 08. 質疑応答(?) 141
  89. 142 まとめ(という名の感想) • Microservices のメリットを本気で引き出そうとすると、考えなければならない ことが本当に多いです • 設計に関する書籍は「読む↔実践する」を何往復かすると得るところが大きい です(消化に時間がかかる・反芻が必要) •

    Event DrivenとEvent Sourcingは両立できるけれども、設計を考える際は文 脈が異なることを意識した方がはかどります • Request/Reply型の同期処理に慣れきった状態から非同期メッセージング によるEvent Drivenなアプリケーションを書くのは、最初はかなり難しいです (脳の切り替えが必要) • Eventチェーンがバシッと決まるとピタゴラスイッチ的なカタルシスを感じること ができます • 通常レベルの流量なら(IoTとかでなければ)、AWSのSQS+SNS+αは、非同 期メッセージングによるEvent Drivenなアーキテクチャの基盤として十分実用 的なパフォーマンスを発揮できそうです • 運用はこれからなので、まだまだ試行錯誤は続きそう。。。
  90. Special Thanks !! • builderscon tokyo 2019 • All Kyash

    Members & Users ◦ especially: Kyash Direct Engineers • @mtoyoshi