RailsDM 2019でマイクロサービスについての登壇をしました

だいぶ時間が空きましたが、2019/03/22-23で行われたRails Developers Meetup 2019にて、「我々はマイクロサービスとどう向き合うべきか」という発表を行いました。

言いたいこととしてはほぼスライドどおりで、だいたい以下の内容になります。

  • マイクロサービスは麻薬
    • 適切に使えば嬉しい
    • 嬉しすぎてついつい適切以上に使ってしまう
    • 適切以上なマイクロサービスは辛い
  • マイクロサービスは問題をより難しくする
    • 例えば分割の失敗
    • 別サービスを対象にしたリファクタリングは難しい
    • モノリシックならまだリファクタリングができる
  • どれくらいが適切かは組織の能力による
    • 小規模でマイクロサービスはオーバーヘッドが多い
    • テクノロジーの進化で中規模でもマイクロサービスがやれるようになってる
    • 組織のパワーが上がるとマイクロサービスが大きくても大丈夫
  • Railsはマイクロサービスでも十分便利
    • マイクロにしすぎないレベルで抑えるのが良い
    • 中規模ぐらいならRailsの主戦場
    • マイクロサービスよりまずはビジネスの成功を
  • サービスをいかに増やさないかが大事
    • 全く増やさないとそれはそれでつらい
    • マイクロサービスの良さを取りつつ、サービスを増やしすぎない位置を狙う

スライドはこちらです

資料作成時のメモ

このプレゼンを作るうえでまとめたまとめを置いときます。 全部細かい粒度で話すと何時間あっても足りないのでかなり大きく削っています。 なお、時系列的には上の方が新しいですが、入れ替えたりしてるので厳密では無いです。

もしこのトピックについて詳しく知りたいみたいな人がいれば詳しく話すことがある…かも⊂(・8・)⊃

ランキングマイクロサービス
障害の連鎖

マイクロサービス
ライフログとAppの共依存
一気にマイクロサービスにするのは無理
  徐々に育てていくのが現実的
  すると複雑なマイクロサービスになる
モノリシックでは起きにくいところ
  サービス間通信とメソッド呼び出しは雲泥の差
  並列数を上げればサーバのボトルネックはなくなる
    実際はDBがボトルネックになるので、似た問題は起きる

↓ボツ
  マイクロサービスの未来の話
    今日のbestは明日のbetterかも
  ただし、トランザクション境界や複雑性とかは解決しないので、そっち方面での限界はありそう

  いきなりマイクロサービスをやるのはヤバイ
      特にスタートアップとか
    マイクロサービスにしないと、影響範囲が増えて成長するとやばい
      言い換えれば、成長するまでは恩恵は少ない

    成功してない段階ではRailsはとても良い
      開発が凄い早い
      おそらくPMFを最速で作れる
    うちの場合
      実は結構事業が成功してないころも投資パワーで回せたのでマイクロサービスできたのでは

    徹底的にFaaSに振ってしまうのもありかも

    とりあえず実装用のサービスを作ると良いかも
      マイクロサービスを回すチームが作れない規模
      既存のモノリシックが辛い時
      第二のモノリシック(でも多少まともなやつ)を作る
        先送りだが、マイクロサービスを意識して剥がしやすくする
        分断されたモノリスよりかはきれいなモノリスの方がまし
    プロジェクト型はむしろ作りまくるのも手かも
      優先度が育てる<作る場合
      多産多死
      ベース+それを活用するサービス達
      死んだプロジェクトが生きてる部分に影響させないように
        ほぼメンテされてないが、生きてるプロジェクトに一部がいるので足かせになってる
------------------------------

例えば横断的関心事が複雑
クオリティの統一や、セキュリティ的な面がチーム毎でバラバラになる
  5.2が出たのにRalis 4.2.1がいたりとか
  ruby 2.3.1のまま何年も放置されたりとか
  温度感もチームによって違う
    チーム毎の優先度を組み替える交渉
    チーム外からだととても手を出しにくい
      上げるのは外からでも出来るが、QAを考えるとオーナーとの交渉が必要
    チーム<サービス数なので、人のリソースが足りない
  機能追加はしなくても問題ないけどセキュリティはせざるを得ない
  試した対策
    gemの一覧を表示できるサービス作ったり
      https://github.com/ota42y/gemicoma
    マイクロサービス毎の進捗シート作ったり
    隙間時間で機能改善をやるムーブメントを作ったり
  規模が小さいので個々の問題は簡単だが、量が多いのでカバーが難しい
    モノリシックなシステムだとgemのアップデートとか大変だけど、みんなが注目するのでカバーは楽
  十分な人員がいれば問題はない
    すべてのマイクロサービスに中堅エンジニアがそこそこ関わってる…的な状態を作れれば良さそう
    たくさん作って手をかけられない部分がいくつか出るか、少なくして難易度を上げるかどっちかのトレードオフ?
    どれくらいやるかのグラデーション


