This page contains information related to upcoming products, features, and functionality. It is important to note that the information presented is for informational purposes only. Please do not rely on this information for purchasing or planning purposes. As with all projects, the items mentioned on this page are subject to change or delay. The development, release, and timing of any products, features, or functionality remain at the sole discretion of GitLab Inc.
StatusAuthorsCoachDRIsOwning StageCreated
proposed @ayufan @mkaeppler @glopezfernandez devops non_devops 2021-05-19

Composer GitLab コードベース

note
GitLab.comの全体的な可用性を向上させ、技術的負債を減らすことに注力しているため、この青写真を実行する能力はありません。23年度第1四半期に再評価を行う予定です。

単一のコードベースの大きなリスクの一つは、アプリケーション全体の無限の成長です。コードが増えれば増えるほど、アプリケーションの実行に必要なリソースが増え続けるだけでなく、アプリケーションの結合が増え、複雑さが爆発的に増大します。

要旨

このブループリントでは、アプリケーション・コードベースを削減・改善する方法としてアプリケーション・レイヤーを導入することの影響について議論します。提案するソリューションの肯定的な結果と否定的な結果について議論し、GitLab.comや小規模インストールへの影響を見積もろうとします。

Application Layersでは、GitLab Railsのコードベースを縦割りではなく、私たちが実際にGitLabを運用しているパターンに従って水平に分割しようとしています。これは、1つの機能が様々な方法で実行される必要があり(例えばCIはWebインターフェースを持ち、APIを使用し、バックグラウンド処理を実行します)、結合のために特定の機能だけを他のアプリケーション(CIのような)と分離して実行することは容易ではないという考えに従ったものです。

この提案自体は、機能のいくつかの側面を切り離すことを可能にしています。これらの側面は、スタックの残りの部分とは別に実行されるコンポーネントとして扱われますが、それでもコアの大部分は共有されます。このモデルは、外部ツール(ランナーAPI、パッケージAPI、機能フラグアンリーシュAPI)用のAPIインタフェースを提供するために実装することができます。

実際の分割は、単一のリポジトリに別々のgemを実装したRails Enginesを使用してテストされました。Rails Enginesを使うことで、個々のコンポーネントを依存関係とともに適切に記述し、多数のRails Enginesで構成されるアプリケーションを実行することができました。

このブループリントは、GitLabの成功の主要な側面である、単一でモノリシックなコードベース(単一のデータストアを持つ)を維持することを目的としていますが、アプリケーションをよりよくモデル化し、コードベースをよりComposerにすることができます。

モノリスの課題(現状)

今日、モノリスの使用は、多くのケースで挑戦的であることが証明されています。明確な境界のない単一の大きなモノリスのコードベースは、多くの問題と非効率をもたらします:

  • 深い結合は、アプリケーションを長期的に開発しにくくします。それは、より多くのインターフェイス・ベースのアーキテクチャを構築することを考慮する代わりに、スパゲッティ実装につながるからです。
  • コードベースの部分間の深い結合は、テストを難しくします。アプリケーションの一部だけをテストする場合、どの部分が影響を受けるかを確実に知るためには、通常テストスイート全体を実行する必要があります。これは、このプロセスを支援するヒューリスティックを構築することである程度改善できますが、エラーになりやすく、常に正確な状態を保つのは困難です。
  • アプリケーションの一部だけを実行するには、すべてのコンポーネントを常にロードする必要があります。
  • 特定のコンテキストではほとんど使用されないアプリケーションの一部をロードするため、リソース使用量が増加します。
  • メモリ使用量が多いため、GC サイクルが長くなり、リクエスト処理の待ち時間が大幅に長くなったり、CPU のキャッシュ使用率が悪化したりして、アプリケーション全体が遅くなります。
  • より多くのファイルを読み込んで解析する必要があるため、アプリケーションの起動時間が長くなります。
  • 起動時間が長くなると、アプリケーションやテストの実行に大幅に時間がかかるため、開発速度が低下し、反復回数が減少します。

コンポーザブルなコードベースの寸法

一般的に、コードベースのモデル化には2つの方法があります:

  • 垂直方向にバウンデッドコンテキスト(Bounded Contexts)、各コンテキストはアプリケーションのドメインを表します。
  • アプリケーションレイヤーの水平方向:Sidekiq、GraphQL、REST API、Webコントローラ、すべてのドメインモデルとDBと直接インターフェースするサービス

