BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ アーティクル GitHubのモノリスからマイクロサービスへのジャーニー

GitHubのモノリスからマイクロサービスへのジャーニー

ブックマーク

キーポイント

  • Take a practical approach when deciding between a Monolithic or a Microservices paradigm, and focus on enablement
  • Apply good architectural practices around modularity, asynchronicity, and code for resiliency, no matter which path you decide to take
  • Start small and make it an incremental process aligned on product and business value
  • It’s important to make the necessary organizational and operational changes to encourage clarity and ownership
  • Focus on extracting core services and shared resources first as the foundation for the rest of your microservices

原文(投稿日:2021/07/28)へのリンク

この記事では、最近のGitHubのマイクロサービスアーキテクチャに向けたジャーニーについて説明します。GitHubの歴史的および現在の状態を詳しく調べ、いくつかの内部および外部の要因を検討し、この移行がどのように取り組みを始めたかに関する実際的な検討事項について説明します。次に組織のこの変革 (トランスフォーメーション) について考えるときに適用できるマイクロサービスアーキテクチャを実装するためのいくつかの重要な概念とベストプラクティスについて説明します。

始めに

GitHubは、開発者がコードをホストして共有しやすくする方法として2008年に設立されました。GitHubの創業者は、Rubyコミュニティのオープンソースの貢献者やインフルエンサでした。そのため、GitHubのアーキテクチャはRuby on Railsに深く根ざしていました。会社の歴史を通して、コードベースのスケーリングと最適化を支援するために、世界最高のRuby開発者を採用してきました。

今では、プラットフォームには5,000万人を超える開発者がおり、年間8,000万を超えるプルリクエストがマージされ、すべての世界中の大陸に1億を超えるリポジトリがあります。ご覧のとおり、モノリシックアーキテクチャは私たちをかなり遠ざけました。12年を越えるコードベースは、1日に複数のデプロイメントを処理する調整されたデプロイトレイン、毎日10億を超えるAPI呼び出しに対応する大規模なプラットフォーム、ジョブの完了に重点を置いたパフォーマンスのかなり高いユーザーインターフェースがあります。

急速な内部成長

内部的には、GitHubは過去18か月で大幅な成長フェーズを経ました。2,000人を超える従業員を擁し、コードベースに貢献するエンジニアの数は2倍以上になりました。私たちは有機的に成長し、Semmle、npm、Dependabot、PullPandaなどの買収を通じて成長しました。さらに、GitHubは高度に分散されたチームであり、パンデミックが発生する前は、従業員の70%以上がサンフランシスコ本社の外で働いていました。GitHubの従業員と請負業者は、6つの大陸で協力し、すべてのタイムゾーンで作業しています。

1,000人を超える社内開発者が多様なスキルを持ち込み、さまざまなテクノロジーで運用しているため、GitHubでのソフトウェア開発の方法を根本的に再考する必要があることが明らかになりました。生産性を上げる前に全員にRubyを学習させ、同じモノリシックコードベースで開発を行うことは、GitHubをスケーリングするための最も効率的で最適な方法ではなくなったのです。

Conway’s Law (コンウェイの法則) によれば、システムを設計する組織は、その構造が組織のコミュニケーション構造の複製である設計を作成します。これは逆も当てはまります。モノリシックな環境では、すべてのチームに影響を与えるロジックと共有データが織り交ぜられているため、利害関係者の会議をより大きくし、意思決定プロセスをより複雑にすることにつながります。

モノリス vs マイクロサービス

これは私たちを考えさせました、ついにRuby on Railsモノリスからマイクロサービスアーキテクチャへの移行を開始する時が来たのだろうか? もしそうなら、私たちはそれをどのように行うべきだろうか?

モノリシックアーキテクチャとマイクロサービスアーキテクチャの両方に利点があります。

モノリシック環境では、複雑な依存関係や適切な要素をすべて取り入れることを心配することなく、より迅速に起動して実行することが容易になります。新しいHubberをGitHubは数時間以内にローカルマシンで稼働させることができます。

モノリスにはコードレベルの単純さもあります。たとえば、タイムアウトに対処するためにロジックを追加したり、ネットワークの遅延や停止が原因で正常に失敗することを心配したりする必要はありません。

さらに、全員が共有の技術スタックで作業しており、同じコードベースに精通しているため、モノリス内のさまざまな機能に取り組むために人やチームを移動し、機能のよりグローバルな優先順位付けに向けて推進することが容易になります。

過去18か月のGitHubの成長で、マイクロサービス環境の利点のいくつかは私たちにとって本当に魅力的に見え始めています。たとえば、システムレベルの所有権を持つ機能チームを設定し、明確に定義されたAPIの契約を通じて機能の境界を設定します。APIの契約が守られている限り、チームはそれらにとって最も意味のある技術スタックを自由に選択できます。