サービス毎のドメインは明確になった
  事業部レベルの分割
    App/EC/BtoBで分けてる
    やっている事業が全く違い、コードベースも違う
      アカウントは共有している
    ビジネス毎に何処でやるべきかは明確に分けられた
  アプリチーム内の分割
    メディア/lifelog/コミュニティ/オンボ
    マイクロサービス毎にやるべき事が明確に別れるようになった 

コミュニケーションコストが上がる
APIの数がとても多くなる
  クライアントだけでなく他のマイクロサービスからも呼ばれる
  複数の要素をまとめて返すようなAPIは作れない場合がある
    マイクロサービスを超えるような場合
    歩数のタブのランキングとか
  問題
    APIをたくさん作る際のコスト
      仕様を決めて繋ぎこんで微妙に型が違う…みたいなの
      既存のAPIを使いたくてもドキュメントが無いと実装を読み込まないといけない
      マイクロサービスごとに音楽性が違う
      クライアントは結合しているので、マイクロサービスごとに処理を頑張る必要性がある
    複数呼び出しのコスト
      必要な情報を持ってるマイクロサービスに個別に問い合わせる必要がある
      モバイル環境だと通信回数のコストは大きい(HTTP1)
    データの整合性
  試した対策
    サービス間のAPIコールを楽に実装できるようにする
      OpenAPI
        client library生成
      gRPC(使ってない)
      APIがドキュメント通りのインタフェースを持つことを保証できる
    クライアントから見たときのマイクロサービスを楽にする
      複数呼び出しのコスト削減
        GraphQL
        BFF
    APIコールをしない
      イベントドリブンアーキテクチャ
        イベントが起きると付随する処理が行われる
        AWS SNS + SQS
        Kinesis
          ストリーミングで常に流す状態

マイクロサービス、良いところも辛いところもある
  マイクロサービス単体の開発は確実に楽になる
  アーキテクチャが複雑なのでその分のオーバヘッドはかなりある
  アーキテクチャの良さは容易に潰れる
    個々に独立して動くのがマイクロサービスの利点
    独立に動けなくなるとむしろ足かせになる
  人数が少ないと兼任が多くなる
    リソースの取り合い
    コミュニケーションコストの増加
    全体的なクオリティの低下

  マイクロサービスの利点と欠点はトレードオフ
    テクノロジーで解決できる部分はありつつも…
      横断的関心事に対処するというのもコストがかかる
      真にゼロにはならない
    モノリシックの辛いところは解消するが、モノリシックなら辛くないところが辛くなる

うまく良いところだけ取り出せないか
  マイクロサービスの良いところを最大限取り出したい
  以下の2点が重要っぽい
    いかにマイクロサービスを適切なタイミングで切り出すか
    マイクロサービスにおける複雑性をどう抑えるか
      コミュニケーションとか
      インフラとか
      いろんなレイヤの複雑性

マイクロサービスにおける複雑性をどう抑えるか
  あらゆる複雑性が襲いかかってくる
    権限が移譲された適切な組織構造
    マイクロサービスのインフラレイヤー
    データの整合性
      タイムアウトによるデータ異常
  どう対処するか
    組織構造
      良い答えを持ってない
      適切に分権してても容易に無視される
      人手が足りない+マイクロサービスを増やすとどうしようもない
      がんばる
    マイクロサービスのインフラレイヤー
      いろんな種類のサーバの面倒を見る必要がある
      一部が落ちると障害が連鎖して死ぬ
      対策は最近出始めている
    k8s
    Envoy
        Ballerina
      プラットフォーム側でのサポートもあり、ここは楽になりつつある

`暗黙知が暗黙知のまま放置されやすい`

-------------------------------------------
やっぱボツ↓
  ユーザ体感の統一も難しい
    デザイナーは共通チームにすることで問題を回避
      デザイナーチームはモノリシック
    機能毎に別々のチームが作るので…

