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

ウェルスナビのマルチサービス化を支える技術〜Spring Cloud GatewayとPu...

ウェルスナビのマルチサービス化を支える技術〜Spring Cloud GatewayとPub/Subの実践〜

JJUG CCC 2026 Spring 登壇資料

Avatar for Koki Hoshihara

Koki Hoshihara PRO

June 30, 2026

More Decks by Koki Hoshihara

Other Decks in Technology

Transcript

  1. @2025 WealthNavi Inc. 斎藤 優介 (Yusuke Saito) ウェルスナビ株式会社 サービス基盤グループ ソフトウェアエンジニアリング (SWE)

    チーム ⾃⼰紹介 3 ひとこと 本⽇はよろしくお願いいたします。 ウェルスナビでは Java / Spring Bootを⽤いたバックエンド開発を主軸に、全社横断の技 術的負債の解消や開発標準化に従事。
  2. @2025 WealthNavi Inc. 星原 宏紀 (Koki Hoshihara) ウェルスナビ株式会社 サービス基盤グループ ソフトウェアエンジニアリング (SWE)

    チーム ⾃⼰紹介 4 ひとこと 初のスポンサーセッションで緊張してます。 本⽇はよろしくお願いいたします! ウェルスナビでは 共通ライブラリ開発(⼤規模バッチ / 認証系)、バックエンド開発、 新規システムのパフォーマンスチューニング、新技術導⼊ を推進
  3. 5 アジェンダ はじめに Spring Cloud Gateway を活⽤した API Gateway Spring

    Cloud AWS を活⽤したイベント駆動アーキテクチャ まとめ
  4. © WealthNavi Inc. All Rights Reserved. 全⾃動の資産運⽤サービス プロダクト紹介 ウェルスナビ 「⻑期‧積⽴‧分散」でリターンの最⼤化をめざす

    1万円から運⽤できる 全⾃動でおまかせできる リスクを抑えて運⽤できる NISAも⾃動で活⽤できる 6 ※画面はイメージです
  5. © WealthNavi Inc. All Rights Reserved. 9 • Java25、Spring Boot4の新機能を利⽤した開発に興味がある

    • Java、Spring Bootを使ったAPI Gatewayや、データ連携の開発に興味がある 本セッションのターゲットは、以下のいずれかに当てはまる⽅を想定します はじめに
  6. © WealthNavi Inc. All Rights Reserved. マルチサービス化 資産運⽤(証券)から保険、その他⾦融商品、資産構成変更のアドバイスまで事業領域を拡⼤す るなか、中核となるMAP(総合アドバイザリープラットフォーム)の構築を進めている。 加えて、「エムット」におけるAIネイティブな資産形成体験をシームレスに提供するために、多

    ⾓化するサービス群を⽀えるための「サービス間連携の標準化」が不可⽋。 10 背景‧⽬的 サービス間データ連携における課題 API同期連携における横断的関⼼事の個別実装による属⼈化。また、可⽤性と疎結合性を両⽴す る⾮同期連携活⽤のための、技術標準が未確⽴。
  7. © WealthNavi Inc. All Rights Reserved. マルチサービス化 11 ⾃社事業 エコシステム

    ID基盤 MAP 資産運⽤ 保険 ウェルスナビID 顧客 ⼀つのウェルスナビID(共通ID)を⼊⼝に複数サービスをシームレスに接続し、資産運⽤を含む 様々な⾦融サービスを個別最適された形で提供できる個⼈向け⾦融プラットフォームの実現。 API デジタル バンク 提携 サービス サービス連携
  8. © WealthNavi Inc. All Rights Reserved. 12 従来のデータ連携のアーキテクチャ全体像 Private API

    PrivateProxy API ThirdParty/ SaaS API API ServerSide Public WebApp NativeApp Internet xxClient xxSDK xxService Internet クライアント層 サービス層 API ServerSide xxClient External API 個別実装による属⼈化された APIによる同期データ連携 同期データ連携が適切でない
  9. © WealthNavi Inc. All Rights Reserved. 13 API Gatewayとイベント駆動の導⼊ Private

    API PrivateProxy API ThirdParty/ SaaS API API ServerSide Public WebApp NativeApp Internet xxClient xxSDK xxService Internet クライアント層 サービス層 API ServerSide xxClient External API API Gateway導⼊ イベント駆動型 データ連携導⼊
  10. © WealthNavi Inc. All Rights Reserved. 1 14 Spring Cloud

    Gateway を活⽤した API Gateway 2
  11. © WealthNavi Inc. All Rights Reserved. 15 Spring Cloud Gateway

    を活⽤した API Gateway 1. API Gateway を導⼊した同期データ連携 2. Spring Cloud Gateway の採⽤背景 3. Spring Cloud Gateway によるルーティング制御および認証プロキシの構築 4. Resilience4j によるレジリエンス実装 5. Spring Security を活⽤した共通認可
  12. © WealthNavi Inc. All Rights Reserved. 16 API Gateway 不在

    Private API Public API PrivateProxy API ThirdParty/ SaaS API ServerSide NativeApp WebApp Internet xxClient xxSDK xxService Internet 横断的関⼼事が個別管理、標準化されていない 全体を把握するのが困難 クライアント層 サービス層 • API連携部分の実装が個別に独⽴しており、認証‧認可やログ出⼒、通信などの横断的関 ⼼事が適切に管理できていない状態である。 • クライアント層、サービス(API) 層の運⽤保守が標準化されておらず、属⼈化傾向にあ る。
  13. © WealthNavi Inc. All Rights Reserved. 17 • API連携の実装における認証‧認可(権限管理)、通信制御などの横断的関⼼事はゲート ウェイが解決する役割を担う。

    • 単⼀障害点のリスクに対応しつつ、集約によるメリットを選択する。 • マルチサービス間のデータ連携ハブとして機能させる。 APIゲートウェイ Private API Public API PrivateProxy API ThirdParty/ SaaS API ServerSide NativeApp WebApp クライアント層 サービス層 標準化 クライアント ‧ルーティング ‧認証‧認可 ‧通信制御 ‧トレーシング 集約 集約 ID基盤 新規事業 App 標準化 クライアント Internet 事業横断でのID連携 ‧SSOを実現 SSO(※) セッション SSO (※)トークン交換仕様(RFC8693)を利⽤した有効なセッションを取得する実装 API Gatewayを導⼊した同期データ連携
  14. © WealthNavi Inc. All Rights Reserved. 18 Spring Cloud Gateway

    ルーティング 認証プロキシ 認可 (OAuth 2.0) レジリエンス (通信制御) API Gatewayが解決する横断的関⼼事と対応する技術要素 Spring Framework / Spring Boot Resilience4j (Spring Cloud 統合) Spring Security
  15. © WealthNavi Inc. All Rights Reserved. 19 Spring Cloud Gateway

    を活⽤した API Gateway 1. API Gateway を導⼊した同期データ連携 2. Spring Cloud Gateway の採⽤背景 3. Spring Cloud Gateway によるルーティング制御および認証プロキシの構築 4. Resilience4j によるレジリエンス実装 5. Spring Security を活⽤した共通認可
  16. © WealthNavi Inc. All Rights Reserved. 20 API Gateway 構築における技術選定

    データ連携におけるハブとなるAPIゲートウェイというプロダクトの性質上、複 数のチームによって継続的に参照‧改修されることが想定される。 開発‧運⽤体制の⼀貫性と効率性を最優先 ウェルスナビバックエンドにおいて習熟度の⾼い技術‧サービスを採⽤
  17. © WealthNavi Inc. All Rights Reserved. Spring Cloud Gateway 採⽤理由

     1. 既存資産の活⽤ Spring Framework は社内の標準的な技術スタックであり、既存のJava資産を最⼤限 に活⽤可能。社内の開発標準‧監視設定にも容易に準拠できる  2. 独⾃のロジック注⼊ SaaSでは困難な複雑な条件分岐や、ビジネス要件に基づいた独⾃ロジックを柔軟に 注⼊することが可能  3. リリースの⾃律性 インフラチームのスケジュールに依存することなく、アプリケーションチーム独⾃の リリースサイクルで運⽤が可能 21
  18. © WealthNavi Inc. All Rights Reserved. 出典: https://spring.pleiades.io/projects/spring-cloud-gateway Spring 上に

    API ゲートウェイを構築するためのライブラリ。API へのルーティングをシンプル かつ効果的に⾏う⽅法を提供し、セキュリティ、監視 / メトリクス、回復⼒といった横断的な問 題に対応可能。 WebFlux版 の誕⽣ Netflix 社の Zuul 1.x に代わる形で Spring チームによって開発。 ⾮同期‧ノンブロッキングな WebFlux ベースとして登場。 Java 21 / Virtual Threads 2023年に Virtual Threads が追加。 ⾮同期コードを記述せずとも、⾼性能を維持することが可能になった。 MVC版 のリリース(GA) Spring Boot 3.2(Java 17 以上対応)。 Virtual Threads と併⽤することで、馴染みのある MVC モデルで⾼スループットを実現可能に。 歴史 Spring Cloud Gateway とは 22
  19. © WealthNavi Inc. All Rights Reserved. • MVC 版を採⽤ •

    Virtual Threads 利⽤を前提とした場合、パフォーマンスが同等であれば、デバッグしやす く資産も活かせる MVC が合理的 MVC vs WebFlux 項⽬ MVC WebFlux 記述スタイル 命令型 直感的なコード 宣⾔型 / リアクティブ Flux/Mono によるストリーム操作 パフォーマンス ⾼いスループット 限られたリソースで効率的に動作 デバッグ‧保守 容易 スレッドを追えるため直感的 困難 トレースが複雑化しやすい 既存資産の活⽤ 制限なし 既存の同期ライブラリが安全 制限あり ⾮同期ライブラリの使⽤が推奨 学習コスト 低い 従来の Java 開発知識を転⽤できる ⾼い リアクティブ特有の思考が必要 WebFlux 相当 Virtual Threads を活⽤可能 23
  20. © WealthNavi Inc. All Rights Reserved. 出典: https://docs.oracle.com/javase/jp/21/core/virtual-threads.html#GUID-8AEDDBE6-F783-4D77-8786-AC5A79F517C0 Virtual Threads

    Virtual Threads は、OSではなくJavaランタイムによって実装されるJavaスレッドです。 従来のスレッド(プラットフォーム‧スレッド)との違いは、⾮常に多くの(何百万も)アク ティブな Virtual Threads を同じJavaプロセスで簡単に実⾏できる点です。 リクエストごとのスレッド‧スタイルで記述されたサーバー‧アプリケーションをより効率的 に実⾏できるため、スループットの向上とハードウェアの浪費の軽減につながります。  ⾼スループットを実現 I/O待ち(ネットワークやDB接続など) が多い⼤量のタスク処理に最適 Virtual Threads は⾼速スレッドではない 速度(低レイテンシ)ではなく、スケール(⾼ス ループット)を提供する技術  API Gateway との親和性◎ ⼤量のHTTPクライアント‧コール(I/O操 作)を伴うタスクを処理する、APIゲート ウェイの要件に⾮常にマッチ。 24
  21. © WealthNavi Inc. All Rights Reserved. spring.threads.virtual.enabled=true Spring Boot での

    Virtual Threads 有効⽅法 • アプリケーションプロパティから設定可能(Java 24 以上推奨、Spring Boot 3.2 以降)。 • Spring Framework 内部で利⽤される、Tomcat / Jetty 等のサーブレットスレッド(リクエ スト処理スレッド)や各種 Task Executor が Virtual Threads に切り替わる。 • ⼀⽅で、サードパーティライブラリ側については、個別に対応が必要。(詳細は後述) ◦ 従来のスレッドプール(プラットフォームスレッドプール)を利⽤している場合があ るため。 25
  22. © WealthNavi Inc. All Rights Reserved. 26 Spring Cloud Gateway

    利⽤バージョン Spring Security v4.0.5 v5.0.1 v2.3.0 v7.0.4 Java 25 Spring Framework / Spring Boot Resilience4j (Spring Cloud 統合)
  23. © WealthNavi Inc. All Rights Reserved. 27 Spring Cloud Gateway

    を活⽤した API Gateway 1. API Gateway を導⼊した同期データ連携 2. Spring Cloud Gateway の採⽤背景 3. Spring Cloud Gateway によるルーティング制御および認証プロキシの構築 4. Resilience4j によるレジリエンス実装 5. Spring Security を活⽤した共通認可
  24. © WealthNavi Inc. All Rights Reserved. 28 Spring Cloud Gateway

    ルーティング 認証プロキシ 認可 (OAuth 2.0) レジリエンス (通信制御) Spring Cloud Gateway によるルーティング制御 Spring Framework / Spring Boot Spring Security Resilience4j (Spring Cloud 統合)
  25. © WealthNavi Inc. All Rights Reserved. Domain X API B

    パスベースルーティング クライアント Spring Cloud Gateway • パスベースのルーティングを採⽤し、API Gateway のI/Fとしてはパスにバックエンド サービスの「事業ドメイン」と「サービス名」をプレフィックスとして付与する • プレフィックスを元にバックエンドサービスを解決し、プレフィックスを除去したパス へプロキシする API A ルーティング処理 Host: serviceA.wealthnavi.com GET /** GET /domainX/serviceA/** 29
  26. © WealthNavi Inc. All Rights Reserved. ルート / Route ルーティングの基本単位

    • ID、述語、フィルターの集合で定義される • 述語が⼀致(true)した場合、そのルートが選択される 述語 / Predicates HTTPリクエストの属性(ヘッダー、パス、クエリ等)と条件を照合する機能。 • Spring WebMvc.fn 準拠 / RequestPredicate を使⽤ • すべてのリクエスト情報にアクセス可能 フィルター / Filter リクエストやレスポンスの加⼯を⾏う機能。HandlerFilterFunction が実体。 • 送信「前」または「後」に処理を挿⼊ • 柔軟なカスタム実装をサポート • Spring Cloud Gateway (MVC版) は、ルート、述語、フィルターの3要素を組み合わせて ⾼度なルーティングを実現。 Spring Cloud Gateway の機能概要 30
  27. © WealthNavi Inc. All Rights Reserved. フィルターの種類 Spring Cloud Gateway

    (WebMVC) で提供される標準機能 • ヘッダー操作: リクエスト/レスポンスヘッダーの追加‧削除 • パス操作: 転送時のパス書き換え、プレフィックス除去 • 通信制御: リトライ制御 標準フィルター HandlerFilterFunction インターフェースを実装することで作成可能 例:認証プロキシ - バックエンドのリクエスト時に認証を⾏うフィルターなど カスタムフィルター • ⼀般的に利⽤される機能は標準フィルターとして提供されている。加えてカスタム実装 も可能 31
  28. © WealthNavi Inc. All Rights Reserved. @Configuration public class GatewayConfig

    { @Bean public RouterFunction<ServerResponse> gatewayRouter() { return GatewayRouterFunctions.route("x_a_service") // ルート定義 .route(GatewayRequestPredicates.path("/domainX/serviceA/**"), // 述語適用 HandlerFunctions.http()) .before(BeforeFilterFunctions.uri("https://A.wealthnavi.com")) // フィルター適用① .before(BeforeFilterFunctions.stripPrefix(2)) // フィルター適用② .build(); } } • Java Configuration によるルーティング定義構成例 ルーティング制御実装サンプル implementation 'org.springframework.cloud:spring-cloud-starter-gateway-server-webmvc' 32
  29. © WealthNavi Inc. All Rights Reserved. Route Domain X API

    B クライアント Spring Cloud Gateway • Spring MVC 標準のフィルターに Spring Cloud Gateway の各機能が適⽤されて処理され る API A ルーティング処理 Host: serviceA.wealthnavi.com GET /** GET /domainX/serviceA/** ルーティング制御構成イメージ Filter Predicates 33
  30. © WealthNavi Inc. All Rights Reserved. 34 Spring Cloud Gateway

    ルーティング 認証プロキシ 認可 (OAuth 2.0) レジリエンス (通信制御) Spring Cloud Gateway による認証プロキシ処理 Spring Framework / Spring Boot Spring Security Resilience4j (Spring Cloud 統合)
  31. © WealthNavi Inc. All Rights Reserved. クライアント Spring Cloud Gateway

    • トークン交換(RFC 8693 OAuth 2.0 トークン交換)またはトークン取得を代⾏した上 で、Bearer ヘッダーに付与してバックエンドへ送る GET /domainX/serviceA/** Domain X API A 認証 Host: serviceA.wealthnavi.com Authorization: Bearer XXX GET /** 外部 認可サーバ GET /token 認証のオフロード(Authentication Offloading) Route ルーティング処理 認証処理 35
  32. © WealthNavi Inc. All Rights Reserved. • カスタムフィルター実装例 • HandlerFilterFunctionインターフェースを実装したフィルター関数を定義

    @Component public class AuthorizationOffloadingHandlerFilterFunctions { public HandlerFilterFunction<ServerResponse, ServerResponse> instrument() { return (request, next) -> { String accessToken = authNService.getToken(); // 1. 任意の認証方式でアクセストークン取得処理 ServerRequest modified = ServerRequest.from(request) .headers(headers -> // 2. 取得したアクセストークンを HTTPヘッダーに付与 headers.set(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken)) .build(); return next.handle(modified); }; } } 認証プロキシの実装サンプル① 36
  33. © WealthNavi Inc. All Rights Reserved. • 作成したフィルターをルート定義に追加 @Configuration public

    class GatewayConfig { + @Autowired + private AuthorizationOffloadingHandlerFilterFunctions customFilter; @Bean public RouterFunction<ServerResponse> gatewayRouter() { return GatewayRouterFunctions.route("x_a_service") .route(GatewayRequestPredicates.path("/domainX/serviceA/**"), HandlerFunctions.http()) .before(BeforeFilterFunctions.uri("https://A.wealthnavi.com")) .before(BeforeFilterFunctions.stripPrefix(2)) + .before(AuthorizationOffloadingHandlerFilterFunctions.instrument()) // カスタムフィルター適用 .build(); } } 認証プロキシの実装サンプル② 37
  34. © WealthNavi Inc. All Rights Reserved. 38 クライアント Spring Cloud

    Gateway • ルーティング処理と合わせてカスタムフィルターによる認証処理が実⾏される GET /domainX/serviceA/** Domain X API A 認証 Host: serviceA.wealthnavi.com Authorization: Bearer XXX GET /** 外部 認可サーバ GET /token 認証プロキシ構成イメージ Route ルーティング処理 認証処理 カスタムFilter
  35. © WealthNavi Inc. All Rights Reserved. 39 Spring Cloud Gateway

    を活⽤した API Gateway 1. API Gateway を導⼊した同期データ連携 2. Spring Cloud Gateway の採⽤背景 3. Spring Cloud Gateway によるルーティング制御および認証プロキシの構築 4. Resilience4j によるレジリエンス実装 5. Spring Security を活⽤した共通認可
  36. © WealthNavi Inc. All Rights Reserved. 40 Spring Cloud Gateway

    ルーティング 認証プロキシ 認可 (OAuth 2.0) レジリエンス (通信制御) Resilience4j による通信制御とレジリエンス向上 Spring Framework / Spring Boot Spring Security Resilience4j (Spring Cloud 統合)
  37. © WealthNavi Inc. All Rights Reserved. レジリエンスの重要性 レジリエンス (Resilience)とは? 障害が発⽣することを前提に、そこから「いかに素早く回復し、被害を最⼩限に抑えるか」

    という回復⼒を指す。 API Gateway におけるレジリエンスの重要性 API Gateway は「単⼀障害点」となるため、レジリエンスを担保することは極めて重要 ここでの障害はシステム全体へ波及するため、耐障害性の確保が必要 41
  38. © WealthNavi Inc. All Rights Reserved. 提供機能 resilience4j-circuitbreaker: 失敗率や遅延を監視し、通信を遮断‧試⾏する。 resilience4j-retry:

    リトライ。指数バックオフなどを⽤いて再試⾏を制御する。 resilience4j-bulkhead: リソースを分離‧制限し、局所的な障害の波及を防ぐ。 resilience4j-timelimiter: 処理時間を監視し、上限を超えた場合に中断させる。 resilience4j-ratelimiter: リクエスト数を制限し、過負荷から保護する。 Resilience4j とは • 分散システムにおける通信制御を通じてレジリエンスを向上させるための、フォールト レランス(耐障害性)ライブラリ。 • 外部サービスとの通信において、様々なトラフィック制御パターンを Java アプリケー ションへ容易に実装できる。 42
  39. © WealthNavi Inc. All Rights Reserved. レジリエンス機能 標準フィルター Spring Cloud

    統合 サーキットブレーカー なし(※) フル機能利⽤可能 リトライ Retry フィルター ⾼度な設定(指数バックオフ等) レートリミッター RateLimiter フィルター 柔軟な制御ロジック バルクヘッド / タイムリミット なし(限定的) 標準対応 (※)標準で「CircuitBreaker フィルター」が用意されているが、これは Spring Cloud 統合を前提としたフィルター Spring Cloud 統合 • Spring Cloud Gateway で通信制御⽤のフィルターを提供しているが限定的。 • Resilience4j を Spring Cloud エコシステムへ統合するためのライブラリを利⽤すること で⾼度な通信制御が利⽤可能。 43
  40. © WealthNavi Inc. All Rights Reserved. クライアント Domain X •

    通信結果を監視して、失敗率を管理 • 失敗率がしきい値を超えた場合、通信を遮断して即座にエラーを返す API A 障害 サーキットブレーカー処理イメージ (1) リクエスト (2) タイムアウト (3) リクエスト (4) エラー Spring Cloud Gateway Route ルーティング処理 通信制御処理 認証処理 44
  41. © WealthNavi Inc. All Rights Reserved. サーキットブレーカー実装サンプル① resilience4j.circuitbreaker: configs: default:

    failureRateThreshold: 30 # 失敗率の閾値 slidingWindowType: COUNT_BASED # リクエスト数で判定 slidingWindowSize: 50 # 判定に使う直近のリクエスト数 instances: x_a_service_cb: # 通信先ごとの定義(今回は上記で定義したデフォルト設定を適用) base-config: "default" • Spring Cloud 統合ライブラリを依存関係に追加 • アプリケーションプロパティから Resilience4j 設定を構成 • 通信先ごとに設定を個別に管理可能 implementation rg.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j' 45
  42. © WealthNavi Inc. All Rights Reserved. サーキットブレーカー実装サンプル② @Configuration public class

    GatewayConfig { @Bean public RouterFunction<ServerResponse> gatewayRouter() { return GatewayRouterFunctions.route("x_a_service") .route(GatewayRequestPredicates.path("/domainX/serviceA/**"), HandlerFunctions.http()) .before(BeforeFilterFunctions.uri("https://A.wealthnavi.com")) .before(BeforeFilterFunctions.stripPrefix(2)) .before(AuthorizationOffloadingHandlerFilterFunctions.instrument()) + .filter(CircuitBreakerFilterFunctions.circuitBreaker(config -> config + .setId("x_a_service_cb") // ①で定義した ID + .setStatusCodes("500", "502", "503", "504"))) .build(); } } • Spring Cloud Gateway が提供する CircuitBreaker フィルターを利⽤することで、①で構 成した設定が適⽤される 46
  43. © WealthNavi Inc. All Rights Reserved. クライアント Domain X Spring

    Cloud Gateway • Resilience4j の Spring Cloud 統合で通信制御を構成 API A 障害 通信制御構成イメージ Route ルーティング処理 通信制御処理 Resilience4j 認証処理 (1) リクエスト (2) タイムアウト (3) リクエスト (4) エラー Filter 47
  44. © WealthNavi Inc. All Rights Reserved. Virtual Threads 利⽤時の注意点 resilience4j-circuitbreaker

    • デフォルトの実⾏スレッドが Executors.newCachedThreadPool() になっている • 対策: Executors.newVirtualThreadPerTaskExecutor() を明⽰的に使⽤するよう設定変更する resilience4j-bulkhead • デフォルト(FixedThreadPoolBulkhead)はプラットフォームスレッドを使⽤する • 対策: SemaphoreBulkhead を使⽤するか、Bulkhead ⾃体を無効化する Rerilience4j 側でも Virtual Threads 対応は進められている(※) プロパティ(resilience4j.thread.type=virtual)による切り替え 48 (※) https://github.com/resilience4j/resilience4j/pull/2335 を参照
  45. © WealthNavi Inc. All Rights Reserved. 49 Spring Cloud Gateway

    を活⽤した API Gateway 1. API Gateway を導⼊した同期データ連携 2. Spring Cloud Gateway の採⽤背景 3. Spring Cloud Gateway によるルーティング制御および認証プロキシの構築 4. Resilience4j によるレジリエンス実装 5. Spring Security を活⽤した共通認可
  46. © WealthNavi Inc. All Rights Reserved. 50 Spring Cloud Gateway

    ルーティング 認証プロキシ 認可 (OAuth 2.0) レジリエンス (通信制御) Spring Security を活⽤した共通認可 Spring Framework / Spring Boot Spring Security Resilience4j (Spring Cloud 統合)
  47. © WealthNavi Inc. All Rights Reserved. Domain X クライアント API

    Gateway • サービスごとに認可処理を独⾃実装せず、API Gateway が認可を担う • ID基盤と連携して、RFC 9068 に準拠した認可処理(アクセストークン検証、スコープに よるアクセス制御)を実施 API Spring Cloud Gateway / Resilience4j Spring Security 共通認可処理 1. トークン検証 2. スコープ検証 JWTトークン API API 認可済み 認可のオフロード(Authorization Offloading) ID基盤 認証要求 公開鍵の取得 51
  48. © WealthNavi Inc. All Rights Reserved. RFC 9068準拠のデコーダー実装サンプル public JwtDecoder

    rfc9068JwtDecoder() { // 1. デコーダーの生成(JWKS URLの設定) NimbusJwtDecoder decoder = NimbusJwtDecoder .withJwkSetUri("https://id.wealthnavi.com/.well-known/jwks.json") .validateType(false) // typ検証は後続のValidatorに委譲するため無効化 .build(); // 2. RFC 9068準拠のバリデータ構成(typ, iss, exp, aud, client_id を一括検証) OAuth2TokenValidator<Jwt> rfc9068Validator = JwtValidators.createAtJwtValidator() .issuer("https://id.wealthnavi.com") // issクレーム .audience("https://apigw.wealthnavi.com") // audクレーム .clientId("my-client-id") // client_idクレーム .build(); decoder.setJwtValidator(rfc9068Validator); return decoder; } • Spring Security 6.5で追加されたRFC 9068対応APIを利⽤し、NimbusJwtDecoderを⽣成 • SecurityFilterChainに登録することで、仕様に厳格に準拠したアクセストークン検証を容 易に実現 52
  49. © WealthNavi Inc. All Rights Reserved. パスベースのアクセス制御を含めた認可実装サンプル @Bean public SecurityFilterChain

    securityFilterChain(HttpSecurity http) throws Exception { return http.authorizeHttpRequests(auth -> auth // GETリクエストは参照権限(read)を要求 .requestMatchers(HttpMethod.GET, "/domainX/apiA/**").access(hasScope("read:domainX:apiA")) // それ以外の更新系リクエスト(POST/PUT等)は更新権限(write)を一括要求 .requestMatchers("/domainX/apiA/**").access(hasScope("write:domainX:apiA")) // 定義外のパスはすべて認証済みであることを要求 .anyRequest().authenticated() ) // RFC 9068準拠のデコーダーを適用 .oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.decoder(rfc9068JwtDecoder()))) .build(); } • API Gateway はエンドポイントの実装(Controller)を持たないため、アノテーション (@PreAuthorize)ではなく SecurityFilterChain によるパスベースの集中型アクセス制 御を実施する • RFC 9068準拠のデコーダーを登録する 53
  50. © WealthNavi Inc. All Rights Reserved. Tips: JWKS URL へのリトライ実装サンプル

    public RestTemplate jwkSetRequestRestTemplate() { // リトライポリシーの設定( SocketTimeoutExceptionを対象) var policy = RetryPolicy.builder().maxRetries(maxRetries).includes(SocketTimeoutException.class).build(); var retryTemplate = new RetryTemplate(); retryTemplate.setRetryPolicy(policy); // インターセプターでリトライ処理を注入 var restTemplate = new RestTemplate(); restTemplate.setInterceptors(List.of((req, body, exec) -> { try { return retryTemplate.execute(ctx -> exec.execute(req, body)); } catch (RetryException e) { throw new IOException("JWKS fetch failed after retries", e); } })); return restTemplate; } • NimbusJwtDecoder はデフォルトで JWKS 取得時のリトライ機構を持たないため、瞬断 がサービス全体の障害に繋がるリスクがある • 公開鍵取得に使⽤する RestTemplate に Spring Retry を適⽤することで、レジリエンス を向上させる(JwkSetUriJwtDecoderBuilder#restOperations に設定) 54
  51. © WealthNavi Inc. All Rights Reserved. 1 Spring Cloud AWS

    を活⽤した イベント駆動アーキテクチャ 3 56
  52. © WealthNavi Inc. All Rights Reserved. 57 Spring Cloud AWS

    を活⽤したイベント駆動アーキテクチャ 1. イベント駆動アーキテクチャ採⽤の動機付け 2. Pub/Subの概念とAWSでの構成 3. Spring Cloud AWSによる実装詳細 4. 運⽤‧設計上の考慮事項
  53. © WealthNavi Inc. All Rights Reserved. 58 • API 連携(同期):呼び出し結果をその場で確認できる。

    • イベント駆動型(⾮同期):1対多で配信できるため、スケールアウトしやすい(※)。 API 連携 Request - Response 呼び出し元 呼び出し先 ① Request ② Response イベント駆動型データ連携 Pub/Sub 連携 Publisher 連携先 A 連携先 B ① Publish ② Subscribe Message Broker API 連携とイベント駆動型データ連携の整理 (※)補足:以降「Pub/Sub 連携」と記載。
  54. © WealthNavi Inc. All Rights Reserved. 59 API連携で更新処理を担う場合の課題 課題①:呼び出し元の複雑化 •

    連携先の状態に応じた複雑な制御が必要 • リトライロジックが肥⼤化 課題②:連携先サービス障害時の復旧負荷が⾼い • 障害時は該当時間帯の処理が⼀律失敗する ため、呼び出し元が再実⾏を管理する必要 がある イベント駆動型を採⽤した場合の対応 解決策①-1:更新処理の簡素化 • ⾮同期化でトランザクション制御を簡素化 解決策①-2:主体性の明確化 • 更新の責任範囲がアーキテクチャ上で明確 解決策②-1:復旧時のバースト負荷を吸収 • キューイングで再処理の負荷を平準化 解決策②-2:更新失敗の影響を局所化 • 復旧後キューの内容に基づき再処理可能 • 更新処理をイベントに分離することで、呼び出し元の責務を減らし、連携先の追加や⼀時 的なエラーに対するリトライを扱いやすくする。 イベント駆動型への移⾏によるメリット
  55. © WealthNavi Inc. All Rights Reserved. イベント駆動型の採⽤判断基準 更新結果の 即時確認が必要 な処理は、

    API連携 が向いている 具体的には、処理の成否をその場で確認し、エラー時に即座に対応する必要がある場合 • 例)即時の入金・出金処理 更新結果の 即時確認が不要 な処理は、 イベント駆動 が向いている 具体的には、⾮同期で処理でき、失敗時もリトライで対応できる場合 • 例)外部サービスへの連携、メール送信 • イベント駆動の採⽤可否は、処理結果の即時確認が必要かどうかを主な判断軸とする。 60
  56. © WealthNavi Inc. All Rights Reserved. ウェルスナビでイベント駆動型(Pub/Sub 連携)採⽤に⾄ったケースを紹介 • 社内システムの業務処理が完了次第、社外へデータを連携したい

    • Internalなシステムから外部へ直接リクエストを⾶ばすのは避けたい • ⼀部のデータに誤りがあっても、他のデータ連携は確実に継続したい ウェルスナビバックエンドにおいて習熟度の⾼い技術‧サービスを採⽤。 Amazon SNS、SQSを⽤いたPub/Sub 連携の仕組みを導⼊(後述)。 SNS → SQS 構成では、複数バックエンドへの fan-out による拡張性も確保できる。 背景‧要求 解決策 61
  57. © WealthNavi Inc. All Rights Reserved. 62 1. イベント駆動アーキテクチャ採⽤の動機付け 2.

    Pub/Subの概念とAWSでの構成 3. Spring Cloud AWSによる実装詳細 4. 運⽤‧設計上の考慮事項 Spring Cloud AWSを活⽤したイベント駆動アーキテクチャ
  58. © WealthNavi Inc. All Rights Reserved. イベント駆動を実現する Pub/Sub の概念を改めて紹介 

    Publisher イベントの送出元 Message Broker  Event メッセージの分類  Queue ⼀時的な蓄積  Subscriber イベントの受信‧処理 Pub/Sub とは、イベントを送る側(Publisher)が仲介役(Message Broker)に イベントを送出し、イベントを受け取る側(Subscriber)がMessage Broker内の ⼀時的な蓄積場所(Queue)からメッセージを受け取って処理するアーキテクチャ データの流れ 63
  59. © WealthNavi Inc. All Rights Reserved. 64 AWSでPub/Subを構成する場合のアーキテクチャ AWSでの実践事例(ウェルスナビの場合) Publisher/Subscriberにはコンテナランタイム(Amazon

    ECS)を活⽤する Topic、Queueの管理にはAmazon SNS、SQSをそれぞれ活⽤する  ECS Publisher Message Broker  SNS Topic管理  SQS Queue管理  ECS Subscriber データの流れ 参考:https://www.docswell.com/s/WN_Tech-PR/KPG18L-2025-11-20-154347#p18
  60. © WealthNavi Inc. All Rights Reserved. 65 AWSでPub/Subを構成する場合のアーキテクチャ AWSでの実践事例(ウェルスナビの場合) Publisher/Subscriberにはコンテナランタイム(Amazon

    ECS)を活⽤する Topic、Queueの管理にはAmazon SNS、SQSをそれぞれ活⽤する  ECS Publisher Message Broker  SNS Topic管理  SQS Queue管理  ECS Subscriber データの流れ どうやって Subscribeする? どうやってPublish する?
  61. © WealthNavi Inc. All Rights Reserved. 66 Spring Cloud AWSを活⽤したPub/Sub実装

    Spring Cloud AWSとは AWS のメッセージングサービスを Spring から利⽤しやすくするライブラリ SNS / SQS を⽤いたイベント駆動アーキテクチャ導⼊時の開発効率向上が期待できる  ECS Publisher Message Broker  SNS Topic管理  SQS Queue管理  ECS Subscriber データの流れ Spring Cloud AWSを利用して Subscribe Spring Cloud AWSを利用して Publish
  62. © WealthNavi Inc. All Rights Reserved. 67 1. イベント駆動アーキテクチャ採⽤の動機付け 2.

    Pub/Subの概念とAWSでの構成 3. Spring Cloud AWSによる実装詳細 4. 運⽤‧設計上の考慮事項 Spring Cloud AWSを活⽤したイベント駆動アーキテクチャ
  63. © WealthNavi Inc. All Rights Reserved. 68 Spring Cloud AWS

    利⽤バージョン v4.0.5 v4.0.2 Java 25 Spring Framework / Spring Boot implementation 'io.awspring.cloud:spring-cloud-aws-dependencies'
  64. © WealthNavi Inc. All Rights Reserved. Spring Boot で SNS

    へ Publish する⽅法 SnsTemplate を利⽤して、SNS Topic にメッセージを Publish する • Publisher は 連携先の SQS Queue を意識しない • Topic へのイベントは SNS Subscription が各 SQS Queue に配送する • 連携先が増えても、Publisher 側の実装変更を抑えやすい 69
  65. © WealthNavi Inc. All Rights Reserved. Spring Boot で SNS

    へ Publish する⽅法(サンプルコード) @Service public class MessagePublisher { private final SnsTemplate snsTemplate; private final SnsProperties snsProperties; public void publish(NotificationMessage message) { snsTemplate.sendNotification( snsProperties.topicArn(), // Properties クラスを使用(※) message, message.orderStatus()); } } public record NotificationMessage( String eventId, String orderId, String customerId, String orderStatus, String occurredDate ) {} • SnsTemplate.sendNotification で SNS へ Publish する。 • シリアライズ⽤のDTOクラスを作成する(Java 17以降であれば record を使⽤可能)。 DTOクラス PublishするServiceクラス 70 @ConfigurationProperties(prefix = "aws.sns") public record SnsProperties(String topicArn) {} Properties クラス (※)参考:https://zenn.dev/khoshihara/articles/c05f10f2d4a936
  66. © WealthNavi Inc. All Rights Reserved. @SqsListener を利⽤して、SQSのメッセージを Subscribe する

    • アプリケーションは @SqsListener で SQS Queue をSubscribeする • 処理に成功したメッセージは削除され、失敗した場合は再配信される Spring Boot で SQS を Subscribe する⽅法 71
  67. © WealthNavi Inc. All Rights Reserved. Publisher と Subscriber の処理特性の違い

    72 @SqsListener では、アノテーション付与のみで上記の共通処理を⾃動化 処理特性 解決策 Publisher SNS へのシンプルなリクエストのみを⾏う Subscriber 共通処理の実装が要求される • ポーリング • メッセージ取得、削除 • 例外発⽣によるリトライ(DLQ移動の起点)
  68. © WealthNavi Inc. All Rights Reserved. 73 @SqsListenerを⽤いた処理フロー(正常系) Queue (SQS)

    DLQ (SQS) EventHandler (@SqsListener) Service (@Service) • @SqsListenerで指定したキューに対応する業務ロジックが正常終了するとメッセージが 削除される。 アプリ 処理の流れ インフラ 正常系 ②:業務ロジック ①:ポーリング ③:処理成功 ④:メッセージ削除
  69. © WealthNavi Inc. All Rights Reserved. @SqsListenerを⽤いた処理フロー(異常系) 異常系 ③:例外発⽣ •

    処理中に例外(Exception)が maxReceiveCount を超えて発⽣すると、メッセージが DLQに移る。 ②:業務ロジック Queue (SQS) DLQ (SQS) EventHandler (@SqsListener) Service (@Service) 74 アプリ 処理の流れ インフラ ①:ポーリング ⑤:①~④のループが maxReceiveCount を超えると DLQ へ移る ④:メッセージは削除 しない
  70. © WealthNavi Inc. All Rights Reserved. Spring Boot で SQS

    を Subscribe する⽅法(サンプルコード) @Component public class MessageListener { private final ObjectMapper objectMapper; private final NotificationService notificationService; @SqsListener("${aws.sqs.queue-name}") public void receive(String rawMessage) throws Exception { // 例外が発生した場合はメッセージが削除されず、リトライ後に DLQ へ送出される(※) NotificationMessage message = objectMapper.readValue(rawMessage, NotificationMessage.class); notificationService.process(message); } } @Service public class NotificationService { public void process(NotificationMessage message) { // 例:業務処理を書く // 例:DB更新、データ連携など } } • @SqsListener でキュー名を指定して Subscribeし、メッセージ取得後は業務処理を実⾏ する。 Serviceクラス Handlerの実装(@Component) 75 (※)参考:https://zenn.dev/khoshihara/articles/327df58984b44b
  71. © WealthNavi Inc. All Rights Reserved. 76 Spring Cloud AWSを活⽤したイベント駆動アーキテクチャ

    1. イベント駆動アーキテクチャ採⽤の動機付け 2. Pub/Subの概念とAWSでの構成 3. Spring Cloud AWSによる実装詳細 4. 運⽤‧設計上の考慮事項
  72. © WealthNavi Inc. All Rights Reserved. SQSの標準キュー‧FIFOキューの違いについて 標準キュー • ⾼スループットなメッセージ処理に最適

    • 重複配信、順序の前後が発⽣する可能性あり FIFOキュー • メッセージの順序性が重要な処理に最適 • MessageGroupId 単位で順序が保証 • 重複を抑制する仕組みを内蔵 • 同⼀ MessageGroupId は直列化されるた め、スループット設計に注意 FIFOキューで高スループットが要求さ れる場合は、High Throughput FIFO を使用する(※)。 77 (※)https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/enable-high-throughput-fifo.html
  73. © WealthNavi Inc. All Rights Reserved. 今回のユースケースでは重複を抑制できる点を評価しFIFOキューを選択 78 標準キュー •

    ⾼スループットなメッセージ処理に最適 • 重複配信、順序の前後が発⽣する可能性あり FIFOキュー • メッセージの順序性が重要な処理に最適 • MessageGroupId 単位で順序が保証 • 重複を抑制する仕組みを内蔵 • 同⼀ MessageGroupId は直列化されるた め、スループット設計に注意
  74. © WealthNavi Inc. All Rights Reserved. デッドレターキュー(DLQ)の役割を紹介 79 DLQの役割 •

    処理に失敗し続けるメッセージを分離する⼿段 • 失敗メッセージを調査し、原因特定‧再処理につなげる • 障害検知の起点として 監視ツール(Datadog など)と組み合わせる
  75. © WealthNavi Inc. All Rights Reserved. デッドレターキュー(DLQ)の設計要素を整理 maxReceiveCount 何回失敗したら DLQ

    に送るか Visibility Timeout 1回の処理に必要な最⼤時間 Message Retention DLQ上で何⽇保持するか Redrive 修正後に元キューへ戻す⽅法を決める 監視 DLQにメッセージが⼊ったら検知する 調査 メッセージを特定する⼀意なIDを設定する 80
  76. © WealthNavi Inc. All Rights Reserved. Pub/Subのテストでは、ユニットテストに加え、 Integration テストも実施する Pub/Subのテストについて

    81 テスト観点 Publisher Subscriber ユニットテスト SnsTemplate をモックし、送信引数を 検証 メッセージを受け取り、期待した処理 が実⾏されるか Integration テスト (LocalStack) LocalStack上のSQSに直接メッセージ を投⼊し受信、業務処理を検証(※) Message定義の検証 record クラスで定義し、 Publisher/Subscriber 双⽅で検証 同左 LocalStack上のSNSへ Publishし、 SQSに流れたメッセージ内容を検証 (※)参考:https://zenn.dev/khoshihara/articles/11954bcbb42aef
  77. © WealthNavi Inc. All Rights Reserved. 84 まとめ 本セッションの振り返り 1

    背景:データ連携⽅式の標準化の要求 2 Spring Cloud Gateway によるAPI Gateway実装 3 AWS SNS/SQSを活⽤したPub/Subの実装 今後はデータ連携⽅式の標準化とエコシステムを 開発組織全体に提供する取り組みを進めていきます。 本⽇はご静聴ありがとうございました!
  78. © WealthNavi Inc. All Rights Reserved. We are hiring 採⽤強化中

    安⼼して使える⾦融インフラを共につくる仲間募集 https://recruit.wealthnavi.com/ 85
  79. © WealthNavi Inc. All Rights Reserved. • 本資料は、断定的判断を提供するものではなく、情報を提供することのみを目的としており、いかなる種類の商品も勧誘 するものではありません。最終的な決定は、お客様自身で判断するものとし、当社はこれに一切関与せず、また、一切の 責任を負いません。

    • 本資料には将来の出来事に関する予想が含まれている場合がありますが、それらは予想であり、また、本資料の内容の 正確性、信頼性、完全性、適時性等を一切保証するものではありません。本資料に基づいて被ったいかなる損害について も、当社は一切の責任を負いません。また、当社は、新しい情報や将来の出来事その他の情報について、更新又は訂正 する義務を負いません。 • 本資料を利用することによりお客様に生じた直接的損害、間接的損害、派生的損害その他いかなる損害についても、当社 は一切の責任を負いません。 商号等:ウェルスナビ株式会社 金融商品取引業者 関東財務局長(金商) 第2884号 加入協会:日本証券業協会 一般社団法人 資産運用業協会 重要な注意事項 86