このブループリントでは、水平分割とアプリケーションレイヤーについて明確に説明しています。

Bounded Contexts(垂直分割)の現状

Bounded Contextsは、数年前から何度も盛んに議論されてきたトピックです。多くのイシューに反映されています:

Bounded Contextsのアイデアを部分的に実行しています:

  • ネームスペースはコードベースのmodule
  • 名前空間は明確な境界を定義するので、各チームが自分のテストを所有するようにします。
  • 名前空間を使用するため、個々の貢献者やレビュアーは、与えられたコンテキストに関するヘルプについて、ドメインの専門家から誰に連絡すればよいかを知ることができます。

モジュールの名前空間は、チームの境界を越えてコードベースをモデル化するために、今日アクティブに使用されています。現在最もよく使われている名前空間はCi::Packages:: です。これらは、グループによって所有されるコードを明確に定義された構造でコンテナ化する良い方法を提供します。

しかし、Bounded Contextsは開発者には役立ちますが、上記の目標には役立ちません。これは純粋にコードの論理的な分割です。これはディープカップリングを防ぐものではありません。CIパイプラインのバックグラウンド処理とRunner APIインターフェースの間に循環依存関係を作成することはまだ可能です(そしてそれはしばしば起こります)。APIはSidekiq Workerを呼び出すことができ、Sidekiqはエンドポイントパスを作成するためにAPIを使用することができます。

Bounded Contextsは、コードベース全体がロードされ実行される必要がある単一のパッケージとして扱われるため、何が何に依存しているかを知るためにコードベースを賢くすることはありません。

Bounded Contextのデメリットに追加で考慮すべきこと:

  • 部族的な知識や重複したコードにつながる可能性
  • 深い結合は、反復や最小限の変更を困難にします。
  • 垂直的な分割のため、変更が連鎖的に影響する可能性があり、その影響を切り分けるのが難しい

アプリケーションレイヤー(水平分割)

バウンデッドコンテキストを名前空間の分離という形で活用し続けることで、開発者とレビュアーに役立つ一方で、アプリケーションレイヤーは、異なる機能部分の間をきれいに分離する方法を提供することができます。

私たちの主なコードベース(GitLab Rails Ruby on Rails上で動作するGitLabの後)は、多くの暗黙的なアプリケーションレイヤーで構成されています。各レイヤーの間には明確な境界がないため、深い結合が生じます。

アプリケーションレイヤーのコンセプトは、個々の機能(CIやパッケージなど)の観点ではなく、アプリケーションをどのように実行するかという観点からアプリケーションを見ます。今日のGitLabアプリケーションは以下のアプリケーションレイヤーに分解することができます。このリストは網羅的なものではありませんが、一つのモノリシックなコードベースの異なる部分の一般的なリストを示しています:

  • ウェブコントローラ:ウェブインタフェースにアクセスしたユーザーからのウェブリクエストを処理します。
  • Web API:自動化ツールからのAPIコール、場合によってはWebインターフェースにアクセスしたユーザーからのAPIコールも処理します。
  • ウェブランナーAPI:RunnerからのAPIコール。Runnerが新しいジョブを取得したり、トレースログを更新したりすることを可能にします。
  • Web GraphQL: 柔軟なAPIインターフェイスを提供し、Webフロントエンドが必要なデータのみをフェッチできるようにすることで、計算とデータ転送の量を削減します。
  • Web ActionCable: 双方向接続を提供し、ウェブインターフェイスにアクセスするユーザーにリアルタイム機能を提供します。
  • Web 機能フラグ Unleash Backend: GitLab API を使用する Unleash 互換サーバーを提供します。
  • Web Packages API: パッケージングツールと互換性のある REST API を提供します:Debian、Maven、コンテナレジストリプロキシなど。
  • Git ノード:SSH 上でgit pull/push を作成するために必要なすべてのコード。HTTPS
  • Sidekiq: バックグラウンドジョブの実行
  • サービス/モデル/DB: データベース構造、データ検証、ビジネスロジック、ポリシーモデルを維持するために必要なすべてのコードで、他のコンポーネントと共有する必要があります。

