Rのつく財団入り口

ITエンジニア界隈で本やイベント、技術系の話などを書いています。

【感想】『マイクロサービスパターン 実践的システムデザインのためのコード解説』:後編

マイクロサービスパターン

 同書の読書記録と感想、長いので3回に分けた最終回です。

microservices.io

f:id:iwasiman:20210123161130p:plain
マイクロサービスパターン

Chapter 9 マイクロサービスのテスト(前編)

 本書が引用しているレポートによると、テスト自動化が進んだ企業は26%、完全自動化した企業はたったの3%とのこと。マイクロサービスでいかに自動テストを効果的にやっていくかを探求する章。

9.1 マイクロサービスアーキテクチャのテスト戦略

最初はテストの入門ということで、知っている方にはおなじみのテスト入門の話が続きます。

  • 例に上がっているのはJavaJUnitで、セットアップ-メソッド呼び出しで実行-チェック(assert)-ティアダウンのいつもの順番。
  • あるサービスのテストで障害になる依存する他サービスは、振る舞いをシミュレートする「テストダブル」に置き換えてテストする。
  • スタブ(stub)実行したいメソッドなどに値を返すためのテストダブル。
  • モック(mock)依存サービスを正しく呼び出すことをチェックするためのテストダブル。このモックがスタブを兼ねることはある。

 スタブとモックの違いはよく混乱しますね…(自分もよく間違えます) gotohayato.com

  • エンドツーエンド(e2e)テスト:アプリケーション全体の受入テスト。
  • コンポーネントテスト:個々のサービスの受入テスト。
  • インテグレーションテスト(統合テスト):DBや他のサービスと連携できるかを含めたテスト。
  • ユニットテストサービスを構成するコンポーネント、クラスレベルのテスト。
  • この4階層のテストピラミッドで、
    下→上 ユニットテスト→インテグレーションテスト→コンポーネントテスト→e2eテスト
    と下の方ほど高速にテストでき信頼性が高く低コスト。上に行くほど時間もかかりコストが掛かる。本書ではユニットテストなど下の階層のテストを重要視することを推奨。microservices.ioの記事に図があります。

microservices.io

サービス間のテストでは、API Gatewayなどの投げ側を「コンシューマー」、サービスのAPIなど受け側を「プロバイダー」とし、「コンシューマ駆動契約テスト」というやり方を提唱しています。

<Consumer-driven contract test>パターン
サービスがクライアントの想定に合致しているかをチェックする。

<Consumer-side contract test>パターン
サービスのクライアントがサービスと通信できることをチェックする。

 同じようなことを言っている気がするのですが、紹介されているのはSpringフレームワークのファミリーに含まれている契約テストのフレームワークSpring Cloud Contract
 こういうリクエストが来たらこういうレスポンスが返るはずだ……という契約(Contract)のテストをAPI Gateway側が書いてバージョン管理システムに入れて受け側のサービス側がテスト、続いてその逆……の流れでやっていくというもの。
 デプロイのパイプラインの話も出てきて、やはりテストを効果的にやっていくにはCI/CDと自動テスト環境は必須なのだな……と思います。

spring.pleiades.io

9.2 サービスのユニットテストの開発

以下2つの分類に分けるのがよいとしています。

単独のユニットテスト(solitary unit test)
クラスが依存するサービスにはモックオブジェクトを使って代用、クラスを単独でテスト。

  • OrderServiceのような、ビジネスロジックのクラス
  • OrderControllerのような、クライアントからのHTTPリクエストを受け取ってサービスに渡すクラス
  • 他のサービスにメッセージを飛ばしたり受け取ったりするメッセージアダプタのクラス

社交的なユニットテスト(sociable unit test)
クラスが依存するサービスは本物を使ってテスト。

  • DBに実際に永続化されるエンティティのクラス
  • Moneyクラスのような、ビジネスロジックの中の値オブジェクトのクラス
  • CreateOrderSagaのようなサーガのクラス

JUnitなど使った実際のコード例が上がっています。

  • Orderエンティティのテスト:JUnit標準のやり方で実際にcreateOrder()してDBにINSERTして結果を確認。
  • Moneyクラスのような値オブジェクトのテスト:JUnit標準のやり方で実処理の結果をふつうにassertする。
  • サーガのテスト:Eventuate Tram Sagaテストフレームワークを使い、.given().expect()を比較
  • OrderServiceのようなドメインのテスト:メンバ変数で持っているリポジトリ、イベントパブリッシャ、Saga管理のクラスをモックに変える。そのうえでOrderService.createOrder()などをして結果を確認。
  • コントローラーのテスト:Spring Frameworkの一部のSpring Mock MVCや、Rest Assured Mock MVCなどのテストFWを使うのが良い。このリクエストが飛んで来たらステータスコードはこれのはず、などをテストに書いて実行する。
  • イベントやメッセージハンドラのテスト:Eventuate Tram Mock MessagingというFWを使っている。

テストピラミッドの底辺のユニットテストが一番重要で時間をかけるべきで、モックやテスト用フレームワークをうまく活用していくのが大事ということですね。

spring.pleiades.io

Chapter 10 マイクロサービスのテスト(後編)

 テストピラミッドの4階層一番下のユニットテストが終わったのでその上へ。統合テスト→コンポーネントテスト→e2eテストの3階層を語っていく章。

10.1 統合テストの開発

下から2階層目の統合テストはテスト対象のサービスが依存サービスと正しく通信できることをチェックし、ここにはDBなどインフラが含まれます。

  • 永続化の統合テスト:Javaのデータ永続化APIJPAを使ってDBに保存する例。OrderRepositoryクラスを呼んで実際にINSERTして、それが検索できるのを確認する。
  • リクエスト/レスポンスの通信の統合テスト:Spring Cloud Contractを使うと契約を使ったテストができる。このリクエストが来たらこのレスポンスが返るはず、というのを契約に書く。
  • パブリッシュ/サブスクライブの通信の統合テスト:こちらも契約によるテスト。
  • 非同期リクエスト/レスポンスの通信の統合テスト:インプットのメッセージでとアウトプットのメッセージを書いた契約でテスト。

ここでSpring Cloud Contractを使った場合の構成図が載っているのですが、大掛かりな仕組みでかなり複雑です。単純なサービスだったら実際に動かした方が早そうな気もしました。

10.2 コンポーネントテストの開発

 下から3階層めが、テスト対象のサービスを「コンポーネント」と見立てて単独で動くか受け入れテストをする、コンポーネントテスト。

<Service component test>パターン
ほかのサービスから分離して単一のサービスをテストする。