また、サービスが小さいほど、コードの読み取りが容易になり、立ち上げ時間が短縮され、そのコードベース内でのトラブルシューティングが容易になります。開発者は、生産性を高めるために、大規模なモノリシックコードベースの内部機能すべてを理解する必要がなくなりました。最も重要なことは、サービスを個々のニーズに基づいて個別にスケールできるようになったことです。

実用的か - 有効化について

 

GitHubでこの移行に取り掛かる前に、私たちは、決定の背後にある理由と、この変更を行うための目標について考えることに時間を費やしました。それは文化的な観点から私たちにとって大きな変化であり、多くの作業を必要とします。

私たちは意図的に考え、解決しようとしている問題や問題点について考える必要があります。GitHubでこれを行うため、過去18か月間に参加した開発者ベースの半分以上をモノリスの外側で生産することにしました。

私たちの目標は、有効化であって置き換えではありません。そのため、GitHubでは、当面の間モノリスとマイクロサービスのハイブリッド環境になるという事実を受け入れる必要があります。つまり、モノリスの既存のコードベースを維持および改善することは依然として非常に重要ということです。この良い例は、Ruby 2.7への最近のアップグレードです。GitHubブログで、私たちが行ったことと、それによってシステム全体がどのように改善されたかについて詳しく読むことができます。

モジュール化から始める優れたアーキテクチャ

優れたアーキテクチャはモジュール化から始まります。モノリスを解体するための最初のステップは、機能特性に基づいてコードとデータを分離することを考えることです。これは、マイクロサービス環境でモノリスを物理的に分離する前に、モノリス内で実行できます。

一般に、コードベースをより管理しやすくすることは優れたアーキテクチャプラクティスです。データから始めて、データへのアクセス方法に細心の注意を払ってください。各サービスが独自のデータへのアクセスを所有および制御していること、およびデータアクセスが明確に定義されたAPI契約を通してのみ発生することを確認してください。

人々がコードロジックを引き出すことから始めても、モノリス内の共有データベースへの呼び出しに依存しているケースをたくさん見ました。これは、分散型モノリスシナリオにつながることが多く、最終的には両方の世界で最悪になります。つまり、マイクロサービスの複雑さを何のメリットもなく管理しなければならなくなります。機能のサブセットをプロダクション環境に迅速かつ独立してデプロイできるなどの利点です。

GitHubのデータ分離

データ分離を正しく行うことは、モノリシックアーキテクチャからマイクロサービスに移行する際の基礎です。GitHubでどのようにアプローチするかを詳しく見てみましょう。

最初に、既存のデータベーススキーマの機能境界を特定し、これらの境界に沿って実際のデータベーステーブルをグループ化しました。たとえば、リポジトリに関連するすべてのもの、ユーザに関連するすべてのもの、プロジェクトに関連するすべてのものをグループ化しました。これらの結果である機能グループはスキーマドメインと呼ばれ、YAML定義ファイルにキャプチャされます。これが私たちの真実の源であり、データベーススキーマにテーブルが追加または削除されるたびに更新されることが期待されています。リントテストを使用して、開発者がこれらの変更を行うときにこのファイルを最新の状態に保たれるように通知します。

次に、各スキーマドメインのパーティションキーを特定しました。これは、機能グループのすべての情報をリンクする共有フィールドです。たとえば、リポジトリに関連するすべてのデータ (イシュー、プルリクエスト、レビューコメントなど) を保持するリポジトリスキーマドメインは、パーティションキーとしてリポジトリIDを使用します。データベーススキーマの機能グループを作成すると、最終的には、マイクロサービスアーキテクチャに必要なさまざまなサーバやクラスタにデータを安全に分割できるようになります。まず、ドメイン境界を越える現在のクエリを修正する必要がありました。これにより、データの分離が発生したときにプロダクトが壊れることはありません。

GitHubでは、クエリが機能ドメインを横断するたびに検出してアラートを送信できるように、モノリスにクエリウォッチャを実装しました。次に、これらのクエリを分割して、ドメイン境界を遵守する複数のクエリに書き換え、アプリケーションレイヤで必要な結合を実行します。

最後に、すべての機能グループが分離された後、同様のプロセスを開始して、データをさらにテナントグループに分割できます。5,000万人を超えるユーザと1億のリポジトリがあるため、機能グループはGitHubスケールではかなり大きくなる可能性があります。ここではパーティションキーが役立ちます。同様のプロセスに従って、グループ化するパーティションキーの範囲を特定できます。

たとえば、数値の範囲に基づいてさまざまなユーザをさまざまなデータストアに割り当てることは簡易な方法です。地域やサイズなど、各データセットの特性に基づいて、おそらくより論理的なグループ化があります。テナント化は、データストレージ障害の炎上範囲 (blast redius) を、一度にすべてに影響を与えるのではなく、顧客のサブセットのみに制限するための優れた方法です。