GitLab Railsの実際のスプリットがどのようなものかを説明するのに最も適した方法です。それはサテライトモデルです。一つのCoreがあり、それがすべてのサテライトコンポーネントで共有されます。この設計では、サテライトコンポーネントが互いに通信する方法は限られています。単一のモノリシックなアプリケーションでは、ほとんどの場合、アプリケーションはコードと通信します。サテライトモデルでは、通信はコンポーネントの外部で実行される必要があります。これは、データベース、Redis、または明確に定義された公開APIを使用します。

flowchart TD subgraph Data Store D[Database] R[Redis] end subgraph Rails Engines subgraph Data Access Layer C[Core] end subgraph Web Processing W[Web] end subgraph Background Processing S[Sidekiq] end end C --> D & R W & S -- using application models --> C R -- push background job --> S W -- via async schedule --> S S -- via Web API --> W

オンプレミスインストールのアプリケーションレイヤー

オンプレミスのインストールはかなり小規模で、通常GitLab Railsを主に2つのフレーバーで実行します:

graph LR gitlab_node[GitLab Node with Load Balancer] gitlab_node_web[Web running Puma] gitlab_node_sidekiq[Background jobs running Sidekiq] gitlab_node_git[Git running Puma and SSH] subgraph GitLab Rails gitlab_rails_web_controllers[Controllers] gitlab_rails_api[API] gitlab_rails_api_runners[API Runner] gitlab_rails_graphql[GraphQL] gitlab_rails_actioncable[ActionCable] gitlab_rails_services[Services] gitlab_rails_models[Models] gitlab_rails_sidekiq[Sidekiq Workers] end postgresql_db[(PostgreSQL Database)] redis_db[(Redis Database)] gitlab_node --> gitlab_node_web gitlab_node --> gitlab_node_sidekiq gitlab_node --> gitlab_node_git gitlab_node_web --> gitlab_rails_web_controllers gitlab_node_web --> gitlab_rails_api gitlab_node_web --> gitlab_rails_api_runners gitlab_node_web --> gitlab_rails_graphql gitlab_node_web --> gitlab_rails_actioncable gitlab_node_git --> gitlab_rails_api gitlab_node_sidekiq --> gitlab_rails_sidekiq gitlab_rails_web_controllers --> gitlab_rails_services gitlab_rails_api --> gitlab_rails_services gitlab_rails_api_runners --> gitlab_rails_services gitlab_rails_graphql --> gitlab_rails_services gitlab_rails_actioncable --> gitlab_rails_services gitlab_rails_sidekiq --> gitlab_rails_services gitlab_rails_services --> gitlab_rails_models gitlab_rails_models --> postgresql_db gitlab_rails_models --> redis_db

GitLab.comのアプリケーションレイヤー

GitLab.comは規模が大きいため、運営にはより多くの注意が必要です。これは、リソースをよりよく管理し、異なる機能部分に対してSLAを提供するために必要です。下のChartは、GitLab.comのアプリケーションレイヤーを単純化したものです。オブジェクトストレージやGitalyノードのようなすべてのコンポーネントを含んでいるわけではありませんが、異なるコンポーネント間のGitLab Railsの依存関係と、それらが今日GitLab.comでどのように設定されているかを示しています:

graph LR gitlab_com_lb[GitLab.com Load Balancer] gitlab_com_web[Web Nodes running Puma] gitlab_com_api[API Nodes running Puma] gitlab_com_websockets[WebSockets Nodes running Puma] gitlab_com_sidekiq[Background Jobs running Sidekiq] gitlab_com_git[Git Nodes running Puma and SSH] subgraph GitLab Rails gitlab_rails_web_controllers[Controllers] gitlab_rails_api[API] gitlab_rails_api_runners[API Runner] gitlab_rails_graphql[GraphQL] gitlab_rails_actioncable[ActionCable] gitlab_rails_services[Services] gitlab_rails_models[Models] gitlab_rails_sidekiq[Sidekiq Workers] end postgresql_db[(PostgreSQL Database)] redis_db[(Redis Database)] gitlab_com_lb --> gitlab_com_web gitlab_com_lb --> gitlab_com_api gitlab_com_lb --> gitlab_com_websockets gitlab_com_lb --> gitlab_com_git gitlab_com_web --> gitlab_rails_web_controllers gitlab_com_api --> gitlab_rails_api gitlab_com_api --> gitlab_rails_api_runners gitlab_com_api --> gitlab_rails_graphql gitlab_com_websockets --> gitlab_rails_actioncable gitlab_com_git --> gitlab_rails_api gitlab_com_sidekiq --> gitlab_rails_sidekiq gitlab_rails_web_controllers --> gitlab_rails_services gitlab_rails_api --> gitlab_rails_services gitlab_rails_api_runners --> gitlab_rails_services gitlab_rails_graphql --> gitlab_rails_services gitlab_rails_actioncable --> gitlab_rails_services gitlab_rails_sidekiq --> gitlab_rails_services gitlab_rails_services --> gitlab_rails_models gitlab_rails_models --> postgresql_db gitlab_rails_models --> redis_db