一般には他のサービスはスタブ(値を返すためのテストダブル)を使うそうで、受入テストの文章を記述していくDSL(ドメイン固有言語)の仕組みである Gherkin が紹介されています。これ昔どこかで聞いたような……

  • フィーチャー(機能)で、もしこのユーザがこの条件でこれをやったらこれが行われる……というのを文章で書く。
  • Gherkinで書かれたテストを実行するテストフレームワークCucumberがある。文章がアノテーションで加えられたテストメソッドを作ってくれる。

cucumber.io

コンポーネントテストの設計としては2つの選択肢を提供しています。

  • プロセス内コンポーネントテスト:依存サービスは代わりにモックやスタブを使う。Spring Bootのテストフレームワークではインメモリの別DBを使ってこれが実現できる。高速に動作。
  • プロセス外コンポーネントテスト:各種DBやApache Kafkaのようなメッセージブローカーは本物、顧客やレストランサービスのような他のサービスはスタブを使う。Spring Cloud Contractを使うとスタブが作れるが、仕組みが重いという欠点がある。

テストコードの例はJavaビルドツールのGradleを使っていて、依存サービスはDockerコンテナ上で動かすGradle Docker Composeを使うとのこと。こういうシーンでDockerを使うこともあるのか……と思いました。

qiita.com

10.3 エンドツーエンドテストの開発

 テストピラミッド4階層の一番上。遅く、脆く、開発に時間がかかるのでなるべく浅くしましょうと推奨しているe2eテスト。
ユーザがシステムを実際に操作する流れに沿ったテスト、何かを新規に作ってそれを変更し削除……のような流れに沿ったシナリオのテストにして、なるべく短く済むようにするのがよいと述べています。テストフレームワークを採用してDockerコンテナ上でやろうとしても、起動に4-5分もかかったりするそうです。

 xUnitシリーズのようなテストツール、スタブやモック、テスト用フレームワークをうまく使い、テストピラミッドの上よりも下に力を入れてテストしていく。
このへんはマイクロサービスでもモノシリックなアプリケーションと根本は変わらず、マイクロサービスの方が外側との連携が多い分さらにテスト自動化が重要である、と理解しました。
テスト駆動開発』『リファクタリング』『レガシーコードからの脱却』などなど一連の書籍で紹介されているテスト技法やテスタブルな設計周りのテクニックも役に立ちそうです。

テスト駆動開発

テスト駆動開発

Chapter 11 本番環境に耐えられるサービスの開発

 マイクロサービスでセキュリティ、設定可能性(configurability)、可観測性(observability) の3つの品質属性をどうやっていくかを追求する章。

11.1 セキュアなサービスの開発
  • 認証(Authentication):アクセスするアプリもしくは人間が正しいか。クレデンシャルでチェックする。
  • 認可(Authorization):指定されたデータに要求する操作をして良いのか、指定された機能を使って良いかなどの権限チェック
  • 監査(auditing):操作を追跡してセキュリティ上の問題やコンプライアンス、後からの調査に役立てる
  • セキュアなプロセス間通信:TLSを徹底したい。

dev.classmethod.jp

 FTGOサービスのモノリシックだった頃の認証の仕組みが載っています。SpringフレームワークファミリーのSpring Securityを使っていたという設定で、認証を通るとJSESSIONIDというセッションのIDがセッショントークンとして返り、クッキーにセットしてその後使う...という標準的な仕組み。認証を通った後に保持するユーザ情報などは「セキュリティコンテキスト」という言い方をしています。

spring.io

マイクロサービス化に当たってのセキュリティの問題点は……

  • インメモリなセキュリティコンテキスト:サーバー側でメモリ上のセッションに保持している情報をモノリシックなら共有はできるが、複数のサービスでは共有できない。
  • 中央集権化されたセッション:サービスそれぞれでセッションが別になるので別の仕組みが必要。

 沢山あるサービスがそれぞれ認証を行うこともできますが、もっと優れたアプローチとしてして紹介しているのが、リクエストが一番最初に到達するAPIゲートウェイで認証を一括して行う方法。

<Access token>パターン
APIゲートウェイが後ろのサービスを呼び出すとき、IDやロールなどユーザ情報が入ったトークンを渡す。

APIゲートウェイの認証機能を通過するとクライアントにはセキュリティトークンが返り、次からのリクエストには常にセキュリティトークンを一緒に渡すというもの。このへんはWeb APIを使う時にはもう一般的ではないでしょうか。
 トークンの中身にはUUIDJWT(JSON Web Token)も紹介されていますが、セキュリティ標準として一般化した OAuth 2.0 を使うことを強く推奨しています。

openid-foundation-japan.github.io

クライアントがAPIクライアントの場合:

APIクライアントがクレデンシャル情報と共にリクエスト→APIゲートウェイ
→OAuth2.0認可サーバーに飛んで認証を実行、成功するとアクセストークンとリフレッシュトークンを返す
APIゲートウェイは得られたアクセストークンと一緒に後ろのサービスにリクエス
→結果をAPIゲートウェイ→クライアントに返す

クライアントが人間でログイン画面からログインする場合:

id/パスワードがクレデンシャル情報としてリクエスト→APIゲートウェイ
→OAuth2.0認可サーバーに飛んで認証を実行、成功するとアクセストークンとリフレッシュトークンを返す
APIゲートウェイはそこから後ろのサービスに行くのではなく、一旦クライアント側に得られたアクセストークンとリフレッシュトークンを返す
→クライアントはアクセストークン/リフレッシュトークンと共にリクエスト→APIゲートウェイ→サービスへ

と流れが若干違います。人間が画面からアクセスする場合はログインしっぱなしで認証を維持する必要があるため、期限が切れたらリフレッシュトークンを使ってアクセストークンを新しく取り直すという違いがあるからですね。

qiita.com

11.2 設定可能なサービスの設計

 ソースコードに設定情報を直書きハードコードはいけない……というのはモノリシックというかアプリケーション開発の基本、これを外から設定するのをどうやるかという節。

<Externalized configuration>パターン
DBのクレデンシャルやネットワーク位置などの設定可能な値を、実行時にサービスに提供する。

プッシュモデル:
デプロイを管理してくれるインフラの仕組み側→サービスインスタンスに設定する。
例に上がっているSpring Bootでは、様々なインプットからの値を柔軟に読み取り、アノテーションを使ってコード内のクラスにセットできる。プッシュモデルは実行中のサービスには適用できず、サービス再起動が必要になる。

プルモデル:
サービスインスタンス側主体→設定サーバーにアクセスして設定を取ってくる。
設定を一元管理し、暗号化/復号化を設定サーバー側でやったりできる。サービスがポーリングして自分から定期的に取りに行けば、動的に設定変更もできる。
設定サーバーとして使えるものには以下がある。