サービス連携が複雑
  連携せざるを得ない部分はある
    完全に独立してたら1個のアプリでは無いので…
  チームをまたがった作業はオーバーヘッドがかかる
    コミュニケーションコストは基本的に高い
      APIによる連携は分割されたモジュールを呼び出すより大変
      適切な仕様のコミュニケーション、シリアライズ・デシリアライズ、通信異常
    別のチームは別の優先度で動いているので
    モノリシックより工数調整が大変
      プロジェクトの見積もりムズイ
  いかにチームやマイクロサービスを超えた機能開発を抑えるかが重要
  とはいえプロジェクト型開発は避けられない
    チームを超えて機能開発が起きる
      コミュニティ+チャット+ランキング
      チャット+ミッション+AI
    チームによる優先度と、横串の優先度との板挟み
  そもそも人が足りなくて1人で複数のマイクロサービスを見てたりする
    マイクロサービスを触れる人のリソースの取り合い
    キャッチアップもムズイ
      暗黙知が暗黙知のまま放置されやすい
  アーキテクチャは無形のシステム
    マイクロサービスの全体像を把握するのは難しい
    誰が何処にアクセスしているか

  StreamingArchitectureの導入みたいな、チームの温度感と違う問題も起きる

------------------------------
マイクロサービスの良いところ、悪いところを話す感じ
  良いところ
    最適な技術スタックを扱える
      DeepLearning
      速度が必要な時
    個々のサービスが小さくなる
      コード変更の影響範囲が限られる
      見通しやすく、新しい人のキャッチアップなども楽
      ここを見てやろうとすると失敗するのではという気持ち
    PDCA回す速度早い
      たぶん一番重要なのはこれ、ほかはコレを実現するための要素
      devops
      小さいチームのコントロール下における
      意思決定を小さいチームで行える
      (適切に権限が割り振られていれば)
        逆にどこに渡すかが明確でないと大変では
                  チーム外の人が実装しようとして、この機能何処に実装すべきですか?という話が出てくる
  悪いところ
    分散システムの複雑性
      サービスを超えたデータの整合性どうするのか
      サービス間の依存関係
        コードからは読み解きにくいので厄介
        サーバレスとかが間に挟まるとカオス
    マイクロサービスを超えた作業のオーバヘッド
      別のマイクロサービスの作業をするのは大変
      クオリティの統一や、セキュリティ的な面でほかチームへ影響を及ぼすのが難しい
      StreamingArchitectureの導入みたいな、チームの温度感と違う問題も起きる
    結合部分のつらみ
      クライアントアプリケーションはマイクロサービス関係ない
      ユーザが見る場所では結合が必要
      対策があるが…
        アプリ分割
        モジュール化
        マイクロフロントエンド
        UXの統一という意味では対策は無い
          一番マイクロサービスやってるAWSのコンソール…
          デザイン的なあれこれを統一しようという動きはある

辛いところ
  通信が複雑
    サービス間通信
      OpenAPI
      GraphQL
      gRPC
    対クライアント
      マルチリクエスト 
      BFF
      Micro Frontend
    データの同期
      イベントドリブン
      ストリーミング
      ESB
  データの状態が複雑
    トランザクションという武器を手放す
      人類が手に入れた並列性と戦う武器
    Sageパターン
    分散トランザクション
    結果整合性
    冪等性
  サービス分割が複雑
    権限管理
      人に紐づくもの
          followとか
      roleに紐付くもの
      管理画面
    サービスをまたいだ処理
    横断的関心事
    コミュニケーションコスト
    ロギング
    DDD
    分断されたモノリス
    どう分割するか
  チームが複雑
    プロジェクト型とプロダクト型
      原義のマイクロサービスは`チームに自由度と責任を与え、自己組織化されたチームに成長させる`のが大事
        中心に作っているプロダクトがあるプロダクト型
      プロジェクト型も一応ある
        某会社とか
        ただし、それにそった開発プロセスになってないと
      うちはプロジェクト型なのにプロダクト型にしようとしたのが失敗では
        とはいえ、オンボチームとかは成功してる
          フォーカスすることがぶれない&コントロール下にあるってのが重要っぽい
        lifelogチームはプロダクト型チームだけどプロジェクト型の都合で壊滅した。ただ、これはむしろ例外ケースみたいな感じ?
    コンウェイの法則
  インフラが複雑
    Ballerina
    ロギング
    k8s
    datalake
    カオスエンジニアリング
      障害の連鎖が起きやすく、わかりにくい