レイヤーの依存関係

GitLabをオンプレミスで運用する方法とGitLab.comで運用する方法の違いは、GitLab Railsの主要な分割線を示しています:

  • Web: すべての API、すべてのコンテナ、すべての GraphQL と ActionCable 機能を含みます。
  • Sidekiq: すべてのバックグラウンド処理ジョブを含む
  • Core:WebとSidekiqの間で共有する必要があるすべてのデータベース、モデル、サービスが含まれます。

これらのトップレベルのアプリケーションレイヤーは、関連するすべての依存関係を持つコードベースの一部にのみ依存します:

  • すべての場合において、基礎となるデータベース構造とアプリケーションモデルが必要です。
  • 場合によっては依存サービスが必要
  • アプリケーション共通ライブラリの一部だけが必要な場合
  • 要求された機能をサポートするgemsが必要
  • 個々のレイヤーは別の兄弟レイヤーを使用せず(密結合)、APIやRedis、DB経由で接続してデータを共有する必要があります(疎結合)。

提案

メモリチームグループは、アプリケーションレイヤー導入の影響を理解するために概念実証フェーズを実施しました。これは、この提案を実行するための複雑さ、影響、必要な反復を理解するために行いました。

ここでの提案は、この青写真の影響の評価として扱われるべきですが、実装されるべき最終的な解決策ではありません。定義されたPoCはマージされるべきものではなく、将来の作業の基礎となるものです。

Railsエンジンを使ったPoC

Webアプリケーションレイヤーをモデリングすることで、Rails Enginesを使用することにしました。Webエンジンには、コンテナ、API、GraphQLが含まれていました。これにより、すべての依存関係を持つWebノードを実行することができましたが、これらのコンポーネントがロードされない場合のSidekiqへの影響を測定することができました。

すべての作業はこれらのマージリクエストにあります:

何が行われましたか?

  • Railsエンジンを使用しました。
  • 上記のMRにあるように、99%の変更はそのままファイルを移動しています。
  • すべてのGraphQLコードと仕様をそのままengines/web_engine/
  • すべてのAPIとコントローラのコードと仕様をengines/web_engine
  • スタックの自立したコンポーネントとしてengines/web_engine/ をテストするために CI を適応させました。
  • GitLabを設定し、gem web_engine Webノード(Puma Webサーバ)をロードするようにしました。
  • バックグラウンド処理ノード(Sidekiq)の実行時にweb_engine をロードしないようにしました。