ここでParameter Storeが出てきて、なるほどこういうところで繋がるのか……と分かりました。

docs.aws.amazon.com

11.3 可観測性を備えたサービスの設計

 日本語だと「かかんそくせい」が言いにくいですが、外側からの監視のしやすさをどうしていくかのパターンの話。互いに二者択一ではなくすべて使える、全6パターンが紹介されています。

<Health check API>パターン
サービスは自分の稼働状態を返す GET /health などのヘルスチェックAPIのエンドポイントを公開し、観測する側に伝える。

起動中だったりInternal Server Error だったりDBと接続に失敗していたり、生きているか死んでいるかを伝える話。これはクラウドだとお馴染みですね。
Spring BootにもSpring Boot Actuator、.NETにも同様に実現するライブラリがあるそうです。実装する際は固定値を返したり、DBに接続できるかや他のサービスと接続できるかを試して返すなど凝ったこともできます。

spring.pleiades.io

<Log aggregation>パターン
検索と警告をサポートする中央の一元管理されたDBに、すべてのサービスのログを集約する。

各サービスがそれぞればらばらなログを吐き出していたら調査ができないので、ログ集約パイプラインを通してロギングサーバーに集約、監視する側はここを見ると。実際に実現しているOSSや製品としては……

  • Elasticsearch テキスト検索に強いDB。
  • Logstash ログパイプライン
  • Kibana Elasticsearch用の可視化ツール。この3つで「ELKスタック」と呼ぶ。
  • Fluentd
  • Apache Flume
  • AWS CloudWatch Logs

これらのキーワードもSRE関係の文脈でよく見聞きします。

www.elastic.co

www.elastic.co

<Distributed tracing>パターン
すべてのリクエストに一意なIDを与えて中央のサーバーで記録、どのサービスを呼んだのかなどを解析できるようにする。

サービス間をリクエストがバンバン飛び交うような中では障害の解析も難しくなるので、どこからどこに流れてどこで障害が起こった、の流れが分かるようにするパターン。例に載っているのは以下でした。

  • Open Zipkin
  • Spring Cloud Sleuth

spring.io

<Application metrics>パターン
集計、可視化、アラートの機能を提供する中央のサーバーにサービスがメトリクスを送る.

 各サービスがCPUやメモリ、ディスク使用率、レイテンシーなど様々な情報を「メトリクス」として、メトリクス収集の仕組みにメトリクス名、値、タイムスタンプの組で送るもの。仕組みの側では「ディメンション」という単位で合計や平均を出せたりします。
 例としてJavaSpring Boot実装でOrderServiceクラスでの例が載っています。メンバ変数にMeterRegistry型のメトリクス機能用インスタンスを持っていて、各メソッドで承認や否認が行われたらその都度このインスタンスの処理を呼んでインクリメントさせていくというもの。これはイメージしやすいですね。

  • プッシュモデル:サービスの側からメトリクスサービスに送る。AWS CloudWatchはこちら。
  • プルモデル:メトリクスサービス側から、サービスのメトリクス用APIを呼ぶ。Spring Bootと連携しているPrometheusはこちら。

docs.aws.amazon.com knowledge.sakura.ad.jp

<Exception tracking>パターン
サービスが例外の重複を取り除いてアラートを生成、例外の解決を管理する中央のサービスに例外を送る。

 Javaのよくあるアプリケーションではログに例外(Exception)スタックトレースがずらずらーっと記録されますが、ひとつの原因で複数の例外が記録されたり解析も大変なので、これも別の中央の仕組みを使うと良いというもの。

  • REST APIで受け口がある例外トラッキングサービスを、サービスからコールする。
  • 例外トラッキングサービスのクライアントライブラリをサービス側で使う。こちらがよい。HoneyBadgerSentry.ioなど。

www.honeybadger.io sentry.io

<Audit logging>パターン
顧客サポートやコンプライアンスの徹底、怪しい動きの検出のためにユーザーの行動をDBに記録していく。

 こちらもクラウドでよく監査ログの話。聞くやりかたが3種類。

  • ビジネスロジック内へ監査用ロギングコードを入れる:分かりやすいが、ビジネスロジックと絡み合ったりしてメンテナンス性が下がる。コード追加を忘れてしまったりもあり得る。
  • AOP(Aspect Oriented Programming)の利用:Spring AOPなどアスペクト指向プログラミングの仕組みを使う。監査用ロギングコードの分が自動的に挟める。AOPの仕組みとしてメソッド名と引数にしかアクセスできないので細かい記録ができない。
  • イベントソーシングの利用:作成や更新のイベントごとの記録がそのまま監査ログにできる。ユーザのIDも記録する必要がある。

qiita.com

11.4 パターンを使ったサービスの開発

 ここまで上げてきた、各サービスごとにそれぞれ仕組みが必要になる「横断的関心事」を毎回ぜんぶ準備するのは大変。ということで……

<Microservice chassis>パターン
例外トラッキング、ロギング、ヘルスチェック、外部設定、分散トレーシングなどすべてのビジネスロジックで必要になる横断的関心事を、フレームワークもしくはフレームワークのコレクションを基礎として構築する。

 chassisの読みが戸惑いますが車の「シャシー」なんですね。「マイクロサービスシャシー」といういろんな雑務を処理する基盤のような仕組みが最初にあり、その上に各サービスを作っていけば各サービスの開発は楽になるよということ。例としては……

  • Spring Boot: <Externalized configuration>パターンを実現
  • Spring Cloud: サーキットブレイカー、サービスディスカバリの機能あり
  • Go言語の Go Kit
  • Go言語の Micro

qiita.com micro.mu

しかしこのマイクロサービスシャシーは、言語/プラットフォームごとに用意が必要という欠点があります。複数言語が混在したサービス群では使えない訳ですね。これを解決するのが……

<Service mesh>パターン
サービスを出入りする全てのトラフィックが、あるネットワーク階層を通過するようにする。その階層で横断的関心事を実装する。

ネットワークインフラストラクチャの階層で多くの雑務を解決する。こうすると各サービスの基盤に配置するマイクロサービスシャシーの仕事も減り、よりシンプルになる。デプロイも切り離せる……というもの。

  • Istio
  • Linkerd
  • Conduit

 クラウド関連の文脈で時々聞く「サービスメッシュ」ですが、なるほどここで出てくるのか……!と合点がいきました。

knowledge.sakura.ad.jp linkerd.io qiita.com

 11章に出てくる各種パターンはAWSAWS認定ですとちょうど『SysOpsアドミニストレーター - アソシエイト』資格に出てくるサービスなどと全部対応する感じで、SRE領域のキーワードが各種揃っています。なるほど、どのプラットフォームでも必要になる機能なのね…と思いました。

