SpringBootでMicroserviceアーキテクチャ


microservicesアーキテクチャについて、アンチパターンや、思想を学んだ。
そこで実際にmicroservicesアーキテクチャで構成されたアプリケーションを見て、実際のプラクティスを学ぶ。

参考にするリポジトリ

全体構成

cloud-foundryをアプリケーション起動環境としていますが、構成で重要なのは以下の点が大事かなと。

  • 全サービスがEurekaservice-discoveryを実現。

    • アプリケーションの機能がステートレスになっているはず。(特定のサービスは特定の銘柄の情報だけを処理する!とかになっていない)
  • 全サービスがSpring-cloud-configで設定ファイルの中央集権的な管理を実現。

  • Histrixで「障害の伝播」を考慮。

  • webサービスはエンドユーザがアクセスするサービスのため、SpringSecurityでセキュリティ考慮。

  • 各サービスは別リポジトリで管理されている。

実装を覗いてみる

とりあえず色々やってるwebサービスを覗いてみる。

設定ファイル

bootstrap.yml
spring:
  application:
     name: web-service
  main:
    allow-bean-definition-overriding: true
  profiles:
    active: local
info:
  build:
    group: ${group}
    name: ${name}
    description: ${description}
    version: ${version}
  • Spring-cloudbootstrapコンテキストをapplicationコンテキストの親的な立ち位置で扱えるようにしてあるみたい。で、それのデフォルト設定をbootstrap.ymlに記載すると起動時にロードするという仕組み。bootstrap.ymlapplication.ymlよりも先に読まれる。
  • このリポジトリにはapplication.ymlは存在せず、bootstrap.ymlspringタグの設定値を参照して、ConfigServerからapplication.ymlをロードしてくるんだと思う。
  • ConfigServerのURIとかないなあと思ってたら、cloud-foundryのサービスでごにょごにょやってるらしい。ローカルでセットアップする場合は以下を記載したconfigserver.ymlとしてConfigServerのディレクトリに含めろって書いてた。
configserver.yml
spring:
  profiles:
    active: git
  cloud:
    config:
      server:
        git:
          uri: https://github.com/pivotalbank/cf-SpringBootTrader-config.git

つまり、起動時は以下のようにconfigが設定される。
webリポジトリのbootstrap.ymlconfigserverURIのGitリポジトリのweb-service.yml

で、設定値を変えたい場合はアプリを再デプロイせずとも、configserverのURIのGitリポジトリのymlファイルを更新すれば動的に設定を更新できる。

Application起動クラス

WebApplication.java
package io.pivotal.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.scheduling.annotation.EnableScheduling;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;

@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
@EnableScheduling
public class WebApplication {

    public static void main(String[] args) {
        SpringApplication.run(WebApplication.class, args);
    }

    static {
        HostnameVerifier allHostsValid = (name, sslSession) -> true;
        HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
    }
}
  • @EnableDiscoveryClientはこのアプリケーションをEurekaの管理するサーバに登録するためのアノテーション。
  • @EnableCircuitBreakerはこのアプリケーションにHistrixをサーキットブレーカとして登録する事を示すアノテーション。@HystrixCommandで指定したフォールバックメソッドを実際の処理の代わりに返すようになる。

最後に

Spring-cloudMicroservicesアーキテクチャを実現するとこういう感じになるのかあ、と何となく理解できた。そしてNetflixさんのOSSはMicroServicesアーキテクチャ実装するときにはお世話になるなあって感じ。
以下の点が気になった。

  • Spring-cloud-configによる動的設定変更と、中央集権的管理。これは是非やりたいけど、ConfigServerが単一障害点にならないようにしたい。
  • Eurekaはアプリケーション起動時にDNS登録(みたいな事)をアノテーション一つで自動で行うから、自前でスクリプト組んでごにょごにょとかしなくて良いのは魅力的。でもAWSのマネージドサービスとかでも代替できるのかも?
  • 同じクラス名だけどフィールドの違うドメインモデル(振る舞い持ってなかったからドメインモデルではないけど、domainパッケージに入ってた)をそれぞれの各サービスに持ってた。commonDomainModelみたいなjarに切り出して使うサービスの依存に含めるとかはしてなかった。jar切り出しパターンであれば、ドメインモデルに振る舞いを持たせたときにwebでは使うメソッドだけど、accountでは使わないメソッドとか生まれそうで、こっちのが好ましいなと思った。
  • サービス間の疎通にWebfluxの非同期HTTP-apiを使用していた。結局これリクエストの来たサービスの経路を通って、webに返しているだけなので、ここを最短ルートで返すとかしてやると、もっと最適化される?でもそれってコンテキスト跨いだ処理をどこかに書かなきゃいけなくなるか?

気になる点は色々あるが、自分でも実装いじってみようと思います。