提案ソリューションの実装詳細

  1. 各アプリケーションレイヤーに新しいRailsエンジンを導入します。

    engines フォルダを作成しました。このフォルダには、今後導入するアプリケーション層ごとに異なるエンジンを格納することができます。

    上記のPoCでは、engines/web_engine フォルダにある新しいWebアプリケーションレイヤーを導入しました。

  2. すべてのコードと仕様をengines/web_engine/

    • ファイル自体を変更することなく、すべてのGraphQLコードと仕様をengines/web_engine/
    • すべてのGrape APIとコントローラのコードを、ファイル自体を変更することなく、engines/web_engine/
  3. gems をengines/web_engine/

    • すべてのGraphQL gemsを実際のweb_engine Gemfileに移動しました。
    • Grape API gem を実際のweb_engine Gemfile に移動しました。
    Gem::Specification.new do |spec|
      spec.add_dependency 'apollo_upload_server'
      spec.add_dependency 'graphql'
      spec.add_dependency 'graphiql-rails'
       
      spec.add_dependency 'graphql-docs'
      spec.add_dependency 'grape'
    end
    
  4. engines/web_engine/config/routes.rb ファイルにルートを移動します。

    • GraphQLルートをweb_engine routesに移動しました。
    • API ルートをweb_engine ルートに移動しました。
    • コントローラルートのほとんどをweb_engine ルートに移動しました。
    Rails.application.routes.draw do
      post '/api/graphql', to: 'graphql#execute'
      mount GraphiQL::Rails::Engine, at: '/-/graphql-explorer', graphql_path:
      Gitlab::Utils.append_path(Gitlab.config.gitlab.relative_url_root, '/api/graphql')
       
      draw :api
       
      #...
    end
    
  5. 内部イニシャライザをengines/web_engine/config/initializers フォルダに移動します。

    • graphql.rb のイニシャライザーをweb_engine のイニシャライザーフォルダーに移動しました。
    • grape_patch.rbgraphe_validatorsweb_engine initializers フォルダーに移動しました。
  6. GitLab アプリケーションと WebEngine を接続します。

    GitLab Gemfile.rb で、web_engine を engines グループに追加します。

    # Gemfile
    group :engines, :test do
      gem 'web_engine', path: 'engines/web_engine'
    end
    

    このgemは:enginesグループの中にあるので、デフォルトでは自動的に必須ではありません。

  7. GitLabにエンジンをロードするタイミングを設定します。

    GitLabconfig/engines.rb では、エンジンをロードするタイミングを設定することができます。Gitlab::Runtime

    # config/engines.rb
    # Load only in case we are running web_server or rails console
    if Gitlab::Runtime.puma? || Gitlab::Runtime.console?
      require 'web_engine'
    end
    
  8. エンジンの設定

    EngineはRails::Engine クラスを継承しています。こうすることで、このgemは指定されたパスにエンジンがあることをRailsに通知し、アプリケーション内でエンジンを正しくマウントして、モデル、メーラー、コントローラ、ビューのロードパスにエンジンのappディレクトリを追加するなどのタスクを実行します。lib/web_engine/engine.rb のファイルは、標準的なRailsアプリケーションのconfig/application.rb ファイルと機能は同じです。このようにして、エンジンはすべてのレイルティとアプリケーションで共有される設定を含む設定オブジェクトにアクセスできます。さらに、各エンジンは、そのエンジンにスコープされたautoload_pathseager_load_pathsautoload_once_paths 設定にアクセスできます。

    module WebEngine
      class Engine < ::Rails::Engine
        config.eager_load_paths.push(*%W[#{config.root}/lib
                                         #{config.root}/app/graphql/resolvers/concerns
                                         #{config.root}/app/graphql/mutations/concerns
                                         #{config.root}/app/graphql/types/concerns])
       
        if Gitlab.ee?
          ee_paths = config.eager_load_paths.each_with_object([]) do |path, memo|
            ee_path = config.root
                        .join('ee', Pathname.new(path).relative_path_from(config.root))
            memo << ee_path.to_s
          end
          # Eager load should load CE first
          config.eager_load_paths.push(*ee_paths)
        end
      end
    end
    
  9. テスト

    スタックの自立したコンポーネントとしてengines/web_engine/ をテストするために CI を適応させました。

    • spec as-is ファイルをengines/web_engine/spec フォルダーに移動しました。
    • ee/spec as-is ファイルをengines/web_engine/ee/spec フォルダーに移動しました。
    • メイン・アプリケーションから環境変数TEST_WEB_ENGINE
    • TEST_WEB_ENGINE 環境変数を使用してengines/web_engine/spec テストを個別に実行する新しい CI ジョブを追加しました。
    • TEST_WEB_ENGINE 環境変数を使用してengines/web_engine/ee/spec テストを個別に実行する新しい CI ジョブを追加しました。
    • すべてのホワイトボックスフロントエンドテストをTEST_WEB_ENGINE=true

結果

これらの変更を導入した場合の効果:

  • RSSの節約
  • 61.06 MB (7.76%) - GraphQLなしのSidekiq
  • 100.11 MB (12.73%) - Sidekiq、GraphQLおよびAPIなし
  • 208.83 MB (26.56%) - Sidekiq、GraphQL、API、コントローラなし
  • Webノード(Puma実行中)のサイズは以前と同じです。

GraphQL、API、コントローラーを使用しないシングルSidekiqクラスターの場合、Sidekiqstart-up イベントで節約されたコスト

  • 264.13MBのRSSを節約 (28.69%)
  • 264.09 MB USS を保存 (29.36%)
  • 起動時間が45.31秒から21.80秒に短縮されました。23.51秒高速化(51.89%)。
  • ライブオブジェクトが805,772個、割り当てオブジェクトが4,587,535個、割り当てページが2,866ページ、ヒープ外のオブジェクトの割り当て領域が3.65MB減少しました。
  • コード・ファイルのロードが2,326個少なくなりました (15.64%)。
  • 1回の完全なGCサイクルの時間を0.80秒から0.70秒に短縮 (12.64%)

Pumaシングルでは、予想通りほとんど差がありませんでした。

詳細はイシューをご覧ください。

GitLab.comへの影響

GitLab.comを運営する規模の結果を見積もるために、今日、私たちは次のものを使っています:

web_engine を導入した場合の最大節約可能量を試算してみました:

  • GCのサイクルタイムを20%短縮。
  • 1秒あたりのGCサイクルの量は変わりませんが、GCサイクル時間の短縮により、8個のvCPUの代わりに6個のvCPUを使用することになります。
  • 最良のケースでは、Sidekiqだけで、GitLab.comのメモリを最大137GB節約することができます。

このモデルを拡張してsidekiq_engine を導入することで、ウェブノードにも同様のメリット(ユーザーへの影響が目に見えるためさらに重要)を与えることができます。

成果

これらの変更を導入したことで、多くのメリットを得ることができました。

長所

  • メモリ使用量の大幅削減
  • Sidekiqのアプリケーションロード時間の大幅な短縮
  • GCサイクルの大幅な短縮により、Sidekiqサービスの応答性が大幅に向上
  • アプリケーションの一部のテストが大幅に容易に。例えば、web_engines/ を変更すると、このアプリケーションレイヤーのテストのみを再実行する必要があります。
  • コードベースのモノリシックアーキテクチャを維持しつつ、データベースとアプリケーションモデルを共有。
  • インフラ面での大幅な節約
  • アプリケーションのフットプリントを削減することで、制約のある環境でも快適に実行可能

短所

  • SidekiqのようにGraphQLサブスクリプションを実装するのは難しいです。
  • api_v4 パスは、Sidekiqで使用されているいくつかのサービスで使用することができます(例えば、api_v4_projects_path )。
  • url_helpers パスは、Sidekiqで使用される可能性のあるモデルやサービスで使用されます(例えば、Gitlab::Routing.url_helpers.project_pipelines_pathExpirePipelineCacheWorkerのExpirePipelineCacheServiceで使用されます)。

例GraphQL

草案PoC - GraphQLをWebEngineに移動

  • 上記のMRにあるように、99%の変更はファイルをそのまま移動することです。
  • 実際の作業は、相互依存の修正、仕様、設定などです。web_engine
  • スタックの独立したコンポーネントとしてengines/web_engine/ をテストするために CI を適応させました。

今日、GraphQLのロードには多くの依存関係が必要です:

GitLabの起動時に14480ファイル、メモリ-チーム-2gb-week#9をロード/要求していることもわかりました。1274ファイルがGraphQLに属しています。つまり、1274個のアプリケーションファイルとそれに関連するすべてのGraphQL gemを必要ないとき(Sidekiq)にロードしなければ、大量のメモリを節約できるということです。

GraphQLは特定のコンテキストでのみ実行する必要があります。ロードされるタイミングを制限できれば、アプリケーションのロード時間と必要なメモリを削減し、アプリケーションの効率を効果的に向上させることができます。これは例えば、あらゆる規模のインストールに適用できます。

GraphQLとWebsocketの潜在的な課題は、ある時点でAction Cableサブスクリプションを使用し、SidekiqからクライアントにGraphQL/APIペイロードをプッシュしたいと思うかもしれないことです。この場合、データの受け渡しにRedisを使用する可能性があります。SidekiqがRedis上で情報を公開し、ActionCable Nodeが接続されたクライアントにその情報を渡します。この動作方法は上記のモデルでも可能ですが、GraphQLまたはAPI(HTTPエンドポイントを介して)を使用して、送信されるべきものを計算する必要があります。

別の方法は、ActionCable パススルーを実行する代わりに、送信クエリに基づいてペイロードを生成するノード(WebSocketを処理するもの ActionCable)を常に作る通知システムを使用することです。これは、クライアントの特定の接続を処理するノードにActionCable 適用 ActionCableできます。これは、多くのクライアントが同じリソースを監視している場合、同じペイロードを再計算しなければならないという欠点があります。しかし、生成されるペイロードは監視しているクライアントの権限に依存するかもしれないので、システムのこの動作はセキュリティ上望ましいかもしれません。

例API

草案PoC - Grape API:API のみを WebEngine に移動

  • 上記のMRにあるように、変更の99%はそのままファイルを移動しています。
  • 実際の作業は、相互依存の修正、仕様、イニシャライザ、gem、ルートの設定などです。

Grape::APIは、Webサーバーコンテキストでのみ実行する必要がある別の例です。

Grape APIの潜在的な課題

  • 現在、モデル内部にAPI::APIの依存関係が存在します(例えば、プロジェクトモデル内のAPI::Helpers::Version 依存関係や、geo_retrieve_urlのGeoNodeモデル内のAPI::API依存関係など)。
  • api_v4 パスがヘルパー、プレゼンター、ビューで使用されています (例:PackagesHelperapi_v4_projects_path )

例コントローラの例

草案PoC - コントローラとGrape API:APIをWebEngineに移動

  • 上記のMRにあるように、変更の99%はそのままファイルを移動しています。
  • 実際の作業は、相互依存の修正、仕様、イニシャライザ、gem、ルートの設定などです。

Controller、Serializers、一部のPresenters、Grape:Entitiesの一部も、Webサーバーのコンテキストで実行する必要がある良い例です。

コントローラの移動に伴う潜在的な課題

  • web_engine がロードされた場合に備えて、engines/web_engine/config/routesengines/web_engine/ee/config/routes をサポートするようにGitlab::Patch::DrawRoute を拡張する必要がありました。これが解決策です。
  • Gitlab::Routing.url_helpers パスは、Sidekiqで使用される可能性のあるモデルやサービスで使用されます(例えば、Gitlab::Routing.url_helpers.project_pipelines_pathExpirePipelineCacheWorkerのExpirePipelineCacheServiceで使用されます)。

パックワーク

note
Packwerkは現在バグフィックスのみ受け付けており、積極的な開発は行っておりません。詳細はこちら

今後の影響

アプリケーションレイヤーとこの提案は現在web_engine。同じパターンに従えば、GitLab Railsの分離、メモリ使用量の削減、保守性の向上を将来にわたって維持するための、サポート専用の追加エンジンを簡単に導入することができます。

これは、追加Packageサービスのサポートのような、コアコードベースの一部である必要がない機能のためのすべての新しいインターフェイスを導入するためのフレームワークとなるでしょう。GitLabの単一のコードベースとモノリシックアーキテクチャを維持しながら、将来的にアプリケーションをよりよくスケールできるようにします。

現在のところ、3つのアプリケーションレイヤーを定義するのが妥当だと思われます:

  • gitlab-coreコア機能:DB構造、モデル、サービス、共通ライブラリ。これはデータアクセスレイヤーをモデル化したもので、最初はGitLabを動かすのに必要な全てのサービスをモデル化したものです。これは将来、より小さな側面に分割される可能性があります。
  • gitlab-web: Webサーバーのコンテキストで実行するために必要なController/API/GraphQL/ActionCable機能(gitlab-coreに依存します。)
  • gitlab-sidekiqSidekiq Workersを実行するために必要なバックグラウンドジョブ機能 (gitlab-coreに依存)

このモデルは、共有コアとサテライトとして今日最もよく説明されています。共有コアはデータアクセスレイヤーを定義し、サテライトはこのデータを提示し処理する方法を定義します。サテライトはCoreとしか会話できません。API、GraphQL、またはRedis(Sidekiqジョブのスケジューリングのため)の形で明確に定義されたインターフェースを使用しない限り、他のサテライトを直接ロードしたり、会話したりすることはできません。

engines の数を制限することは合理的です。最初の提案では、エンジンが爆発的に増加しないように、最大5つのエンジンの作成を許可しています。

イシューとマージリクエスト