aws.amazon.com

Chapter 12 マイクロサービスのデプロイ

 デプロイに関する各パターンとそれぞれの長所短所を上げて深掘りしていく章。最初にデプロイの歴史が語られています。

  • 1990年代は物理マシンにWebLogicWebShereのような重アプリケーションサーバーがあって、そこにデプロイ
  • 2000年代になるとTomcatJettyのような軽量のコンテナが登場。
  • 2006年にAWSEC2が登場、クラウド上の仮想マシンの上にデプロイできるように。
  • 2013年にDockerがリリース、仮想マシンの上にさらにコンテナランタイムが動いてその上にデプロイ。
  • 2014年にAWS Lambdaがリリース、サーバーレス専用のランタイムの中に関数だけデプロイ……

 イントラネットに守られた奥のエンタープライズな開発だとまだまだ物理サーバーにデプロイが現役、WebLogicTomcatもまだまだ現役なのはニャンともかんともであります。
 心温まる手動リリースをしながら本番サーバーを一生懸命メンテするのを「ペットのように世話を焼く」、モダンな環境での仮想マシンやコンテナは立てたり破棄したりが簡単なのを「ペットでなく処分できる家畜」と表現しているのが面白いです。(なんかこれアメリカだと動物愛護団体からクレームが来そうな言い回しですが……)

12.1 <Language-specific packaging format> パターンによるサービスのデプロイ

<Language-specific packaging format> パターン
言語固有のパッケージをデプロイする。

 読んで字のごとくその名の通りのパターン。サンプルのFTGOアプリケーションはJava実装なので、クラス群と画面やCSSやJSなど一式をディレクトリごとZIPにまとめたWARファイルをデプロイ。Go言語ならOS固有の実行可能ファイルをデプロイ、JavaScript/Python/PHP/Rubyならソースコードごとデプロイ……となります。
 Javaでの構成例が載っています。

  • 1台のマシンに複数のTomcatを配置しそれぞれが別プロセスで稼働するやり方。その上でサービスのインスタンスがそれぞれ稼働。
  • 1台のマシンにひとつのTomcatでプロセスは1つ、その上にサービスのインスタンスが複数稼働するやり方。こちらはインスタンス同士が分離されなくなる。

 1つのWebサーバーの上に別々のWebアプリケーションとして配置するのはよくありますが後者がこれですね。
利点は以下。

  • 高速なデプロイ:ネットワークを介してコピーされる情報量が比較的小さく、一般的に速い。サービス起動も速い。
  • 効率的にリソースを使える:マシンやOSのリソースをうまく使える。特に1つのWebサーバーの上にサービスを複数乗せるとうまく共有できる。

欠点は以下。

  • テクノロジスタックをカプセル化できない:運用チームがそのデプロイ方法にまつわる知識を知っていなければならない。複数の言語やFWが混在すると、そのぶん知識が必要になってしまう。
  • 消費するリソースを制限できない:あるサービスインスタンスがCPUやメモリを消費しつくしてしまったりする。
  • インスタンス同士を切り離せない:1つのWebサーバー上で動かしていると、再起動すると全部一緒で落ちるなど。
  • サービスインスタンスをどこに配置するか自動的に決められない:マシンごとにスペックが違ったりすると、自動配置は無理で作業担当者が決めないといけない。

tomcat.apache.org

 エンプラ世界のシステムはまだまだこれで動いてるんだよな~と思いつつ、本書ではもうこのパターンは使わない方が良いとしています。よりモダンなデプロイ方法が、続いていくパターン群。

12.2 <Service as a VM> パターン

<Service as a VM> パターン
仮想マシン(VM)イメージの形でデプロイされたサービスをデプロイする。個々のサービスインスタンスVMである。

 サンプルのFTGOではAWS上に載せようとしています。レストランサービスのコードを含んだ一式がVMイメージビルダーを通し、VMイメージであるAMI(Amazon Machine Image)としてEC2インスタンスの素として生成。
 本番ではオートスケールするごとにこのAMIを元にEC2インスタンスの実体が増えていく……という、クラウドだといつものパターン。Netflix製のAminatorPackerAWSElastic Beanstalkも紹介されています。
 利点が以下。

欠点が以下。

  • 非効率なリソースの使い方:1つのサービスだけがその仮想マシンをつかうので、VMのリソースをフル活用しない場合もある。重くなりがちなJavaベースのサービスでは問題ないがNode.jsやGoで書かれた軽いサービスでは無駄があるかもとのこと。
  • 時間が掛かるデプロイ:VMイメージの構築にも、仮想マシンが立ち上がるのにも一般的に時間が掛かる。数分など。
  • システム管理のオーバーヘッド:OSや言語のパッチ当てなど、仮想マシンごとに必要。

aws.amazon.com

12.3 <Service as a container> パターン

<Service as a container> パターン
コンテナイメージという形でパッケージングされたサービスをデプロイする。

 ここで出ましたDocker。OS含めたマシン一式が入っている仮想マシンよりもずっとコンパクトな、コンテナ技術を使うといもの。ベースにOSがありその上にDockerなどのコンテナランタイムが載り、その上に区切られた別々のコンテナが複数、その中にサービスがひとつづつ配置……となります。
準備する際はサービスのコード一式が含まれた「サービスのコンテナイメージ」を準備。必要になったらコンテナイメージレジストリ仮想マシン上に1つあるいは複数、コンテナをデプロイしてその中でサービスが動いていく形になります。

  • Dockerfileを作る。ベースはこれ、追加でこのコマンドをいれてサービスが入ったJavaならjarファイルを含めて……というのを設定。
  • docker build コマンドでコンテナイメージ作成。
  • docker tag コマンドで名前を付けて、docker push コマンドでレジストリに登録。
  • docker run でそのコンテナが実行。周囲の依存サービスも含めて起動/停止ができる Docker Compose の方がより優れている。

利点は仮想マシンとほぼ同様。

欠点が以下。

  • コンテナイメージを管理しないといけない。さらにその下のOSやランタイムの管理もある。AWS ECSGoogle Kubernetes Engineのようなマネージドなサービスを使うと管理の手間は緩和される。
  • Docker Composeも1台のマシン内に制限される。複数マシンをリソースにするには次のKubernetesが必要。

aws.amazon.com

cloud.google.com