コアサービスと共有リソースから始める

データ分離の重要性を探った後、ギアを切り替えて、モノリスからサービスを抽出するための基礎を築く方法に飛び込みましょう。依存関係の方向は常にモノリスの内側から外側に向かう必要があり、その逆ではないことを覚えておくことが重要です。そのため、分散したモノリスの状況に陥ることはありません。これは、モノリスからサービスを抽出するときは、コアサービスから始めて、機能レベルに進むことを意味します。

次に、開発者がモノリスで作業し続ける引力を探します。モノリス内での開発を非常に便利にする共有ツールは、時間の経過とともに構築されるのが一般的です。たとえば、GitHubのフィーチャーフラグ (feature flags) は、モノリス開発者に、スタッフによりリリースされたベータ版からプロダクション環境に移行するときに、誰が新しい機能を見ることができるかを制御できるという安心感を提供します。これらの共有リソースをモノリスの外部の開発者が利用できるようにし、その引力をシフトし始めます。最後に、新しいサービスが稼働したら、必ず古いコードパスを削除します。ツールを使用して、誰がこのサービスを呼び出しているかを理解し、トラフィックの100%を新しいサービスに移動する計画を立てて、2セットのコードのサポートで永遠に行き詰まることがないようにします。GitHubでは、Scientistと呼ばれるオープンソースツールを使用して、この種のロールアウトを支援しています。このツールは、古いコードパスと新しいコードパスの両方を並べて実行および比較できます。

GitHubのAuthN/AuthZを抽出する

GitHubで最初に抽出することにしたコアサービスは、認証と認可でした。

すべてにおいて認証が必要なため、かなり複雑です。WebサイトとGitの運用の間には多くの共有ロジックがあります。つまり、github.com がダウンすると、Gitシステムへのアクセスもダウンし、プルやプッシュなどのGit操作はコマンドラインインターフェイスを通しても機能しなくなります。これが、これらの基本的な部分のいくつかを抽出して、モノリスに縛られることなく主要な機能を引き続き実行できるようにすることが非常に重要である理由です。

私たちの認可ははるかに簡単で、モノリスの外のゴーストサービスとしてすでに書き直されています。現在のRailsアプリ (別名モノリス) は、gRPCのようなサービス間通信フレームワークであるTwirpを使用して通信するため、内部から外部への依存関係の方向性が必要です。

運用を変更する

監視、CI/CD、およびコンテナ化は新しい概念ではありませんが、モノリスからマイクロサービスへの変革 (トランスフォーメーション) をサポートするために必要な運用上の変更を行うことで、大幅な時間の節約を実現し、マイクロサービスへの移行を促進できます。

これらのワークフローを変更するときは、マイクロサービスの主な特徴を念頭に置いてください。多様な技術スタックを使用して多数の小規模で独立して実行されるサービスの運用をサポートすることは、大規模なモノリスのために高度にカスタマイズされた単一のパイプラインを実行することとは大きく異なります。機能呼び出しメトリックからネットワークメトリックおよび契約インターフェイスに監視を更新します。サービス間で共有できる、より自動化された信頼性の高いCI/CDパイプラインを推進します。コンテナ化を使用して、さまざまな言語と技術スタックをサポートします。再利用性を有効にするワークフローテンプレートを作成します。

たとえば、GitHubでは、マイクロサービスをボックスで提供するセルフサービスランタイムプラットフォームを作成しました。目標は、マイクロサービスを作成するための各チームの運用オーバーヘッドを大幅に削減することです。Kubernetes対応のテンプレート、負荷分散のための無料のIngressセットアップ、Splunkへのログの自動パイプ、および内部デプロイメントプロセスへの統合が付属しています。したがって、新しいマイクロサービスやセットアップで実験を希望するチームが簡単に開始できるようになります。

小規模から始めて、プロダクト/ビジネスへの価値について考える

ここまで、モノリスからマイクロサービスアーキテクチャへの移行を成功させるために必要な構造の変更と共有基盤について多くのことを説明してきました。この時点からは、新しい機能をモノリスの外部のマイクロサービスとして作成する必要があります。次に、モノリスから抜け出すためのいくつかのシンプルでマイナーな機能を探します。たとえば、複雑な依存関係や共有ロジックがあまりない機能。GitHubでは、Webhookのデリバリーと構文の強調表示から始めました。これを機会として、一般的なパターンを探し、ギャップを特定してから、モノリスのより大きくて奥深い機能に移ります。プロダクトとビジネスの価値を使用して、マイクロサービスの適切なサイズを決定します。

