「マイクロサービスアーキテクチャ」を読む

Tech

この本に期待すること

  • 仕事で使用しているモノリシクなプロダクトの可用性を上げ、コンフリクトを避けるようにしたい。
  • 10 人以上で開発しているとコンフリクトで作業が進まないのが主な悩み。
  • 気になるのは、DB を共有しないとテーブル間のキー制約をかけたままサービス分離することができない点。
  • フロントのコードの分離は iframe で呼び出す? https://zenn.dev/neko3cs/articles/introduction-to-micro-frontends

要約

1 章 マイクロサービス p.1 – p.13

  • マイクロサービスは、協調して動作する小規模で自律的なサービス
    • 小規模 … 「2 週間で書き直せるもの」

メリットとして、

  • 高凝縮で変更しやすい
  • サービスごとに異なる技術を使うことができる
  • 局所的なスケーリングが可能
  • 他のシステムがダウンしても動作する回復性

マイクロサービス以外の分解テクニック

共有ライブラリ

言語が固定されるため、技術的多様性が失われる
全体に影響するデプロイ
組織内 で再利用したい一般的なタスクのための解決法

モジュール

OSGI(Open Source Gateway Initiative)は、モジュール式分解に対する技術固有の手法の 1 つ
Erlang も良い例 モジュールはすぐに残りのコードと密結合になる

2 章 進化的アーキテクト p.15 – p.32

ソフトウェアは生き物のようなもので、ユーザーの利用による変化を許容できる
アーキテクトは方向性を大まかに設定する必要があり、限られた場合にのみ実装の詳細について具体的に関わる。

アーキテクトは、サービス境界内で起こることではなく、サービス間で起こることに注意を払う(p.19 まで)

設計におけるフレーミング

アーキテクトがシステム設計のトレードオフから判断を下す際、材料となるのは下記の三つ

  • 戦略的目標
    • ビジネスを推進するビジョンとは何でしょうか。また、そのビジョンはどのように変化するでしょうか
  • 原則
    • 原則とは、実行することを大きな目標に一致させるために作成した規則であり、ときどき変更されるもの
    • 例: Heroku 12 Factors
  • プラクティス
    • プラクティスは、原則を確実に実行する方法。タスクを実行するための詳細で実用的な一連の指針
      • コーディング指針,
      • すべてのログデータを集中して保存すること
      • HTTP/REST が標準的な統合形式であること

原則やプラクティスについては、調べて実行でき、アイデアを具体化するサンプルコードを持つという考えが好まれる

–> 会社の「おすすめの開発方針」がこれにあたるかも。読み直す。

大規模なモノリシックシステムでは、開発者たちが向上 して何かを所有する機会はほとんどありません。一方、マイクロサービスではそれぞ れ独立したライフサイクルを持つ複数の自律的なコードベースがあります。多くの責 任を引き受ける前に個々のサービスを所有させることで開発者たちを向上させること は、各自のキャリア目標を実現させるための優れた方法であり、同時に責任者の負荷 を軽減します。

オーナーシップによるモチベーション向上効果は実感としてある。

監視

サービスをまたがったわかりやすいシステム健全性のビューを作成できることが、不可欠

ガバナンス

ガバナンスは、利害関係者のニーズ、状況、選択肢を評価し、優先順位付けと意思決定を通じて方 向性を設定し、合意した方向性や目的に対する実績、順守、進捗の監視を行うことで企業の目的が達成されるようにすることです。 – COBIT

3 章 サービスのモデル化方法 p.33 – 43

マイクロサービスの本質は、システムの他の部分を変更する必要 なしに、あるサービスを変更してデプロイできること

疎結合と高凝縮がキーワード

疎結合 = 他のサービスと最低限な通信を行い、デプロイしても他のサービスを変更しなくて良い
高凝縮 = 変更が一箇所で済むようになる

境界づけられたコンテキスト – 『Domain-Driven Design』

  • 明示的な境界によって強制される特定の責務
  • モデルを使用して明示的な境界と通信する
  • 細胞膜 = モデル。細胞 = 境界づけられたコンテキスト

経理部門と倉庫を 2 つの別個の境界づけられたコンテキストとみなせる
これらの境界づけられたコンテキストはどちらも(在庫報告書、給与明細書といった観点で)外部との明示的なインタフェースを持ち、知っておく必要がある詳細(フォークリフト車、計算機)しか知らない image

上記の場合だと、倉庫のコンテキストから在庫品目に関するすべてをやみくもに公開する必要はない。
同じ「在庫品目」という言葉でも、倉庫のコンテクストと経理のコンテクストでは取得したい情報や、とりうる活動が異なる。コンテクストの内部のみに関わる表現を共有しないことで、密結合を防げる。