12.4 Kubernetes によるFTGOアプリケーションのデプロイ

 ということでリソースにするマシンが複数あっても対応できる、Dockerより上の階層で一連のマシンをリソースプールとして扱うDockerオーケストレーションフレームワークKubernetesの出番となります。主要機能が3つ。

  • リソース管理:マシンのコレクションを一台のマシンとみなして管理。
  • スケジューリング:コンテナを実行するマシンを選択してくれる。
  • サービス管理:マイクロサービスでのサービスに相当する、Serviceの概念を実現して管理してくれる。負荷分散やアップデートなどなど。

 アーキテクチャとしては1つのマスターマシンと複数のノードからなります。Kubernetesマスターにあるものが以下。

  • APIサーバー:外からサービスのデプロイなどの命令を受け付けるREST APIを提供。
  • etcd:NoSQLでクラスタのデータを格納している。
  • スケジューラー:ノードを管理していく。
  • コントローラーマネージャー:コントローラーを実行してクラスタを管理していく。

kubernetes.io

 たくさんあるであろうKubernetesノードそれぞれににあるものが以下。

  • Kubelet:ノード上で実行されるPodを管理する
  • kube-proxy:ロードバランシングやネットワーク管理
  • Pod:物を載せるところ。ここにマイクロサービスの各サービスが載る。

 Javaの世界ではWebアプリケーションを作る時のクラスをServletと言いますが、Kubelet-letの語源はどこなのかな?と思ったりしました。
Kubernetesのコンセプトとしてあるワードが以下。

  • Pod: デプロイの基本単位で1つ以上のコンテナからなる。横断的関心事を処理するサイドカーコンテナを持つこともある。生成されたりクラッシュしたり短命。
  • Deployment: Podの仕様を宣言するもの。YAMLファイルに書く。
  • Service: 呼ぶ側のクライアントに静的なIPアドレスを与えてくれるサービスディスカバリの仕組み。マイクロサービスの「サービス」とは違うk8sの中の概念。(ややこしい...)
  • ConfigMap:サービスのための外部設定を保存するところ。

kubernetes.io

 そしてサンプルのFTGOの中のレストランサービスを、k8sにデプロイする例で手順が解説されています。

  • YAML形式でDeploymentのファイルを書く。Podにこのサービスが載っていてヘルスチェックのURLはここ……等の設定。kubectl applyコマンドでこのファイルを実行して更新。
  • YAML形式でServiceのファイルを書く。DNS名に使われるサービスの名前、対応するコンテナ等の設定。こちらもkubectrl applyコマンドで実行。
  • APIゲートウェイの部分もYAML形式でServiceとして書く。
  • サービスを新しくしたい場合も、新しいコンテナイメージを作っておいてkubectl apply コマンドで新しくしてくれる。

 さらなる高等な技としてはデプロイとリリースを分離するというテクニックも紹介されています。
本番環境にデプロイしても最初は一般ユーザはそちらにルーティングされないようにしておいてしばらくテスト、徐々にルーティングの割合を増やして最後は新しいバージョンに100%ルーティング、というもの。AWS API Gatewayカナリアリリースの機能みたいなものですね。
 この分離を実現するにはサービスメッシュを使うのが簡単、そして現状サービスメッシュを実現する仕組みの中の有力候補、Istioを紹介しています。
「マイクロサービスを接続、管理し、セキュリティを保つためのオープンプラットフォーム」だそうです。

istio.io

<Sidecar>パターン
サービスインスタンスと共に実行されるサイドカープロセスまたはコンテナの中で、横断的関心事の処理を実装する。

Istioはその中で使っているEnvoyプロキシで実現。構成図も載っているのですがなかなか複雑です。本書ではバージョン0.8と記述、公式サイトでは1.8。サービスメッシュが今後成熟していくであろう中ではもっとも有望株とのことです。

12.5 <Serverless deployment> パターン

 最後は仮想マシンも用意せずにデプロイしていけるサーバーレスのパターン。AWS Lambaを紹介しています。
実は世の中にはクラウド外で、オープンソースのサーバーレスフレームワークというのもあることはあるんですね。本書ではインフラの保守管理が必要でかつサーバレスデプロイメントを選択するのは制約が増えるだけだ……とし、事実上パブリッククラウド限定で話を進めています。

<Severless deployment> パターン
パブリッククラウドが提供するサーバーレスデプロイメントのメカニズムを使ってサービスをデプロイする。

  • Lambdaは言語はJavaJavaScript(Node.js)、C#、Go、Pythonをサポート。
  • JavaではRequestHandlerインターフェースを実装して作る。入力が入力オブジェクトとコンテキスト、出力がオブジェクト。伝統のServletにちょっと似ている。呼び出し方は以下4種。
  • 1:: HTTPリクエスト:API Gateway+LambdaでRESTfulサービスが実現。
  • 2:: AWSサービスが生成したイベントの処理:S3DynamoDBKinesisなど各種サービスでオブジェクト生成や更新をイベントとして実行できる。
  • 3:: スケジューリングによる呼び出し:cronのような毎日定時起動などができる。
  • 4:: Webサービスリクエストを使ったラムダ関数呼び出し:アプリケーションからLambda関数の名前と入力イベントデータを指定して呼び出せる。同期も非同期も可能。

Lambda関数の利点は以下を挙げています。

  • たくさんのAWSサービスとの連携:いろんなサービスのイベント発生時に連携できる。
  • 保守管理作業の多くがなくなる:OSやランタイムのパッチ当てが不要。
  • 弾力性:フルマネージドなので必要な性能を予測したり準備したりがなくなる。
  • 使用量に基づく課金:サーバーが起動している時間分のお金でなく、リクエストが飛んできて処理しているだけのリソースだけ課金。

欠点は以下を挙げています。

  • レイテンシのロングテール化:起動まで時間がかるので一部のリクエストではレイテンシ―が大きくなる。Javaベースのサービスでは数秒掛かる。
  • イベント/リクエストベースのプログラミングモデルに制限される:長時間動き続けるバッチ、メッセージを消費し続けるサービスなどには向かない。

ロングテール」の表現はニッチな商品も広く揃えて儲ける話のとき専用かと思っていたのですが、ネットワークの話題でも使うんですね。

aws.amazon.com

12.6 AWS Lambda と AWS API Gatewayを使ったRestfulサービスのデプロイ

FTGOサービスをLambdaに載せていく例が解説されています。リクエストが来たらAPI Gatewayが受けて複数のLambda関数に分割、中でRequestHandlerを受けてサービスのJavaコードが動く……と、構成図もかなりシンプルになっています。

  • FindRestaurantRequestHandler:レストラン検索のLambda版。handHttpRequest(request, context) メソッドが処理開始だが、中でメンバ変数で持っているResutaurantServiceのクラスを呼んで、後はサーバーレス版でない今までの実装と同じ。
  • AbstractAutowiringHttpRequestHandler:その親クラス。Spring Bootの固有機能分を実装。
  • AbstractHttpHandler:さらにその親クラス。handleRequest()メソッドで共通の例外処理。さらにこの親がLambdaの仕組みで定義されているインターフェース。

 Lambda関数のサンプルコードというと、処理の開始となるhandHttpRequest関数の中で完結するちょっとした処理をやって終わり、というパターンが多いような気がするのですが、Spring Bootを使いながらJavaで書いている本書のサンプルは貴重かもしれません。

 様々な技術や解法を紹介している本書ですが、本章のデプロイのパターンでは完全に
