革命のブログ

フレボワークスの社員がブログを通じて情報発信します。

マイクロサービス化に悩んでる人へ

どうも、小野です。

以前、参加されていただいたAWS DEV DAYのMicroservicesのセッションを聴いて、
改めてマイクロサービスの有効性や複雑性など再認識させられました。

特に、以下のスライドがとても参考になりました。

www.slideshare.net

今はバスワードとも言える「マイクロサービス」。

マイクロサービスとよく比較されるものとして、モノリシックというアーキテクチャがあります。

モノリシックは1枚岩と表現されるとおり、1つの巨大なシステム(サービス)のことです。
管理対象は1つなので、管理は楽そうではありますが、以下のようなデメリットが挙げられます。

  • プログラム修正時の影響範囲の把握が難しい
  • テストを含むビルドに時間がかかる

これは最終的にリリースサイクルのスピードに関わってきます。

これらを解決するために考えられたのが、マイクロサービスです。

私もマイクロサービスについて勉強し、導入を検討しましたが、結局断念しました。
断念した理由ですが、主に以下の3つが挙げられます。

  • 実装での考慮すべき点が多く、実装コストの増加につながる
  • エンジニアが足りない
  • リリースのスピードが求められていない

当時携わっていたシステムは受託PJだったため、スケジュールも決められており、
実装コストをなるべく抑え、品質を重視する必要があったため、断念せざるを得ませんでした。
その上、人が全然足りず、マイクロサービスをやっていくのは自分の首を締めるだけでした。

本記事ではマイクロサービスの導入によって、どこまでのメリットが得られるか考えながら読んでいただきたいです。

マイクロサービスのメリット

新しい技術を導入する際、メリットとデメリットを確認すると思います。
ここで、まずはマイクロサービスのメリットについて述べていきたいと思います。

技術異質性

サービスごとに異なった技術での開発が可能になります。
つまり、チームごとに得意な技術、または新しい技術で挑戦できます。

回復性

障害が起きても、問題のあるサービスを切り離すことで、他のサービスを稼働し続けられます。
もちろん、その間は問題のあるサービスに対する処理(リクエストなど)は動作しません。

スケーリング

サービス単位でのスケールが可能になります。
例えば、アクセスが多いサービスにはインスタンス3つ、アクセスが少ないサービスにはインスタンス1つなど、
柔軟に効率よくスケールできます。そのため、モノリシックに比べ、コスト効率が良くなる場合があります。

デプロイの容易性

サービス単位でのデプロイが可能になり、システム全体としての影響を最小限に抑えられます。
他のサービスとは独立しているため、迅速なデプロイが可能です。

マイクロサービスは諸刃の剣

マイクロサービス導入で得られるメリットはありますが、一歩間違えると「諸刃の剣」と化します。
その理由を前項で挙げたメリットと比較してみていきます。

技術異質性

サービスによって最適な技術が必要なのは重要ですが、本当に必要か疑問に思います。
逆に技術を統一化することで、モジュールの再利用性も高まるのではないでしょうか。
例えば、新しい技術を使ったあるサービスのメンバーがいなくなったら、メンテナンスできる人いますか?

回復性

問題があるサービスがアカウント(ユーザ)などのシステム全体の基盤となるサービスの場合、全体に影響が及ぶことになります。
あと、原因の追求が困難になることもあります。 例えば、サービス内部ではなく、サービス間通信のネットワーク障害や、マシンの障害なども関わってきます。
サービスごとのログをfluentdなどを使って集約した状態で管理しておかないと、各サービスのログを確認する必要が出てきます。

スケーリング

管理するマシンの対象が増えるため、AWSのECSなどのクラウドサービスを利用しない限り、 困難です。あと、クラウドサービスを利用した場合でも、各サービスの負荷状況などを常に監視しないと、 無駄なコストがかかってしまいます。

デプロイの容易性

修正したソースをデプロイする際に、Githubなどのソース管理から取得することがほとんどなので、 サービスごとにリポジトリを分ける必要があります。 つまり、サービスごとにバージョンを意識する必要があります。

技術的なトレードオフ

マイクロサービスにすることで、技術的に考慮すべき点は多くありますが、 ここではデータベース分割(ドメインの分割)による問題について考えてみます。

データベース分割(ドメインの分割)による問題

N+1問題

とくに個人的に難しいのはデータベース分割(ドメインの分割)によるデータの扱い方です。
基本的にサービスによって管理するテーブルは分かれますので、
モノリシックでは、データを取得する際に結合(JOIN)で取得できていたものが、
マイクロサービスでは、親(結合元)を取得し、付随するサービスのデータを取得するために、親のレコード分のクエリを実行するN+1問題が発生したりします。

N+1問題については解決する方法はありますが、クエリの煩雑化やパフォーマンスなど別の問題が出てきます。

トランザクション管理

例えば、A口座からB口座へ振り込みをしたときの例で考えてみます。

登場人物としては、振込サービス、出金サービス、入金サービスがあるとします。

振り込みを行った際の主な処理は以下のとおりです。

  1. 振込サービスが出金サービスを呼び出し、A口座から100万円を出金
  2. 振込サービスが入金サービスを呼び出し、B口座に100万円を入金

ここで、2.を行うときに失敗した場合はどうなるでしょうか。

モノリシックであれば、トランザクション境界が同じであるため1.の処理もロールバックしてくれますが、 マイクロサービスの場合はどうでしょう。

トランザクション境界が別なので、モノリシックと同様の実装だと、1.のみコミットされることとなり、データの不整合が発生します。

ではどうするか。

振込サービスが2.でのエラーを検知した際、1.の処理を戻すトランザクションを発行する必要があります。 つまり、100万円を出金したレコードを削除します。 あとは、分散トランザクションを利用する方法がありますが、実装がより複雑になります。

サービス間でのデータの受け渡し

サービス間でのデータの受け渡しには多くの場合HTTPを利用することになります。 内部のネットワークに限るのですが、ネットワークを介すということはネットワーク障害時のことも考慮する必要があります。

通信間で考慮すべきことにはリトライ処理や、タイムアウト時の処理中断などがあります。

データベースから直接取得したほうが、実装が単純な上、パフォーマンスも良いです。

マイクロサービスを導入したい人は

マイクロサービス化することでメリットもありますが、このような技術的に複雑化になるので、 そこはビジネス要件を考慮した上でのトレードオフになるのではないでしょうか。

ここで、以下のチェックリストをやってみてください。

現在、モノリシックなシステムがある
リリースサイクルの早く回したい
システムの規模に対するリソースが足りている
マイクロサービスを熟知している人がいる、またはメンバー全員が意欲がある
CI/CDなど自動化の仕組みがある

全てチェックの場合はマイクロサービスの導入を検討してもいいと思います。
逆に未チェックが1つでもあった場合は、異なるアプローチがないか検討してください。

さいごに

マイクロサービスというのはあくまでもアーキテクチャの方針であり、実装方法は十人十色です。

マイクロサービス前提ではなく、極力マイクロサービス化しないような作りにするべきであり、 ビジネスの観点でみたときに、モノリシックでは補いきれない状況になって初めて、 マイクロサービス導入を検討するべきだと思います。

今すぐにマイクロサービスをやりたい人は、小さいなところから始めるようにしてください。

決して無理をしないこと

参考文献

https://www.amazon.co.jp/%E3%83%9E%E3%82%A4%E3%82%AF%E3%83%AD%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3-Sam-Newman/dp/4873117607/ref=cm_cr_arp_d_product_top?ie=UTF8www.amazon.co.jp