新規システムはモニリシックに作って、後で分割したほうが良い

4 章 統合 p.45 – p.92

ポステルの法則 - 送信するものに関しては厳密に、受信するものに関しては寛大に

DB 統合

異なるサービスが同じ DB を参照している状態で、最も避けるべき。

オーケストレーション

中枢の指揮者がその他をコントロールする ビジネスプロセスモデリングソフトウェアというツールがある 欠点は、顧客サービスが中央監督機関になりすぎること

コレオグラフィ

image ダンサーが隣のダンサーの動きに合わせるように、他のサービスの動きに合わせてコントロールする 欠点は、明示的なビジネスプロセスが、システムには暗黙的にしか反映されなくなること コレオグラフィ手法に向かう傾向が強いシステムの方が、疎結合で柔軟性があり、変更を受け入れやすい

UI との統合

API 合成

2 つの欠点
1

さまざまな種類のデバイスごとにレス ポンスを調整することがほとんどできません 例えば、顧客記録を取得するときには、移動店舗ではヘルプデスクアプリケーションの場合と同様にすべてのデータを取得する必要があるでしょうか。顧客がリクエストを行うときに取得したいフィールドを指定できるようにするという解決策も 1 つありますが、これはそれぞれのサービスがこ のような対話の形式をサポートしていることを前提としています

2

誰がユーザインタフェースを作成するのでしょうか。 サービスの担当者たちは、サービスのユーザへの見せ方には関わりません。例えば、 別のチームが UI を作成している場合、小さな変更でも複数のチームに変更リクエストを行わなければならなかった、昔のひどい階層化アーキテクチャの時代に逆戻りしかねません

UI 部品合成

サービスに UI の部品を直接提供させ、その部品を集めて UI を作成する方法

この手法には、サービスを変更するのと同じチームが UI 部品の変更も担当できるという利点があります。これにより、変更を迅速に公開できますが、この手法には問題もあります

ユーザエクスペリエンスの一貫性を保証しなければなりません。この問題を回避するリビングスタイルガイドのようなテクニックがあります。リビングスタイルガイドでは、HTML コンポーネント、CSS、画像といった資産を共有してある程度の一貫性を提供できます

また、ネイティブアプリケーションやシック(thick) クライアントでは、UI コンポーネントを提供できません

BFF

バックエンドサービスとの呼び出しが多いインタフェースやデバイスの種類ごとに コンテンツを変えなければならない問題に対しては、サーバ側集約エンドポイント (API ゲートウェイ)を用意して解決を図ります

API は、ゲートウェイがモノりシックになる欠点があるため、BFF と呼ばれるバックエンドの使用を特定のユーザインタフェースやアプリケーションに制限する方法がある

BFF の危険性は、他の集約レイヤの場合と同じ。入り込むべきではないロジックが入り込む恐れがある。バックエンドが使うさまざまな機能のビジネスロジックは、サービス自体の中に留まるべき

image