サーバーレス>コンテナ>仮想マシン>言語固有パッケージ
の順で評価するのがいいよ、としています。サービスがたくさんある本格的なマイクロサービスでは、結局もうパブリッククラウド前提なのかなあと思いました。

aws.amazon.com

Chapter 13 マイクロサービスのリファクタリング

 完全新規で作ったマイクロサービスのリファクタリングではなくて、モノリシックな既存サービスをどうマイクロサービスに移行していくかを深掘りしている最後の章。
 サンプルのFTGOサービスでは完全な新機能の「遅延オーダーサービス」を開発、また既存機能の中にある「配達サービス」をマイクロサービス側に移してみよう、というストーリーになっています。

13.1 マイクロサービスへのリファクタリングの概要

 膨れ上がったモノリスでは追加開発の生産性も下がってテストもしにくく、バグもあるかもしれないしスケーラビリティもない。ビジネス部門からの支持を何とか取り付けてメアリさんはマイクロサービスへの移行を決断していかねば……という流れ。

  • 古臭いアプリケーションを新しいアーキテクチャとテクノロジスタックを持つものに変換していくのを「モダナイゼーション」(Modernization)と呼ぶ。
  • ビッグバンリライト:古いコードは捨ててゼロからマイクロサービスで作り直す。とてもリスキー。かのマーチン・ファウラー氏によると「ビッグバンリライトが生み出すのはビッグバンだけ」
  • それよりもモノリスの中の既存サービスを、段階的にひとつひとつ徐々にマイクロサービス側に移行していく「ストラングラーアプリケーション」がよい。こちらも難しいがリスクはずっと小さい。移行が進むごとにモノリス側はだんだん小さくなり、やがて消える。

<Strangler application>パターン
古いアプリケーションを包囲するように新しい(ストラングラーの)アプリケーションを段階的に開発し、アプリケーションをモダナイズしていく。熱帯雨林の絞め殺しの木が名前の由来。

bliki-ja.github.io qiita.com

 物騒なネーミングですが、なるほどという感じです。サービスを表す四角や丸がたくさんあって、ひとつづつ徐々にMS側に切り替わっていって残った頑固なモノリス機能はいつの間にか四面楚歌の孤立無援に……という絵で考えると、「包囲する」という表現も一応分かるような気がします。

  • 素早く頻度の高い価値の訴求:段階的に移行するとマイクロサービス側の新サービスをすぐ見せられるので、投資効果を見せてビジネス部門側からも支持を受けやすい。
  • モノリスへの変更は小規模に:大きな変更は時間が掛かるので小さく小さく変えていく。リファクタリングやレガシーコードの改善と同じ。
  • デプロイのインフラストラクチャの仕組みは最初からフルセットにする必要はない:デプロイや可観測性などなど、最初のうちは高度は仕組みは不要。経験を積んでから大きな出費の判断をした方がよい。
13.2 モノリスをマイクロサービスに移行させるための方法

 3つの方法が紹介されています。

1:: 新機能をサービスとして実装する

これ以上モノリスは成長させず、マイクロサービスとして素早く開発して価値を見せる方法。

  • クライアントからのリクエストの受け手のAPIゲートウェイでは、その新機能へのアクセスは新サービス側へ、旧機能へのアクセスはモノリス側へと振り分ける。
  • 新機能から旧機能、あるいはその逆にお互いのデータにアクセスが必要になることもある。その場合はお互いに通信できる線を用意しておき、この部分を「インテグレーショングルー」と呼ぶ。
  • 小さな機能追加だったりDBの構成上切り離すのが難しかったり、モノリス側の旧機能に実装した方が良い場合もある。

グルーは接着剤のGluePythonがグルー言語(glue language)と呼ばれるように2つをくっつけるからですね。

2:: プレゼンテーションティアとバックエンドを切り離す

  • モノリスなアプリケーションは プレゼンテーション->ビジネスロジック->データアクセスの3階層のティア(tier, 層)に分離できる。
  • このうちプレゼンテーションモノリス側のまま。しかしそこでデータ取得部分はRESTクライアントとして、呼び出し先を変える。
  • REST API->ビジネスロジック->データアクセス のバックエンド分を別のモノリスとして切り離す。これで将来はプレゼンテーション層から繋ぐ先をマイクロサービス側に繋ぎ変えたりできる。

3:: モノリスのビジネス機能を抽出してサービスに置き換える

2::の例のバックエンド分のモノリスをマイクロサービス側に置き換えるやり方。
リクエストを受ける場所->ドメインロジック->他との通信->DBのスキーマ と、ビジネス単位で縦に切ってその分をマイクロサービスに移動するので、モノリス「縦にスライス」という表現がなされています。

  • ドメインモデルの分割:ドメイン駆動設計のアグリゲートの考え方を使うと良い。今まではクラス同士が参照していたのを、主キーでの参照に変える。
  • DBのリファクタリング既存テーブルも分割して、新サービス側に抽出して移動させる。
  • データのレプリケート:モノリス側の既存テーブルの変更箇所は、しばらくそのままにしておいて読み取り専用でアクセス可能にしておいて、コード側で見る先を新サービス側に変えておくと良い。
  • どのサービスを抽出していくか:期間を区切って定義していくやり方もある。どのサービスを対象とするかランクをつけて計画的に移行していくやり方もある。

bliki-ja.github.io

13.3 サービスとモノリスの連携方法の設計

 新サービスと旧モノリスを繋ぐ「インテグレーショングルー」をどう設計していくかの節。

  • REST APIでもメッセージングでもよい。サービスのビジネスロジックのクラスはどんな方法なのか知らなくて済むよう、インターフェイスを定義すると良い。
  • REST APIなら旧モノリスにリクエストが飛ぶと、DBを検索して返す……という普通のやり方である。シンプルになる。
  • モノリスのDBが新しくなるとイベントが飛んできて、新サービス側で持っているレプリカのDBも新しくなっていく……というCQRSを使うやり方もある。

 旧モノリス側のビジネスロジックは設計が古かったりしてそのままデータを新サービス側に持ってきてはまずい場合は、DDDでの「腐敗防止層」(ACL)をパターンとして紹介しています。