未整理
  CDCテスト
  コンテナのちからがマイクロサービスを推し進めている
    複数の種類のアプリケーションの面倒を見るインフラコストが下がっている
  生産性を下げない/上げるためのマイクロサービス
    生産性が下がるなら、マイクロサービスからモノリスに戻すのも一つの手
    (community)
    Martin Fowlerもそう書いている
  モノリシックカーネルとハイブリッドカーネル、マイクロカーネル
    マイクロカーネルが良かったんだけど、


Rails、現実的な解決策だよねという話
  実際、スタートアップが立ち上げからマイクロサービスをやるのは愚か
  マイクロサービスによるオーバヘッドは無視できない
  マイクロサービスにしないと、コミュニケーションパスが増えて人数が増えるとやばい
  RailsでとっととPMF作ろう、その後マイクロサービスにしたら?
  うちは事業が成功してないころも投資パワーで回せたのでマイクロサービスできたのでは

チームの人数を一定に保つためのマイクロサービスでは :thinking_face:
  2枚のピザ理論
  社会を構成する人の単位
    小隊・分隊
    家族とか
    https://ja.wikipedia.org/wiki/ダンバー数
    

狭い意味でのマイクロサービス(分散システム)はもともとやってるよね
  MySQL
  Redis
  誰もデータ永続化を自分のアプリケーションの中に書いてないし
  ドラクエ10(2012)はゲームプロセスとかを分割している
    ドラゴンクエストXを支える技術
  役割に応じて開発するのを分けるというのは、わりと普通の考え方
  今の広い意味でのマイクロサービスと何が違うのか
    故障要求とかかなー
    気軽さが上がったとかもありそう
    ecs/k8sが無い時代と今とだと違う

理想的なマイクロサービスとの付き合い方
  増やしすぎない
    増やす圧力はとても強い
    既存のモノリシックが辛ければ辛いほど
    完全に別チーム作れるなら話は別っぽい
    リファクタリングの方がはるかに楽
  既存から切り出す
    失敗しにくい(lifelog)
    新たに立てるとうーんみたいな事がある
    ただし、以降は簡単ではない
  たくさんの複雑さがある
    過渡期なので有効な解決策が無いことが多い
    将来的にはより簡単になるかもね
やるなら
  ラッパーマイクロサービス
    実質Appにいるけど別マイクロサービスが前にいるあれ
    BFFに実装したやつ
  機能でマイクロは辛い
    ある程度のビジネスでマイクロサービスにするべき
    FaaSはやめたほうがいい
    社内SaaSぐらいの規模にしたほうが成功しそう
    課金系のようなバックエンドの共通サービスというのはある
      とはいえ、アレも最初は成功していた
      それ単体で成長できないのが問題
        communityと紐づく
        小さすぎてそれ単体で大きくなれない
        PDCAの速度を落とさないためのマイクロサービスなので、PDCA回さないならそんなに意味がない…
  コストはかかる
    マイクロサービスにしたやつの開発コストは下がる
    マイクロサービス間の連携のコストはメソッド呼び出しに比べてかなり大きい
    チームを適切に分けて権限委譲したり、サービスの分断面を適切にしたり
    分割に失敗したときの影響はモノリシックより大きい
      組織ー複雑度の図

マイクロサービスは過渡期
  ecsとかk8sが無い数年前は相当大きくならないとペイしない
  今はk8sとかenvoyとか出てるので、中規模ぐらいでもペイすると思う
  もっと周辺ツールが進めば小規模でもペイするかもね
  (ただし、トランザクション境界や複雑性とかは解決しないので、そっち方面での限界はありそう)
  CIはあたりまえに、Dockerは徐々に当たり前になりつつある
    マイクロサービスはまだ当たり前ではない


良い資料
  https://tech.mercari.com/entry/2018/12/01/200159
  code:text
    チームの人数を6〜10名程度の少人数に保つ
  チームに自由度と責任を与え、自己組織化されたチームに成長させる
  開発と運用の両方に責任を持つことで、ソフトウェアサイクル全体からフィードバックを直接受け、改善サイクルを加速できるようにする
  質の高いツールや自動化など技術的な改善にも確実に投資する
https://gist.github.com/everpeace/c40b69eff6636b9ec2f9
  https://techlife.cookpad.com/entry/2014/09/08/093000
  http://kimitok.hateblo.jp/entry/2014/11/09/211820
    code:text
      めったに変更されないシステムの部分は、現在変更をたくさん行っている部分とは異なるサービスにするべきです。もし2つのサービスを同時に変更することが何度もあれば、それはそれらのサービスを1つにすべきサインです。

TDのマイクロサービス化の手順が良かった
  資料どこだっけな…