頻繁に変更およびデプロイされるコードとデータを探して、より密結合された機能を判別します。これらを、他の領域から独立して繰り返しデプロイできる自然なグループとして使用します。プロダクトとビジネスの価値に焦点を当てることは、エンジニアリング、プロダクトおよび設計にわたる組織の調整にも役立ちます。細かく分割しすぎると、不必要な複雑さとオーバーヘッドが追加される可能性があることに注意してください。たとえば、個別のデプロイキー、より多くのオンコール責任、および共有知識の欠如による単一障害点などです。

非同期と回復力のあるコードへの移行

モノリスからマイクロサービスへの移行は、大きなパラダイムシフトです。この移行を経て、ソフトウェア開発プロセスと実際のコードベースの両方が大幅に違って見えるようになります。最後に、マイクロサービス開発の重要な概念であるサービス間通信と障害の設計について簡単に説明します。

サービスが相互に通信する方法には、同期と非同期の2つがあります。同期通信では、クライアントは要求 (リクエスト) を送信し、サーバからの応答 (response) を待ちます。非同期通信では、クライアントは応答 (response) を待たずにメッセージを送信し、各メッセージは複数の受信者 (レシーバ) で処理することができます。

GitHubでは、Twirpを使用して認可などモノリスとモノリス外のコアサービス間の同期通信を有効にします。ただし、より多くのサービスがモノリスの外に移動すると、右上の図が示すように、同期通信は非常に効率の悪いものになり始めます。また、すべてのサービス間で密結合が作成され、マイクロサービスアーキテクチャに移行するという目的が果たせなくなります。より良いアプローチは、複数のプロデューサとコンシューマ間でメッセージを仲介できる共有イベントパイプラインを作成することです。これは、SendGridで使用したアーキテクチャです。

サービスが単一サーバでホストされなくなったため、ネットワークを介して通信する場合は、遅延と障害のシナリオを考慮することが重要です。ほとんどの一時的なネットワークの問題を処理するには、再試行の頻度と最大再試行回数が明確に定義された単純な再試行ロジックで十分な場合があります。指数バックオフを使用して、再試行ロジックにインテリジェンスを追加することを検討してください。指数バックオフは、一定の間隔で要求を再試行する代わりに、再試行間の待機時間を増やし、過負荷のために応答していないサーバにある程度の救済を提供します。

サーキットブレーカは、自己保護および修復メカニズムとしてのサービス間の媒体として追加することもできます。たとえば、何度か試行に失敗すると、サーキットブレーカがオープンし、サービスが回復するまで追加の要求を通過できなくなります。タイムアウトを設定して、サービスが外部サービスの応答を永遠に待たないようにします。ユーザフレンドリーなメッセージを表示するか、キャッシュ内の最後の既知の良好な状態にフォールバックして、正常に失敗してみてください。ユーザエクスペリエンスに注意し、ビジネスにとって意味のあることを実行してください。

結論

最初の4つのセクションでは、モノリスからマイクロサービスに移行するジャーニーを始める前に必要な基本的な要素に焦点を当てています。Whyに焦点を当てます。モジュール化とデータ分離について考えてください。コアサービスと共有リソースから始めて、必要な運用上の変更を加えてください。これらを正しく行うことで、マイクロサービスへの移行が組織全体にとってはるかに楽しい体験になります。次に、どこから始めればよいか、マイクロサービスをプロダクトやビジネスの価値に結び付ける方法について話しました。最後に、サービス間通信と回復力のあるシステムの構築に関するマイクロサービスの2つの重要な概念について説明しました。

著者について

Sha Ma氏 は現在業界をリードするカスタマサクセスプラットフォームであるCatalyst.ioの副社長兼エンジニアリング責任者です。Catalystの前は、GitHubでエンジニアリング担当副社長を務め、コアプラットフォームとエコシステムを担当していました。2017年、SendGridでエンジニアリング担当副社長として、Shaは会社を公開したリーダシップチームの一員でした。Shaは、多様性 (diversity)、公平性 (equity)、職場への包含性 (inclusion) に情熱を注いでおり、2018年に、Denver Business Journalのテクノロジーとテレコミュニケーションにおけるビジネスにおける優れた女性 (Outstanding Women in Business in Technology and Telecommunications) の受賞者に選ばれました。Shaは夫と2人の子供と一緒にコロラドに住んでおり家族とのスキー、セーリング、旅行を楽しんでいます。

この記事に星をつける

おすすめ度
スタイル

こんにちは

コメントするには InfoQアカウントの登録 または が必要です。InfoQ に登録するとさまざまなことができます。

アカウント登録をしてInfoQをお楽しみください。

HTML: a,b,br,blockquote,i,li,pre,u,ul,p

コミュニティコメント

HTML: a,b,br,blockquote,i,li,pre,u,ul,p

HTML: a,b,br,blockquote,i,li,pre,u,ul,p

BT