<Anti-corruption layer>パターン
片方のモデルのコンセプトでもう片方のモデルが汚染されるのを防ぐため、ドメインモデルの変換を行うソフトウェア階層を設ける。

新サービス側のインテグレーショングルーの終点からサービス本体に繋がるところにこの腐敗防止層を用意して、適切に変換するというもの。
権限の話で出てくるアクセスコントロールリスト(Access Control List)も略すとACLなので文脈によって注意が必要ですね。

またサービスがたくさんあるマイクロサービスとモノリスが混在した状況で、認証と認可の処理では以下のような手法を紹介しています。

  • 従来通りログイン画面からログイン→APIゲートウェイモノリス側のログインの仕組みへ。
  • ここでセッションクッキーの他に、ユーザ情報を格納したUSERINFOクッキーも追加で返すようにする。
  • APIゲートウェイは追加のUSERINFOもクライアントに返す。
  • クライアントはUSERINFOクッキーも含んだ状態で新サービスにリクエストを送る。
  • APIゲートウェイはこのUSERINFOクッキーをチェックして、サービスに送る時のAuthorizationヘッダーに組み込んでクエストを送る。

ユーザーは意識することなくAPIゲートウェイがよろしくやってくれるということですね。

 なかなか高度な話が続くのですが、絵を見ながら読むと何となくイメージは湧く感じです。このあたりの古いシステムの刷新の話題は、読んだ本ですと『Enginneers in VOYAGE』で実際の現場での似たような話がいろいろと語られています。

iwasiman.hatenablog.com

13.4 新機能をサービスとして実装する:配達ミスの処理

 配達ミスを処理する「遅延オーダーサービス」(DelayedDeliverryService)という新機能を、マイクロサービス側に追加しようというストーリーで実例を語っていく節。

  • リクエストが来たら受け口のAPI Gatewayで分岐、GetDelayOrder()が来たらこちらの新サービスに。
  • 新サービスが顧客連絡先情報を必要だったら、インテグレーショングルーとして旧モノリス側にgetCustmerContactInfo()のRESTの口を用意してここから取得。データ量が少なければこれで簡単。
  • モノリス側でOrderRestaurantドメインに変更が生じたら、ドメインイベントとして新サービス側にパブリッシュ-サブスクライブで通知、レプリカのDBを更新していく。
13.5 モノリスの分解:配達管理の抽出

 巨大なモノリスの中から配達機能の部分をうまく取り出して、「配達サービス」に独立させていくというストーリーの節。

  • 新サービスにどの操作とどのデータを移すか、モノリス側にどのAPIを提供するか、モノリス側はどのAPIを用意するか、が設計として必要。
  • まず旧モノリスのコードを洗い出し、関係するエンティティとフィールドを明らかにする。
  • 新サービス->モノリスに残ったデータモノリス->サービス側に移動したデータ へのアクセスを考えながら、どのデータを新サービス側に移すかを決める。
  • ドメインロジックのコードは主にモノリスからの切り貼りになる。こうした局面ではコンパイルエラーで分かる静的言語だと楽になる。
  • 2つを繋ぐインテグレーショングルーの設計。例えば旧モノリス側のOrderの変更を新サービスに伝えるとする。
    Order側のライフサイクルなど、詳細な知識を配達サービスが知っていなければいけないAPIよりは、詳細を知らなくてよいAPIの方がよい。Orderの変更で配達が設定された、新しくなった、キャンセルされた、など別のイベントを発行するなど。→ソフトウェア設計の原則、関心の分離。
  • インテグレーショングルーで移動するデータが膨大なときは、REST経由のクエリではなくレプリカのDBがよい。

モノリス側の書き換えについては以下のようになっています。

  • まず必要な機能を全部メソッドに洗い出したインターフェース DeliveryService を定義。モノリス側の配達機能は、このインターフェイスを実装した DeliveryServiceImpl クラスのようになる。
  • コードの中で配達機能を使っているところは、実装クラスのメソッド呼び出し→このインターフェースのメソッド呼び出し に全部変更。ここでも、静的型付け言語だと楽である。
  • 新サービス側を呼び出す DeliveryServiceProxy クラスを新規実装。
  • DeliveryServiceImpl -> DeliveryServiceProxy に一斉変更と見せかけて……その前にDeliveryServiceを実装した「フィーチャートグル」(Feature Toggle)のクラスを定義。
    このクラスが旧実装クラスと新Proxyクラスの呼び出しを切り替えられるようにする。新Proxyクラスを介してサービスに振り向けるようにしてテスト、問題が生じたら旧実装クラスに切り替え。最後は新Proxyクラスしか呼ばないようにして、旧実装クラスは埋葬。

この「フィーチャートグル」はマイクロサービスに限定しないテクニックですが面白いですね。
実際にモノリスから抽出していくのは大変でしょうが、こうやって徐々に引き抜いていくとモノリス側がだんだん小さくなり、マイクロサービス側の小さなサービスがだんだん増えていく。メンテナンス性やテストしやすさも上がり、開発速度も上がってサービス全体も成長してみんなハッピーになると。

qiita.com

 またモノリスからのコードを抜きとって移行する話ではC#Javaのような静的型付け言語の方がコンパイルエラーで検知できるので便利だ…という話が複数回出てきて、確かにこういう局面だとそうだろうなあと思いました。

f:id:iwasiman:20210123161130p:plain
マイクロサービスパターン

まとめ:マイクロサービスの実際の作り方が分かる本

本書の感想:
 高度な問題領域を扱ったなかなか難しい本です。うっかりすると分からなくなりそうなので読書記録を細かめに記録しながらじっくり読んだのですが、マイクロサービスに関わるキーワードを一通りさらうことができてMS完全に理解した…! という気分になりました。(※ちゃんと作れるとは言っていないw)
数年前にオライリー本の『マイクロサービスアーキテクチャ』を最初に読んだ時は「概念は分かったけどこんなのほんとに実現できるの?」という気持ちだったのですが、だいぶ解像度が上がった感じです。
文中で登場する関連キーワードやプログラミング・設計の原理、設計テクニック、OSSのテクノロジ、フレームワークなども多岐に渡り、最近のモダンな開発テクノロジーの総覧的に読むこともできます。

 もっとも重要なのはサービスの分割であるとのことで、設計のところではドメイン駆動設計も出てきます。通常のHTTP通信以外にメッセージングも出てくればAPIゲートウェイなどクラウドデザインパターンも関わり、RDBとNoSQL、クラウドの原理やAWSのサービスもよく登場、セキュリティの重要性はいつもどおり、テストについてはTDDも関わり、デプロイになるとCI/CDにVMにコンテナにサーバーレス、SRE領域のキーワード、リファクタリングのテクニックも関連…と、様々な技術や考え方と繋がりがあります。