5 章 モノリス(一枚岩)の分割 p.94 – p.120

  1. コードベースを接合部に合わせて整理する
    漸進的な手法は進めながらマイクロサービスについて学ぶ手助けとなり、間違いの影響も制限される 初期フェーズなど、ドメインに対する理解が安定するまでモノリシクで良い

  2. データベースアクセスコードにも同じことを実行する

    一般的なプラクティスは、ORM を使ってリポジトリレイヤを用意してコードをデータベースとバインドし、 オブジェクトやデータ構造のデータベースに対するマッピングを容易にすることです。
    データベースレベルの外部キー制約を確認するには、別のツールでデータを可視化する必要があります。手始めとしては自由に利用できる SchemaSpy(http://schemaspy.sourceforge.net)といったツールを使うとよいでしょう。

  3. 整合性・一貫性の担保

    サービスにまたがって独自の一貫性検査を実装 するか、関連データを整理する措置を講じなければなりません。多くの場合、これが 必要かどうかは技術者が判断することではありません。例えば、注文サービスにカタ ログ品目の ID のリストが含まれている場合、カタログ品目を削除し、注文が無効な カタログ ID を参照するようになると何が起こるでしょうか。これを許すべきでしょ うか。許すなら、注文を表示する際にどのように表示するのでしょうか。許さないな ら、違反していないかをどのように調べるのでしょうか。ユーザに対するシステムの 振る舞いを決める人に、このような質問に答えてもらわなければなりません。

経理コードが 品目テーブルにアクセスするのではなく、経理コードが呼び出せるカタログパッケージの API 呼び出し経由でデータを公開します。

-> 複数の場所からデータを取得してメモリ内で結合する。 この本では、性能は下がるけど、開発速度が上がるなら ok という認識。 API では、全情報を取得できるようにするか、ID のリストで情報を取得できるようにするなどのバッチ API を提供すると良い

つまり、ハンドリングは自前で実装する必要があるということ。
また、トランザクション完全性は失われる。
代わりにキューイングとリトライで結果整合性を保証することはできる
compensating トランザクションを発行する (DELETE 文で消すなど) こともできるが、複雑になってくると困難 .
あるいは分散トランザクション。最も一般的なのは 2 相コミット

分散トランザクション
投票フェーズ 分散トランザクションの参加者がトランザクションマネージャにローカルトランザクションを進められるかどうかを通知
1 つでも「いいえ」の投票があれば、トランザクションマネージャは全参加者にロールバックを送信

前提・制約:
トランザクションマネージャがダウンしたら、保留中のトランザクションは決して完了しない
票後にコミットに失敗したらどうなるかという課題
保留中のトランザクションがリソースに対するロックを保持し、競合がスケーリングを困難にする
分散トランザクションの導入は困難なため、本当に一貫性が必要か確認すべき。

親子関係にあるマイクロサービスを、ネストして秘匿するか、独立して公開するかは、管理する組織構造に基づくべき。 組織構造とソ フトウェアアーキテクチャの相互作用 -> 10 章を読む 脆弱な RPC 呼び出し -> 4 章を読む

データポンプ .
各サービスの DB に直接アクセスするスタンドアロンなプログラムを用意する
そのプログラムから、定期的に中央のレポート DB にデータをコピーする。これをイベント駆動にすることも可能。
結合は残るので、サービスチームがデプロイをする必要があり、レポート DB の変更も難しくなる

メリット・デメリット

DB の選択肢が広がる
マイクロサービスに分割することで、グラフ型やドキュメント型、カラム型の DB を部分的に使える

実行速度は下がるが、開発速度が上がる .
xxxx

6 章 デプロイ p.121 – p.153

CI とは

CI の主な目的はすべてを互いに常に同期させることであり、実際には新たにチェックインされたコードが既存コードと適切に統合(インテグレーション)されるようにすることで、これを実現します
このプロセスの一環として、大抵はサービスをデプロイしてテストを実行すると いった、追加の検証に使う成果物を作成します

CI とは何かを本当に理解しているか 「Jez Humble」

  • 1 日に一度はメインラインにチェックインしていますか
    • 一時的なブランチをできる限り頻繁に統合すべき
  • 変更を検証するテストスイートがありますか。
  • ビルドが壊れたときに、それを修正するのがチームの最優先事項でしょうか

CD

継続的デリバリは、チェックインするたびに本番環境への準備状況に関するフィードバックを常に得られ、さらに各チェックインをすべてリリース候補として扱う手法

プラットフォーム固有の成果物

npm パッケージ, gem, jar などのプラットフォーム固有の成果物をテストするのはセットアップに手間がかかる。
自動化は、基盤となる成果物のデプロイ機構の違いを隠すのに、大いに役立ちます。
例:Chef、Puppet、Ansible
-> 仮想マシンイメージの利用の方が高速

構成ドリフト … ソース管理内のコードが稼働中のホストの構成を反映しなくなっている状態

仮想化

Vagrant .. 遅い、リソースの消費が激しい

  • Linux コンテナは高速だが、コンテナ間の通信で iptables を設定するのが複雑
  • また、あるプロセスが突然他のコンテナのプロセスと対話できたりする事象が起こりうる

Docker は、1 台のマシン上で動作するが、複数のマシン上の複数の Docker インスタンスにわたるサービスの管理をしたい場合は Kubernetes が必要になる

7 章 テスト p.155 – p.182

「単体テスト」「サービス」という言葉には複数の定義がある テストの分離性を高めることで、問題の検出と修正が早まる -> テストで多くのことをやりすぎてどこが問題かわからないあるある…

優れた経験則としては、ピラミッドを下るにつれて必要なテストの数が一桁増える E2E (1) -> サービス (10) -> 単体 (100)

E2E テストには多くの欠陥がある。 常にコケているのが当たり前になると、テストスイートへの信頼が失われる「逸脱の常態化」が起こる 信頼できないテストをできる限りすぐに探して取り除く必要がある。
-> 「SpreadSheet でのテスト管理」もその恐れを持っている気がする… -> QA チームの誰かに任せる?機能追加を全て見てもらう必要がある

コンシューマ駆動契約

-> python のサポートがあるか確認する

CDC では、サービス(プロデューサ)に対するコンシューマのエクスペクテー ション(期待)を定義します。コンシューマのエクスペクテーションはテストとして コード形式で格納し、そのテストをプロデューサに対して実行します。成功したら、 CDC をプロデューサの CI ビルドの一環として実行し、契約のいずれかに違反して いたら決してデプロイされないようにします

ブルーグリーンデプロイメントを利用したスモークテスト

本番環境でデプロイ後に動作の確認をする image

カナリアリリース

本番環境のトラフィックの一部をシステムに送り期待通りに機能するかどうかを確認すること 両バージョンが長期間共存することが予想され、トラフィック量を頻繁に変更する点が、ブルーグリーンとは異なる ブルーグリーンデプロイメントよりも複雑な準備が必要

MTBF と MTTR との間のトレードオフ

機能テストスイートの作成に時間を費やすほとんどの組織は大抵、監視や障害からの復旧の改善に全くと言っていいほど労力を割きません。そのため、最初に発生する不具合の数は減るか もしれませんが、そのすべてを取り除くことはできず、本番環境で不具合が生じた場 合に対処する準備ができているとは言えません

10 章 コンウェイの法則とシステム設計 p.223 – p.236

コンウェイの法則

システム(ここでは単なる情報システムよりも広く定義されたシステム)を設計するあらゆる組織は、必ずその組織のコミュニケーション構造に倣った構造を持つ設計を生み出す。

Amazon と Netflix の例

組織とアーキテクチャが一致すべきだと考える 2 つの申し子は、おそらく Amazon と Netflix でしょう。Amazon は、そのチームが管理するシステムのライフサイクル 全体の責任をチームが持つことの利点を、早い段階で理解していました。チームに そのチームが担当するシステムを所有、運用させ、ライフサイクル全体を管理させ ようとしました。しかし、Amazon は小規模なチームの方が大規模なチームより仕 事が速いことも知っていました。その結果、有名な「2 枚のピザチーム」(two-pizza teams)につながりました

国を横断した開発では、タイムゾーンの縛りから抜け出すためにマイクロサービス化を進めるべきかも。

イギリスとインドの両方にある 2 つのチームがサービスの 変更に積極的に関与するとしましょう。事実上、サービスを共同所有しているのです。 その場合、地理的なタイムゾーンの境界がチーム間の粒度の細かいコミュニケーションを困難にします

社内オープンソース

最善を尽くしても共有サービス以上の方法が見つからなかったらどうなるのでしょうか。そのときには、社内オープンソースモデルを適切に採用することが、大いに理にかなっています。

中核にいる人が PR のレビューを行う方式。 管理方法としては、管理者が信頼できる中核コミッタとそうでない人に分ける。

メンバーの変更への欲求を理解してください。あまり早く進めすぎてはいけません。

まとめ

今度調べる

  • ドメインモデル貧血症 https://bliki-ja.github.io/AnemicDomainModel/

  • ヘキサゴナルアーキテクチャ

  • SOA

    • ソフトウェアの再利用性の促進を目指す手法
    • 部品化されたソフトウェアを結合してシステムを構築する設計手法は従来から存在したが、どちらかというとコンピュータ寄りの視点で機能の分割や実装が検討されることが多かった。SOA ではサービスと呼ばれる構成単位でソフトウェアを開発・導入するが、例えば「請求書を発行する」といったように利用者側の視点から見た作業単位に対応するように個々のサービスの内容が決められる
  • CAP 定理

    • 下記三つの保証のうち同時に満たせるのは二つまでであり、同時に全てを満たすことはできない
    • Consistency : 誰かがデータを更新したら必ず更新後のデータを参照できること
    • Availability : クライアントは必ずデータにアクセスできること
    • Partition-tolerance : データを複数のサーバーに分散保管できること
  • Protocol Buffers

    • Protocol Buffers はインタフェース定義言語 で構造を定義する通信や永続化での利用を目的としたシリアライズフォーマット
    • スキーマ定義用のドメイン固有言語
syntax = “proto3”; package example.protobuf; message SimpleMessage { message HeaderItem { string name = 1; string value = 2; } enum Type { START = 0; BLOB = 1; END = 2; } uint64 id = 1; Type message_type = 2; repeated HeaderItem headers = 3; bytes blob = 4; }
  • CDC (Consumer-Driven Contract)

今度読む

  • レガシーコード改善ガイド
  • データベース・リファクタリング
  • 継続的デリバリー
  • 実践テスト駆動開発 テストに導かれてオブジェクト指向ソフトウェアを育てる

Tech

Posted by kyogom