マイクロサービス分割に着目してContinuous Deliveryを形作る
こんにちは。@Juju_62qです。
この記事はJAWS DAYS 2020で話す予定だった内容です。人によっては当たり前のようにできているのかもしれません。
まずは遅れてごめんなさい。本当はスライドは作ろうと思っていて途中まで作っていたのですが、喋らないと思うとどうにもやる気が出ず、一方できちんと形には残したいと言うことでブログに書くことにしました。 新卒1年目の学びを形に残す意味でもスライドについてはそのうち完成させたいと思っています。
このブログで出してる意見は完全に自分の意見なので異論反論同調意見あれば是非お聞かせください。
TL;DR
- マイクロサービス -> イケてるアーキテクチャ、と言うわけではない
- マイクロサービス分割はビジネス境界で行う
- モノリシックにすることをイメージしてマイクロサービスアーキテクチャを設計する
- サブシステムのどこを切り取ってもデプロイ可能なようにする
前提
登壇時は補足しようと思ってましたが本記事は
の考えに追加したものになります。あらかじめ目を通していただけると多少スムーズに理解ができると思います。
マイクロサービス化のモチベーション
マイクロサービス化のモチベーションってなんでしょう? 基本的にはビジネスの成長速度を落としたくないと言うものだと思います。 ビジネスの成長を落とさないためのマイクロサービスの採用理由はなんでしょう?
- アプリケーションごとの最適な技術選定
- アーキテクチャの拡張性と自由度
- 単一アプリケーションのビジネスロジック肥大化の抑制
- アプリケーションの廃棄性向上
- 権限分離による意思決定の速度上昇(逆コンウェイの法則のような狙いも含む)
よく言われるのがこの辺りになると思います。 そもそもこの辺りの特性をマイクロサービスアーキテクチャは満たすのでしょうか? あるいはこれらの特性はマイクロサービス アーキテクチャじゃないと満たさないのでしょうか? 考えていきたいと思います。
マイクロサービスアーキテクチャと自由と制限
これから考えていくのは下記の2つの項目です。
- アプリケーションごとの最適な技術選定
- アーキテクチャの拡張性と自由度
アプリケーションごとの最適な技術選定
まずこちらですが、理屈の上では可能でしょう。 一方で、マイクロサービスアーキテクチャだからといって本当に自由な技術選定ができる現場は多いわけではないです。 まず持って優秀なソフトウェアエンジニアの数は会社内で常識的な数で有限でしょうから、調査を無限にできるわけではないでしょう。 ビジネスを大きくするにあたり、多くの場合機能の修正や拡充と言うのは必要不可欠です。 そうなるとある程度蓄積すべきノウハウを絞ってルールを形作ることが多いです。 マイクロサービスだからといって完全に好き勝手技術選定を行うのはバッドノウハウと言われています。
したがったマイクロサービスの開発ではSREやPlatformチームと呼ばれる人あるいはそれに準ずる作業をしている人がある一定のルールを設けていることが多いです。 つまるところ、マイクロサービスアーキテクチャを採用していても常識的には一定の制限がかかると言って差し支えありません。
アーキテクチャの拡張性と自由度
では拡張性や自由度と言う面ではどうでしょうか? マイクロサービスアーキテクチャでは高い抽象度のアプリケーションが協調してシステムとして成り立つため柔軟性が高く拡張性や自由度が高いと言う物言いが頻繁にされます。 これは真であり偽であると思っています。
マイクロサービスアーキテクチャではマイクロサービスアプリケーションを前提とした機能拡充は比較的容易にできると言えます(これは実感としてもそうです)。 一方でマイクロサービス分割の境界を間違えた場合アプリケーションの開発難易度は跳ね上がります(だからこそ、多くの場合マイクロサービスアプリケーションの責務決定には細心の注意が払われます)。
オライリーのマイクロサービスアーキテクチャでは分割を間違えた企業がモノリシックなアプリケーションに直し、分割をやり直したと言う例が載っていました。このやり方はおそらく正しくて、マイクロサービス to マイクロサービスで間違ったマイクロサービス の分割を正そうとすると単一の責任を持っているが故に責務の移譲が難しく多くの場合高い難易度になるでしょう。 しかしながら、やっているのはビジネスです。間違えることもあるだろうし、自身の変化よりも市場の変化が早いと言うことは多々あるでしょう。 そこで、この質問をしてみます。
あなたのマイクロサービスアプリケーションはモノリシックにすることができますか?
多くの場合これはNoでしょう。マイクロサービスアーキテクチャで開発されるアプリケーションはそれが分散システムであることを大前提としています。 また、分散システムであることを強要してくる場合も少なくないです。 耐障害性を求めて分散システムを組んだが故にどこで結合しているのかがわかりにくくなっているケースは少なくないと思います。 システムアーキテクチャの自由度を高めることがマイクロサービスアーキテクチャの採用理由だったはずなのに、それを適切に進めていった結果モノリシックなアプリケーションを選択する自由が失われています。
以上から自分は、マイクロサービスアーキテクチャの採用により柔軟性が高まると言う考え方は真であり偽であると捉えています。
マイクロサービスアーキテクチャは本当に最適?
さて、そもそもマイクロサービスアーキテクチャは本当に今"イケてる"技術なのでしょうか? マイクロサービスアーキテクチャが難しいことは頻繁に語られますが、それは高い技術力を持って正しく実行すれば解決するのでしょうか?
例えばサービスメッシュを実現するためのアプリケーションとして注目されているIstioは、モノリシックなアプローチを利用してリアーキテクチャを行いました。
Prometheusライクにログ収集を行うことができるlokiは明確にモノリシックアプリケーションとマイクロサービスアプリケーションをサポートしています。
このように技術的な最先端をいくようなツールでも必ずしもマイクロサービスアーキテクチャが採用されるわけではなくなってきました。 ではどうやって下記のようなメリットをとりにいくのでしょうか?
モノリスのままマイクロサービスアーキテクチャのエッセンスを取り入れる
一例としてShopifyのModular Monolithのような考え方があります。
これはモノリシックなアーキテクチャのままビジネス分割を区切り、アプリケーションをモジュラブルに作り上げることでビジネスロジックを小さく保ったり、アプリケーションの廃棄性を高めるという手法です。 もちろん、マイクロサービスアプリケーションほどの強制力は働きませんから、権限分離による意思決定の速度上昇のような内容は少し作用として弱くなるかもしれませんが、場合により必ずしもマイクロサービスアーキテクチャでなくてもその設計思想に基づいたメリットを得ることはできると思っています。 逆に言えば権限分離による意思決定の速度上昇を逆コンウェイの法則に基づき強制的に進めたい場合はマイクロサービス は明確なメリットとなりうるのかもしれません。
モノリス vs. マイクロサービス
マイクロサービスアーキテクチャは一気に広がり、現在アーリーマジョリティくらいの領域で利用されるようになったんだと思います。 一方でここまでの解説で分かるように最先端においては"部分的に"マイクロサービスアーキテクチャからからモノリシックアーキテクチャへの揺り戻しが来ているように見えます。 優れた技術者が作成しているにも拘らずです。
この構図どこかで覚えがありますね。オペレーティングシステムも似たような変遷を辿っています。 オペレーティングシステムでもマイクロカーネルと呼ばれる実装方法が提唱され、従来のものがモノリシックカーネルと呼ばれるようになりました。 では現在のLinuxがどうなっているかと言うとマイクロカーネルともモノリシックカーネルとも言えない実装に合わせていいところを取った形式となっています。
現在のマイクロサービスアーキテクチャに対する期待感からの揺り戻しも、マイクロサービスを完全にやめようとなるのではなく、対象のビジネスやとりたい特徴に合わせて採用するものを変えていく形になっていくと思います。 大仰な言い方をするのであればマイクロサービスアーキテクチャ全盛期が終わったと言えるのかもしれません。
マイクロサービス分割で考えること
さて、ここまでの解説で分かるように僕自身はマイクロサービスアーキテクチャについて話をしていますが、マイクロサービスアーキテクチャに過度に肩入れするつもりはありません。 そしてマイクロサービス分割の話を知るためにこのブログを見てくださっていると思いますが、最適なマイクロサービスに分割する体系的な手法は存在しません。そのビジネス、対象とするドメインに思いを馳せましょう。
その上でマイクロサービス分割をするときに自分が考えていることを記述します。 マイクロサービスアプリケーションなので前提としてそれぞれが課題を解決するための抽象化されたモデルをもちます。
再三言いますが、これは自分が個人として分割する際に気をつけていることです。
モノリシックアーキテクチャにすることをある程度イメージする
マイクロサービスを常にマイクロサービスアプリケーションとして捉えるのではなく、マイクロサービス郡がどのようなサブシステムを構成しているのかを強く意識しましょう。 前提としたブログでは数が多いと考えられないためにある程度大きなサブシステムに分割するということを記述しましたが、大きなサブシステムをイメージすることで、自身が区切ったマイクロサービスアプリケーションをどうすることでモノリスにできるのかを考えやすくなります。 必ずしもそうではないですが、DDDでいうとマイクロサービスがドメイン、サブシステムを境界づけられたコンテキストと考えるとイメージがつくかもしれません。
これによりマイクロサービスアーキテクチャでありながらモノリシックなアーキテクチャにする自由をある程度得ることができます。 場合により、サブシステムの中でのコミュニケーションではある程度マイクロサービス"らしさ"を捨ててもいいのかもしれません(一貫性の問題など許容しづらいものもある)。 このサブシステム分割の際、サブシステムがシステムにとってモジュラブル且つ、サブシステム内部のマイクロサービスアプリケーションをモジュラブルに表現することをイメージすると管理しやすくなります。 もちろんサブシステムの下の階層は必ずしもマイクロサービス アプリケーションでなくてもよく、マイクロサービスを束ねたサブシステムでもいいと思っています。
第一にビジネスコンテキストを分割する
よく言われますが、技術的な内容を第一の分割の単位にするのはあまり得策ではないです。 例えばbatchのようなアプリケーションは一見バッチ処理を行うという単一の処理を持ちますが、バッチだからとなんでも詰め込んでいくと結局何をリリースするにもbatchのデプロイが必要になります。 これではマイクロサービスアーキテクチャとモノリシックアーキテクチャの悪いところを両取りしてしまいます。 対象のドメインをきちんと考え、どのサブシステムに所属する機能なのかをきちんとイメージしましょう。
その上で技術的な理由でアプリケーションを切り分けたいケースは多々あるでしょうから、それは問題ないと考えています。
循環依存を回避する
前提のブログでも書きましたが循環依存は管理が非常に難しいです。 マイクロサービス、サブシステム間の関係はDAGで表現しましょう。
アプリケーション中心に見るContinuous Delivery
ここまでほぼ全てマイクロサービスの説明や、マイクロサービス分割について話をしてきましたが、ここまでくるとCDは比較的作りやすいです。 意識すべきことは2つだと思っています(ライフサイクルの違いについては話が逸れるため別途ブログを書きます)。
- サブシステムを常にデプロイの単位として捉える
- サブシステムごとに入れ子構造を作る
つまりこれ
の場合下記のようにするとわかりやすいです。
./System ├── SubSystemA │ ├── MicroserviceA │ └── MicroserviceB └── SubSystemB ├── MicroserviceE └── SubSystemC ├── MicroserviceC └── MicroserviceD
この構成はTerraformでもKubernetesのmanifestでも表現することが可能です。 SubSystemAとSubSystemBの依存関係など並列なもので依存がある場合についてはコンテキストマップのようなものを使って整理するといいでしょう。
アプリケーションの分割に着目することで無理なくContinuous Deliveryを設計できたと思っています。 あるいはこのブログ全体でDelivery目線に立って自由度の高いアプリケーション分割を考えてきたとも取れると思っています。
終わりに
近頃はクラウドネイティブやマイクロサービスアーキテクチャへの異様な期待も少しずつ是正され、マイクロサービスアーキテクチャを少しずつ現実のものとして扱う人が増えてきました。 かくいう自分も決済という分散システムで扱いにくい領域でマイクロサービスアプリケーションを1年間開発・運用してきました。 経験の中でさらにマイクロサービスらしくありたいところ、モノリシックにしたいところなどはたくさんあり、もっとこうしたいという思いは絶えませんでした。 そんな中でいかに自由度の高いアーキテクチャを作ることができるかを分割やDeliveryの目線で考えたのがこのブログに書いた考え方と構成です。 もちろんこの記事の内容をベストプラクティスと主張するつもりはありません。ケーススタディと捉えて議論を発展させることができればと考えています。 これからも、ビジネス・プロダクトに最適なアーキテクチャを時代や技術の変化とともに模索していきたいと思います。
長文にお付き合いいただきありがとうございました。
余談ですが、この記事のOGPというかタイトル画像にしたの、アクセシビリティ界隈に怒られそうな気配を感じますね。