おお、あれがここで出てくるのか…!という、真理の湖を目指す旅の途中で知識の点と点が線でつながるような気持ちを何度も味わいました。なんというか、モダンな開発に関わる事柄が全部乗せな感じなんですよね。だからこそマイクロサービスはいま注目されてもいるし、バズワード的に取り上げられることも多いのだろうなあと思いました。

 難点は...というと500ページを超えるこのボリュームが大きな障壁でしょう(笑) 経験の浅い方だと挫折してしまいそうですし部分的に読む手もあるかと思います。
ゲートウェイ」と「Gateway」とか、ところどころ英語で書くべきところ/日本語で書くべきところが混在とか、英単語が不自然なカタカナに訳されているところもたまにあります。このへんは長い本なのでしょうがないのかなと。また電子版だとリフロー形式でないので、2ページ表示でも1ページ表示でも上下左右の空白が大きくてちょっと見にくいですね。

出てくるコードの話:
サンプルストーリーで出てくるFTGOサービスのコードもGitHubに上がっています。

github.com

 FTGOサービスは全部Java実装でSpringフレームワークを使っているという設定なので、サンプルコードもオールJavaです。Spring固有の書き方も出てきて知らない方は戸惑うかもしれませんが、本書を読むぐらいの方はきっと複数言語を操っていて雰囲気でだいたい分かるはず…!(想像w)
 本書の日本語版の副題には「実践的システムデザインのためのコード解説」とありますが、コードをコピペしてそのまま使うような本ではなくてより抽象度の高い領域、コード自体の前段にある考え方を知るのがメインなので、コード自体はそんなに理解できなくても大丈夫かなと思います。
また最初は依存性の注入から始まって2000年代に一世を風靡したSpringフレームワークはその配下に様々なモジュールでいろんな仕組みを持っているのですが、クラウド関連やマイクロサービス関連の仕組みもけっこう持っているのだなと思いました。

 マイクロサービス最大の難問(だと思う)DBのトランザクションが分断されてしまう話では、4章を中心に<Saga>パターンという考え方を展開して作者さんらによるEventuate Tramフレームワークがあちこちに登場し、Saga全推しの展開になっています。なのですがこのEventuate Tram、日本で採用事例を見たことがないし実際はどうなのだろう?と思いました。
そもそもマイクロサービスの利点のひとつがサービスごとに様々な技術を使えることですし、このフレームワークを導入するとなるとサービスは全部オールJavaという縛りがたぶん入ります。2020年代に果たしてその選択をするかな?という問題もあります。

 またオンプレ/クラウドの区別なく概ね中立に様々なテクノロジーを紹介している本書ですが、12章のデプロイメントの話になると完全にサーバーレス/コンテナ技術/仮想マシンへのデプロイを推奨しています。結局の所、本格的にマイクロサービスをやるならパブリッククラウド必須なのかなあと思いました。

対象読者の話:
 前書きの所で、エンタープライズアプリケーションのアーキテクチャや設計の基本的なことが分かってさえいればよい、3層アーキテクチャやWebアプリの設計、RDB、RESTなどの通信、セキュリティの基礎は必要です…と書いてあり、そのとおりです。
開発に関わる事柄が一通り出てくるので、ITエンジニアとしてひとつのアプリケーションの開発に一通り携わったことが複数回ぐらいはある方、中級者以上でしょうか。インフラ系の方が読むのも面白いと思います。ふだんからアーキテクチャ検討や設計に携わっている方にも参考になるでしょうし、設計の手札を増やしてスキルを高めたい方がチャレンジするにも学びになると思います。

マイクロサービス自体の話:
 ワタクシは本格的に作ったこともまだないし近年バズワード気味なこともあり、それなりに経験ある現場のエンジニアとしては若干懐疑的な気持ちもあるままでいます。本書を読んだ後も、面白そうだけど技術的難易度高そう〜!という感触は変わらずでした。
 これ下手に手を出して設計でしくじったら大変なだけになって大きな負債になるし、赤字になっちゃいそうですね。そもそも設計のできる優秀なエンジニアを複数人集める必要があるし、サービスごとに個別に開発チームが組めるだけの組織も必要になります。先進的な企業での導入事例はあれこれ見聞きしますが、キラキラ感だけでなく現実を見つつやっていかんとなあと思います。
 下のリンク集のラクスさんのブログ記事にあるのですが、原理主義的にも見えるマイクロサービスほど厳しい分割にこだわらず、もう少しマイルドなアーキテクチャパターンというのも提唱されています。このへんも含めて今後の動静を見ていきたいところです。

おまけ:リンク集

 さすがに高度な領域を扱っている本だからでしょうか、感想も少なめです。ざきさんのブログで見つけました。

内容のまとめやツイートをまとめている方もいます。

翻訳される前、原著の『Microservices Patterns』を読んだ方々の記事。よくまとまっていて当時反響も大きかったです。

関連してラクスさんのエンジニアブログの、アーキテクチャまとめ記事。これは参考になります。マイクロサービスは大変すぎだということでそこまで分割しすぎない「ミニサービスアーキテクチャ」「モジュラーモノリス」という新しい考え方も整理されています。
この記事によるとマイクロサービスアーキテクチャ「機能(Feature)ごとに分割」でこれは極端なので、もう少し優しいミニサービスでは「サービスドメイン(Service Domain)ごとに分割」となっています。なのですが本書『マイクロサービスパターン』では業務による分割かサブドメインによる分割で、実質ドメインごとに分割なのでは?と読み取れます。このへんもう少し深堀りしていきたいところです。

tech-blog.rakus.co.jp

『レガシーコードからの脱却』の翻訳者であるRyuzeeさんのブログでも、2015年時点のマイクロサービスまとめがあります。

www.ryuzee.com

マイクロサービスアーキテクチャ

マイクロサービスアーキテクチャ

  • 作者:Sam Newman
  • 発売日: 2016/02/26
  • メディア: 単行本(ソフトカバー)

本書『マイクロサービスパターン』の前、2016年に一番最初に和訳されたオライリー本『マイクロサービスアーキテクチャ』の感想。

モノリスからマイクロサービスへ ―モノリスを進化させる実践移行ガイド

モノリスからマイクロサービスへ ―モノリスを進化させる実践移行ガイド

  • 作者:Sam Newman
  • 発売日: 2020/12/26
  • メディア: 単行本(ソフトカバー)

www.oreilly.co.jp

2020年12月の最新のオライリー本『モノリスからマイクロサービスへ』。こちらも書評がぽつぽつ出てきました。

うーんこの本もだんだん気になってきましたぞ。
ということで3回シリーズの超長い読書記録、お立ち寄りいただきありがとうございました〜。