Microservicesアンチパターンについて ①

業務でモノシリックなTransactionScriptで書かれたアプリケーションをマイクロサービスに移行しようと検討している中で、下記の学術記事を読んだ。
[Microservices antipattern and pitfalls](https://www.oreilly.com/ideas/microservices-antipatterns-and-pitfalls)

知識整理のためにまとめる。


## Data-Driven Migration AntiPattern
- モノシリックなアプリケーションをマイクロサービスに移行する場合にやりがちなアンチパターン。
- モノシリックなアプリケーションを機能的に分離すること。そして、その分離したサービスのみに所属したデータベース(スキーマ)を巨大なデータベースから分離していくこと。この二つがゴールとなる。
- とりあえずアプリケーションのモジュールとデータベースを分割して、マイクロサービスに移行しようとしても、それは歪で、移行のコストは高くなっていく。

### About Microservices
- マイクロサービスなシステムは小さく、一つの関心事のみのために作られる。そして、それぞれのマイクロサービスはそれぞれのデータのみを保有する。
- マイクロサービスは、自分自身に境界付けられたコンテキストのみをサポートし、他のマイクロサービスと何も共有せず、ただ定義されたインターフェースを公開し、何にも依存しない。
- 上の定義に従えば、テスト・開発・デプロイは容易なものになる。

### Functionally First, Data Last
- データベースの分割は、ソースコードの分割よりも複雑で困難。
- まずは機能的にモジュールを分割していく。そして機能的にその切り離したマイクロサービスの関心事が最小になったところで、そのサービスが処理するリクエストやモデルを分析し、切り離したサービスのみが扱うデータベース(スキーマ)を切り出す。
- この方法が最も移行のコストを下げる方法。

![DataAnti.png](https://qiita-image-store.s3.amazonaws.com/0/301386/278a942d-8c68-e35f-561b-e2d5b60d7744.png)




## The Timeout AntiPattern

### About Microservices
- マイクロサービスアーキテクチャは各サービスが定義されたプロトコルを使用して互いに交信しあう。
- マイクロサービスアーキテクチャの困難の一つにサービス間の可用性・応答の管理がある。


### Using Timeout Value
- `Consumer`であるマイクロサービスが接続もしくは購読をしている最中に`Publish`側サービスからの応答が来なくなった場合、`Consumer`サービスは無期限に待機するか、定義されたリトライ回数分のリトライを行うだろう。
- こういう場合、`Publish`側が配信を行っていないことはどうすれば`Consumer`は確認できるか。この場合、よく使われるのはタイムアウト値を設定することである。
- しかし、タイムアウト値には欠点がある。例えば、サービス間の平均通信レイテンシが`1000ms`だとして、最大レイテンシは`5000ms`だとする。タイムアウト値を`5000 × 2 = 10000`msと設定したとすると、ユーザーがエラーだと気づくまでに10秒かかることになる。これがタイムアウト値設定の場合の欠点。
でも、これそもそものレイテンシ遅くない。。？

### Using The Circuit Breaker Pattern
- 次はサーキットブレーカという死活監視をサービス間に置く方式。
- サーキットブレーカは何らかの方法(ping,etc..)で`Publish`サービスの状態を監視し、もし`Publish`が応答を返さなくなったら、サーキットブレーカを通過していた`Consumer`からの通信対して、`Publish`サービスが応答を返さなくなったことを伝える。
![circuitAnti.png](https://qiita-image-store.s3.amazonaws.com/0/301386/712e9d4c-b955-a543-f9b0-36e196e06178.png)

- サーキットブレーカパターンはいくつかの著名なOSSでも使われている方式で、タイムアウトはアンチパターンとなっていた。

## The "I was Taugut to share" AntiPattern

### About Microservices
- オブジェクト志向プログラミングで作られたアプリケーションでは、文字列を扱うユーティリティや汎用的な計算ロジックを含んだ共通モジュールを、いくつかのモジュールで共通で参照する構成はよく見られる。
- しかし、これはマイクロサービスにおいてはデプロイ・テストなどの容易性を実現するに当たって、障害となってしまう。ではどうすれば共通ユーティリティモジュールを`100`を超えるマイクロサービスでも共通的に扱えるようにすれば良いのか。


### 4Patterns
記事では4つのパターンが紹介されていた。

##### Shared Project
- 共有ユーティリティをプロジェクトとしてマイクロサービスのプロジェクトと共有しておき、コンパイル時に動的にバインディングする方法。これは開発効率については有益だが、変更を誰がなぜ行ったのか、ということがわかりづらく、リリース間際になって共通ユーティリティの変更が破壊的な影響をサービスに与えてしまい、テストをし直すという状況にもなり得る。


##### shared Library
- 共通ユーティリティをモジュールとして管理する方式。これは開発効率を損なう可能性はあるが、
`Shared Project`よりも優れている点はバージョン管理が可能ということ。サービスのオーナーはバージョンアップされたモジュールを使うか、現在バージョンのモジュールを使うが明確に判断が下せる。

##### Replicated
- 共通ユーティリティを各サービスコンポーネントがそれぞれ保有する方式。これは`DRYの原則`には反するが、依存を外部に全く持たなくなるという点では有利。だが、この方式の欠点は共通ユーティリティにバグがあった場合、全てのコンポーネントの保有する共通ユーティリティを修正しなければならないということ。そのため、この方式をとる場合はその共通ユーティリティが変更が限りなく少なく、安定したモジュールである場合に限るだろう。

##### Consolidation
- この方式は共通ユーティリティを分解して、サービスごとに特化した部分のみを各サービスに分離して含めるという方式。つまり事実上、共通ユーティリティを使わないという方式だと言っているように思う。これは使用している共通ユーティリティが頻繁に変更されるものであれば、検討しても良いかもしれない。


## 続く
今回は三つのアンチパターンとそれに対するプラクティスを記載した。

- Data-Driven Migration AntiPattern
- The Timeout AntiPattern
- The "I was Taugut to share" AntiPattern

継続して投稿していこうと思います。