2020年6月5日金曜日

マイクロサービスパターン[実践的システムデザインのためのコード解説]

良い本でした。
マイクロサービスというタイトルだけどアーキテクチャーについて網羅的に記述ている。

Chap1
SOAとの違いは、データベースがサービスごとにありグローバルに参照するわけではないこと。
単純なアプリならモノリシックな方が良いことのほうが多い。


Chap2
command=データの更新系
query=データの読み出し
業務(ドメイン)に従ってサービスを分けていく


Chap3
Service間で通信は必須

同期・非同期がある。
同期ではOpenApi、gRPCが主に使われる。
Circuit breaker(失敗が続いたら受付を止める処理)は必須。
マイクロサービスのフレームワークにあったりするので探すのが良い。
サービスディスカバリーもEurekaなどライブラリーがある。
Dockerやk8sはサービスディレクトリを提供する。可能な限りこれを使うほうがメンテナンスがしやすい。

非同期ではmessage brokerがメッセージを仲介する
非同期では、リクエスト/レスポンスのスタイルと一方通行の2種類のスタイルを分けてドキュメントを作る必要がある。
Kafka/JMS/RabbitMQなどがある。
MQはat least onceなので、重複するメッセージが来る。
冪等性の確保は必須。データベースにmessage idを保存するなどして対処する
メッセージの送信の信頼性の確保にはoutboxデータベースを送信元で作成して、それをpolingするかdbのtransaction logをtailingする。
著者はEventuate tramというフレームワークで高レベルapiを用意している。

非同期にすることで可用性は上がる。


Chap4
サーガとは複数のサービスで一つの目的を達成するための単位。
コレオグラフィとオーケストレーションの2択がある。
コレオグラフィは、各ServiceがP2Pで連携するイメージ。
オーケストレーションは、O家すとれーたクラスで一括管理すつ方法。
オーケストレーションの方が、一箇所にまとまりやすいのでおすすめ。

オーケストレーションでステートマシンで管理するのがよい。
ロールバックなどの命令もここでやる。
サーガには3ステップある。
補償可能トランザクション:補償トランザクションでもとに戻すことが可能。
ピボットトランザクション:このトランザクションが成功したらあとは成功するのみの分岐点。
再試行可能トランザクション:ピボットトランザクションのあとで確実に成功するトランザクション
カウンターメジャーで、処理の順番の不整合に対処する。イベントが期待通りの順番に飛んでこないこともあるので、その場合に対処する道具がカウンターメジャー.。
pendingなどの状態で管理するsemantic lock
処理の順番が入れ替え可能にするcommunicative update
処理の不整合が発生しそうなupdateを最後に持ってくるpessimistic view
処理の最初にreadして、もう一度更新前にreadした値が更新されていないかcheckするreread value

OderServiceがOderSagaStateを作成するような形で、Sagaを作るのもまたService

Chap5
外部イベントを受け取るHandler
外部にイベントを出すPublisher adapter
データベースとやり取りするDatabase adapeter


Aggregateはそのroot同士だけでやり取りする。
主キーでお互いに参照するoderが参照するconsumerはconsumer idとなる
1つのトランザクションに対応するのは1つのaggregate


Chap6
イベントソーシング
アグリゲートを永続化するときにそのデータを保存するのではなく、イベントをすべて保存することで、あとからそのイベントをすべて処理することで、前回の状況を再構築する。
アグリゲートはprocessとapplyに分かれる。
processでイベントを複数作成し、そのをapplyでアグリゲートに適用。
イベントを保存する。
イベントを途中から再開するときは、イベントのセットを読み出してapplyを繰り返し呼び出しアグリゲートを復元。processを呼び出して新しいイベントを作って、また同じことの繰り返す。
イベントを複数処理し終わったアグリゲートを保存したスナップショットを作ることでパフォーマンスは上がる。
冪等性担保には、processed_idをtableにwriteすることで対応。
イベントソーシングでのイベントの更新には、アップキャストと言う方法を用いる。
データベースからイベントをloadするときにインスタンスを新バージョンに変えるのだ。

Chap7
CQRS
コマンドとクエリーの分離を意味する。
クエリー用のDBを作成することで、複数回のネットワークアクセスをしないようにするなどの工夫ができる。
レプリケーション遅延の問題なども起こるが、UI上の問題であればClientのDBを予め更新しておき、あとからServerと同期する形にしても良い。


Chap8
GatewayはそれぞれのFrontend向けにできるだけ分けたほうが良い。
gatewayは
認証、認可、流量制御、cahcing、メトリクスの収集、リクエストのロギングなどの役割がある。

API Gatewayも製品がある。LongやTraefikなどZuul、Spring Cloud gatewayもある。

GraphQLはスキーマ、リゾルバ、Proxyに分かれる。スキーマはI/F、リゾルバはServiceとのmapping、Proxyは実際のServiceの呼び出し。
GraphQLを使うメリットは、クライアントがqueryを打てるようになるイメージに近い。
様々なデータを様々な組み合わせでよく取得するような場合に、最も効果を発揮する。


Chap9
Serviceごとの契約(I/F)の検証としてSpring Cloud Contractなどがある。
Pactフレームワークの一種


Chap11
サービスはそれぞれ、観測可能であるべき。
Health check api
Log aggregation:複数のログをまとめ上げて、開発者が見られる形にする。log4Jとか。Elasticsearchとか、LogstashとかKibanaとか。
Distributed tracking:リクエストに紐づくIDを与えて各サービスでも追いかけられるようにする。分散トレーシング、Zipkinとか
Exception tracking:例外をcacheして開発者にアラートを送る。HoneyBadgerとかServlet Filterとか
Application metrics:カウンターやゲージなど
Audit loggging:ユーザーの行動を計測する。Spring AOPとか。

Microservice chassis(マイクロサービスシャシー)、必要なものが一通り揃ったやる。
Spring Cloud、Spring Bootとか。


Chap12
デプロイは、まあDockerだろうな。
Istioが最もポピュラーなサービスメッシュ
k8sつかって、Envoyをサイドカーとしてデプロイする。
いろいろ変わりそうなところではある。

Chap13
モノリスのリファクタリングについて。
まずは、モノリスのGatewayに相当する部分を抜き出してみる。
新規機能追加のときにServiceとして作ってみる。
必要なデータは、レプリケーションなどしてコピーしたりもする。
マイクロサービス化していったときに、モノリスをロールバックするのは不可能と言って良い。
なので、モノリスは最後の最後に、処理が終わったら必ず成功まで行くという後半に持ってこないといけない。








https://www.amazon.co.jp/dp/B086JJNDKS/ref=cm_sw_r_tw_dp_U_x_e8q0Eb9X2E665