SpringBootでMicroserviceアーキテクチャ

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

### 参考にするリポジトリ
- [pivotalのトレーダーシステムのリポジトリ](https://github.com/pivotal-bank/cf-SpringBootTrader)を参考に、実際のアプリケーション実装を見ていく。

### 全体構成
![springBootTrader.png](https://raw.githubusercontent.com/pivotal-bank/cf-SpringBootTrader/master/docs/base-architecture-diagram.png)

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

- 全サービスが`Eureka`で`service-discovery`を実現。
  - アプリケーションの機能がステートレスになっているはず。(特定のサービスは特定の銘柄の情報だけを処理する！とかになっていない)

- 全サービスが`Spring-cloud-config`で設定ファイルの中央集権的な管理を実現。
- `Histrix`で「障害の伝播」を考慮。
- `web`サービスはエンドユーザがアクセスするサービスのため、`SpringSecurity`でセキュリティ考慮。
- 各サービスは別リポジトリで管理されている。

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


#### 設定ファイル
```yml: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-cloud`は`bootstrap`コンテキストを`application`コンテキストの親的な立ち位置で扱えるようにしてあるみたい。で、それのデフォルト設定を`bootstrap.yml`に記載すると起動時にロードするという仕組み。`bootstrap.yml`は`application.yml`よりも先に読まれる。
- このリポジトリには`application.yml`は存在せず、`bootstrap.yml`の`spring`タグの設定値を参照して、`ConfigServer`から`application.yml`をロードしてくるんだと思う。
- `ConfigServer`のURIとかないなあと思ってたら、`cloud-foundry`のサービスでごにょごにょやってるらしい。ローカルでセットアップする場合は以下を記載した`configserver.yml`として`ConfigServer`のディレクトリに含めろって書いてた。

```yml:configserver.yml
spring:
  profiles:
    active: git
  cloud:
    config:
      server:
        git:
          uri: https://github.com/pivotalbank/cf-SpringBootTrader-config.git
```

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

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


#### Application起動クラス

```java: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-cloud`で`Microservices`アーキテクチャを実現するとこういう感じになるのかあ、と何となく理解できた。そして`Netflix`さんのOSSは`MicroServices`アーキテクチャ実装するときにはお世話になるなあって感じ。
以下の点が気になった。

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

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