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. The development, release, and timing of any products, features, or functionality may be subject to change or delay and remain at the sole discretion of GitLab Inc.
Status Authors Coach DRIs Owning Stage Created
rejected -

이 제안은 라우팅 서비스 제안에 의해 대체되었습니다.

Proposal: Stateless Router using Requests Buffering

gitlab_users, gitlab_routes, gitlab_admin 관련 테이블을 분해하여 모든 셀에서 공유할 수 있도록 만들어 사용자를 인증하고 정확한 셀로 요청을 라우팅할 수 있게 합니다. 셀은 자신이 소유하지 않은 리소스에 대한 요청을 받을 수 있지만, 정확한 셀로 다시 리디렉션하는 방법을 알고 있습니다.

라우터는 상태를 유지하지 않으며 routes 데이터베이스에서 읽지 않으므로 모든 데이터베이스와의 상호 작용은 여전히 Rails 모노리스에서 발생합니다. 이 아키텍처는 지역 간 저 트래픽 데이터베이스를 복제하여 지역 간에 지원함으로써 지원합니다.

사용자는 셀의 개념에 직접 노출되지 않으며 대신 선택한 조직에 따라 다른 데이터를 볼 수 있습니다. 조직은 응용 프로그램에서 격리를 강제하도록 도입되어 요청이 어떤 셀로 라우팅될지 결정하도록 허용하며, 조직은 단일 셀에만 속할 수 있습니다.

Differences

이 제안과 라우트 학습을 통한 무상태 라우터와의 주요 차이점은 이 제안이 항상 요청을 셀 중 하나로 보내는 것입니다. 요청이 처리되지 못하는 경우, 관련 헤더와 함께 요청이 다시 전송됩니다. 이에 따라 요청이 버퍼링되어야 합니다. 라우터는 요청 디코딩을 URI 또는 Rails에서 요청 본문을 통해 처리할 수 있습니다. 따라서 각 요청은 한 번 이상 보내질 수 있고 결과적으로 여러 번 처리될 수 있습니다.

라우트 학습을 통한 무상태 라우터 제안은 항상 라우트 가능 정보가 URI에 인코딩되어 있어야 하며, 라우터는 사전 확인 요청을 보냅니다.

다이어그램 요약

이 다이어그램은 사용자 요청이 DNS를 통해 가장 가까운 라우터로 라우팅되고 라우터가 요청을 보낼 셀을 선택하는 방식을 보여줍니다.

graph TD; user((사용자)); dns[DNS]; router_us(라우터); router_eu(라우터); cell_us0{셀 US0}; cell_us1{셀 US1}; cell_eu0{셀 EU0}; cell_eu1{셀 EU1}; user-->dns; dns-->router_us; dns-->router_eu; subgraph 유럽 router_eu-->cell_eu0; router_eu-->cell_eu1; end subgraph 미국 router_us-->cell_us0; router_us-->cell_us1; end
더 많은 세부 정보 이 다이어그램은 라우터가 실제로 모든 셀로 요청을 보낼 수 있는 것을 보여줍니다. 사용자는 지리적으로 가장 가까운 라우터를 받게 됩니다. ```mermaid graph TD; user((사용자)); dns[DNS]; router_us(라우터); router_eu(라우터); cell_us0{셀 US0}; cell_us1{셀 US1}; cell_eu0{셀 EU0}; cell_eu1{셀 EU1}; user-->dns; dns-->router_us; dns-->router_eu; subgraph 유럽 router_eu-->cell_eu0; router_eu-->cell_eu1; end subgraph 미국 router_us-->cell_us0; router_us-->cell_us1; end router_eu-.->cell_us0; router_eu-.->cell_us1; router_us-.->cell_eu0; router_us-.->cell_eu1; ```
더 많은 상세 정보 이 다이어그램은 데이터베이스를 보여줍니다. `gitlab_users` 및 `gitlab_routes`는 미국 지역에서만 존재하지만 다른 지역으로 복제됩니다. 복제는 다이어그램을 읽기 어렵게 만드므로 화살표가 없습니다. ```mermaid graph TD; user((사용자)); dns[DNS]; router_us(라우터); router_eu(라우터); cell_us0{셀 US0}; cell_us1{셀 US1}; cell_eu0{셀 EU0}; cell_eu1{셀 EU1}; db_gitlab_users[(gitlab_users Primary)]; db_gitlab_routes[(gitlab_routes Primary)]; db_gitlab_users_replica[(gitlab_users Replica)]; db_gitlab_routes_replica[(gitlab_routes Replica)]; db_cell_us0[(gitlab_main/gitlab_ci Cell US0)]; db_cell_us1[(gitlab_main/gitlab_ci Cell US1)]; db_cell_eu0[(gitlab_main/gitlab_ci Cell EU0)]; db_cell_eu1[(gitlab_main/gitlab_ci Cell EU1)]; user-->dns; dns-->router_us; dns-->router_eu; subgraph 유럽 router_eu-->cell_eu0; router_eu-->cell_eu1; cell_eu0-->db_cell_eu0; cell_eu0-->db_gitlab_users_replica; cell_eu0-->db_gitlab_routes_replica; cell_eu1-->db_gitlab_users_replica; cell_eu1-->db_gitlab_routes_replica; cell_eu1-->db_cell_eu1; end subgraph 미국 router_us-->cell_us0; router_us-->cell_us1; cell_us0-->db_cell_us0; cell_us0-->db_gitlab_users; cell_us0-->db_gitlab_routes; cell_us1-->db_gitlab_users; cell_us1-->db_gitlab_routes; cell_us1-->db_cell_us1; end router_eu-.->cell_us0; router_eu-.->cell_us1; router_us-.->cell_eu0; router_us-.->cell_eu1; ```

변경 요약

  1. 사용자 데이터(프로필 설정, 인증 자격 증명, 개인 액세스 토큰 포함)와 관련된 테이블은 gitlab_users 스키마로 분해됩니다.
  2. routes 테이블은 gitlab_routes 스키마로 분해됩니다.
  3. application_settings (그리고 아마도 일부 인스턴스 수준 테이블)은 gitlab_admin 스키마로 분해됩니다.
  4. routes 테이블에 routes.cell_id 열이 추가됩니다.
  5. 요청을 셀로 라우팅할 새로운 라우터 서비스가 존재합니다.
  6. GitLab에 조직이라는 새로운 컨셉이 도입되며 사용자는 “기본 조직”을 선택할 수 있으며 이것은 사용자 수준 설정이 됩니다. 기본 조직은 사용자를 /dashboard와 같은 모호한 경로에서 /organizations/my-organization/-/dashboard와 같은 조직 범위의 경로로 리디렉션하는 데 사용됩니다. 기본 사용자는 Cell US0의 글로벌 리소스를 계속 사용할 수 있습니다. 모든 기존 네임스페이스는 초기에 이 공용 조직으로 이동합니다.
  7. 셀이 routes.cell_id에 대한 요청을 소유하지 않는 경우, 해당 요청은 302X-Gitlab-Cell-Redirect 헤더로 반환되어 라우터가 올바른 셀로 요청을 보낼 수 있습니다. 올바른 셀은 이 요청이 어떻게 캐시되어 세포를 기억하는지에 대한 정보를 포함하는 X-Gitlab-Cell-Cache 헤더를 설정할 수 있습니다. 예를 들어, 요청이 /gitlab-org/gitlab인 경우 헤더에 /gitlab-org/* => Cell US0 (예: /gitlab-org/로 시작하는 모든 요청은 항상 Cell US0로 라우팅될 수 있음)를 인코딩합니다.
  8. 캐시에서 셀이 요청을 어느 셀로 보낼지 모를 경우, 해당 지역 내의 임의의 셀을 선택합니다.
  9. gitlab_usersgitlab_routes에 대한 쓰기는 US 지역의 기본 PostgreSQL 서버로 전송되지만 동일 지역의 복제본에서 읽을 수 있습니다. 이는 기존 GitLab에 비해 적은 빈도로 예상되므로 이러한 쓰기에는 지연이 추가됩니다. ```

첫 번째 이터레이션에서 기본 조직에 대한 자세한 설명

모든 사용자는 사용자 설정에서 제어할 수 있는 users.default_organization이라는 새 열을 받게 될 것입니다. GitLab.com Public 조직이라는 개념을 소개할 것입니다. 기존 사용자를 위해이 조직을 기본 조직으로 설정할 것입니다. 이 조직은 사용자가 Cell US0의 모든 네임스페이스에서 데이터를 볼 수 있도록 할 것입니다(예: 원래의 GitLab.com 인스턴스). 이 동작은 기존 사용자에게는 보이지 않을 수 있어도 (/dashboard와 같은 전역 페이지를 볼 때 어떤 조직에 지정되었는지 심지어 알리지 않겠다는 것입니다).

GitLab.com Public 이외의 기본 조직을 갖는 새로운 사용자들은 구별된 사용자 경험을 받게 될 것이며, 그들이로드하는 모든 페이지가 언제나 하나의 조직에만 지정된 상태임을 완전히 인식하게 될 것입니다. 이러한 사용자들은 /dashboard와 같은 전역 페이지를 로드할 수 없으며 항상 /organizations/<DEFAULT_ORGANIZATION>/-/dashboard로 리디렉션될 것입니다. 이는 이전 API 및 해당 사용자가 조직에만 지정된 API를 사용할 수 있다는 경우 일 수 있습니다.

관리 영역 설정의 자세한 설명

관리 및 동기화가 괴로울 것으로 생각되므로 모든 관리 영역 설정을 gitlab_admin 스키마에서 분해 및 공유할 것으로 믿습니다. 이것은 매우 적은 쓰기 트래픽을 받기 때문에 안전해야 합니다(다른 공유 스키마와 유사). 다른 셀이 서로 다른 설정이 필요한 경우(예: Elasticsearch URL) 관련 application_settings 행에 동적으로 설정할 수 있도록 템플릿 형식을 사용하거나, 이렇게 하기 어렵다면, per_cell_application_settings라는 새 테이블을 도입하고 각 셀당 1행씩 추가하여 셀당 다른 설정을 할 수 있도록 할 것입니다. 그것은 여전히 gitlab_admin 스키마의 일부이며 중앙에서 관리하고 모든 셀의 설정을 동기화하는 것을 단순화시킬 것입니다.

장점

  1. 라우터는 상태를 유지하지 않고 여러 지역에 존재할 수 있습니다. 우리는 Anycast DNS를 사용하여 사용자에게 가장 가까운 지역으로 해결합니다.
  2. 셀은 잘못된 셀에서 네임스페이스에 대한 요청을 받을 수 있지만 사용자는 여전히 올바른 응답을 받고 라우터에서 캐싱되어 다음 요청이 올바른 셀로 전송되도록 보장하므로 다음 요청은 올바른 셀로 이동하게 됩니다.
  3. 대부분의 코드는 여전히 gitlab 레일 코드베이스에 살고 있습니다. 라우터는 실제로 GitLab URL이 어떻게 구성되는지 이해할 필요가 없습니다.
  4. gitlab_users, gitlab_routes, gitlab_admin을 읽고 쓰는 책임이 여전히 레일에 있으므로 도메인 모델을 격리하고 새로운 인터페이스를 구축해야 하는 서비스와 비교하여 레일 애플리케이션에 필요한 변경이 최소화될 것입니다.
  5. 별도의 라우팅 서비스와 비교했을 때 레일 애플리케이션에 더 복잡한 규칙을 인코딩하고 일부 기존 API 엔드포인트에도 작동할 수 있을 것입니다.
  6. 모든 새로운 인프라(라우터만)는 선택 사항이며, 단일 셀 Self-Managed형 설치는 심지어 라우터를 실행할 필요가 없으며 다른 새로운 서비스가 없습니다.

단점

  1. gitlab_users, gitlab_routes, gitlab_admin 데이터베이스는 여러 지역에 복제되어야 하며 쓰기가 여러 지역에 전파되어야 할 수 있습니다. 이 관련 테이블의 쓰기 TPS에 대한 분석을 수행하여 이것이 실행 가능한지 여부를 결정해야 합니다.
  2. 많은 다른 셀에서 데이터베이스에 대한 공유 액세스는 모든 셀이 포스트그레 스키마 수준에서 결합되어 있음을 의미하며 이는 데이터베이스 스키마의 변경을 모든 셀의 배포와 조화롭게 진행해야한다는 것을 의미합니다. 이는 API를 제어하는 공유 서비스로 된 아키텍처와 비교하여 셀이 밀접하게 유사한 버전으로 유지되도록 한정한다.
  3. 대부분의 데이터가 올바른 지역에 저장되어 있지만 다른 지역에서 프록시로 전달된 요청이 있을 수 있으며 이는 일부 유형의 규정에 문제가 될 수 있습니다.
  4. gitlab_usersgitlab_routes 데이터베이스의 데이터는 모든 지역에 복제되어야 하며 이는 일부 유형의 규정에 문제가 될 수 있습니다.
  5. 라우터 캐시가 매우 크게 필요할 수 있습니다(예: 장기간에 걸쳐 많은 다양한 URL) - 이와 같은 경우 사용자 쿠키에서 2단계 캐싱을 구현하여 자주 액세스하는 페이지가 항상 처음에 올바른 셀로 이동하도록 할 필요가 있을 수 있습니다.
  6. 여러 셀에서 gitlab_usersgitlab_routes에 대한 공유된 데이터베이스 액세스가 공유된 서비스를 추출하는 것과 비교하여 촌스러운 아키텍처 결정입니다.
  7. 매우 가능성이 높은 점은 GraphQL URL의 캐시 가능한 요소를 찾지 못할 수 있으며 기존의 GraphQL 엔드포인트는 id에 극도로 의존하기 때문에 셀은 데이터가 어떤 셀에 있는지 모를 수 있습니다. 따라서 우리는 아마도 경로에 조직 컨텍스트를 포함시키도록 GraphQL 호출을 업데이트해야할 것입니다(예: /api/organizations/<organization>/graphql).
  8. 이 아키텍처는 구현된 엔드포인트가 특정 셀에서 즉시 접근 가능한 데이터에만 액세스할 수 있지만 많은 셀에서 정보를 집계할 가능성은 낮을 것입니다.
  9. 알 수 없는 경로 모두가 최신 배포로 전송되며, 해당 요청을 제공할 수 있는 최신 셀로 가정됩니다. 이는 새롭게 추가된 엔드포인트가 최신 셀에서만 해독 가능하도록 되기 때문에 필요합니다. 나중에 이 셀이 주어진 요청을 제공할 수 있는 올바른 곳으로 리디렉트될 수 있습니다. 요청 처리가 무거울 수 있기 때문에 일부 셀은 이를 통해 상당한 양의 트래픽을 수신할 수 있습니다.

데이터베이스 구성 예

공유 gitlab_users, gitlab_routes, gitlab_admin 데이터베이스를 처리하면서 동시에 전용 gitlab_maingitlab_ci 데이터베이스를 사용하는 것은 이미 config/database.yml을 사용하는 방식으로 처리되어야 합니다. 또한, 우리는 이미 gitlab_usersgitlab_routes를 위해 단일 US 주 서버와 함께 전용 EU 복제본을 처리할 수 있어야 합니다. 위에 설명된 Cell 아키텍처에 대한 데이터베이스 구성의 일부분에 대한 일부 스니펫은 다음과 같습니다.

Cell US0 ```yaml # config/database.yml production: main: host: postgres-main.cell-us0.primary.consul load_balancing: discovery: postgres-main.cell-us0.replicas.consul ci: host: postgres-ci.cell-us0.primary.consul load_balancing: discovery: postgres-ci.cell-us0.replicas.consul users: host: postgres-users-primary.consul load_balancing: discovery: postgres-users-replicas.us.consul routes: host: postgres-routes-primary.consul load_balancing: discovery: postgres-routes-replicas.us.consul admin: host: postgres-admin-primary.consul load_balancing: discovery: postgres-admin-replicas.us.consul ```
Cell EU0 ```yaml # config/database.yml production: main: host: postgres-main.cell-eu0.primary.consul load_balancing: discovery: postgres-main.cell-eu0.replicas.consul ci: host: postgres-ci.cell-eu0.primary.consul load_balancing: discovery: postgres-ci.cell-eu0.replicas.consul users: host: postgres-users-primary.consul load_balancing: discovery: postgres-users-replicas.eu.consul routes: host: postgres-routes-primary.consul load_balancing: discovery: postgres-routes-replicas.eu.consul admin: host: postgres-admin-primary.consul load_balancing: discovery: postgres-admin-replicas.eu.consul ```

요청 흐름

  1. gitlab-org는 최상위 네임스페이스이며 Cell US0GitLab.com Public 조직에 존재합니다.
  2. my-company는 최상위 네임스페이스이며 Cell EU0my-organization 조직에 존재합니다.

my-organization의 구성원인 유료 사용자의 경험

이러한 사용자는 기본적으로 /my-organization으로 설정된 기관을 가지고 있으며 이 외의 글로벌 경로를 불러올 수 없을 것입니다. 다른 프로젝트/네임스페이스를 불러올 수는 있지만 페이지 상단의 MR/Todo/이슈 카운트는 처음에는 올바르게 설정되지 않을 것입니다. 사용자는 이 제한을 인지하고 있을 것입니다.

로그인한 채로 /my-company/my-project로 이동

  1. 유저는 유럽에 있으므로 DNS가 유럽의 라우터로 해석됩니다.
  2. 그들은 라우터 캐시 없이 /my-company/my-project를 요청하므로 라우터는 무작위로 Cell EU1을 선택합니다.
  3. Cell EU1/my-company를 보유하고 있지 않지만, Cell EU0에 위치한다는 사실을 알고 있으므로 라우터를 Cell EU0로 리디렉션합니다.
  4. Cell EU0은 올바른 응답을 반환하고 동시에 라우터에 대한 캐시 헤더를 설정합니다. /my-company/* => Cell EU0
  5. 이제 라우터는 /my-company/*와 일치하는 모든 요청 경로를 Cell EU0으로 이동해야 한다고 캐시하고 기억합니다.
sequenceDiagram participant user as User participant router_eu as Router EU participant cell_eu0 as Cell EU0 participant cell_eu1 as Cell EU1 user->>router_eu: GET /my-company/my-project router_eu->>cell_eu1: GET /my-company/my-project cell_eu1->>router_eu: 302 /my-company/my-project X-Gitlab-Cell-Redirect={cell:Cell EU0} router_eu->>cell_eu0: GET /my-company/my-project cell_eu0->>user: <h1>My Project... X-Gitlab-Cell-Cache={path_prefix:/my-company/}

로그인하지 않은 채로 /my-company/my-project로 이동

  1. 유저는 유럽에 있으므로 DNS가 유럽의 라우터로 해석됩니다.
  2. 라우터는 아직 /my-company/*을 캐시하지 않았으므로 무작위로 Cell EU1을 선택합니다.
  3. Cell EU1은 로그인 플로우를 통해 유저를 리디렉션합니다.
  4. 여전히 라우터 캐시 없이 /my-company/my-project를 요청하므로 라우터는 무작위의 Cell EU1을 선택합니다.
  5. Cell EU1/my-company를 보유하고 있지 않지만, Cell EU0에 위치한다는 사실을 알고 있으므로 라우터를 Cell EU0로 리디렉션합니다.
  6. Cell EU0은 올바른 응답을 반환하고 동시에 라우터에 대한 캐시 헤더를 설정합니다. /my-company/* => Cell EU0
  7. 이제 라우터는 /my-company/*와 일치하는 모든 요청 경로를 Cell EU0으로 이동해야 한다고 캐시하고 기억합니다.
sequenceDiagram participant user as User participant router_eu as Router EU participant cell_eu0 as Cell EU0 participant cell_eu1 as Cell EU1 user->>router_eu: GET /my-company/my-project router_eu->>cell_eu1: GET /my-company/my-project cell_eu1->>user: 302 /users/sign_in?redirect=/my-company/my-project user->>router_eu: GET /users/sign_in?redirect=/my-company/my-project router_eu->>cell_eu1: GET /users/sign_in?redirect=/my-company/my-project cell_eu1->>user: <h1>Sign in... user->>router_eu: POST /users/sign_in?redirect=/my-company/my-project router_eu->>cell_eu1: POST /users/sign_in?redirect=/my-company/my-project cell_eu1->>user: 302 /my-company/my-project user->>router_eu: GET /my-company/my-project router_eu->>cell_eu1: GET /my-company/my-project cell_eu1->>router_eu: 302 /my-company/my-project X-Gitlab-Cell-Redirect={cell:Cell EU0} router_eu->>cell_eu0: GET /my-company/my-project cell_eu0->>user: <h1>My Project... X-Gitlab-Cell-Cache={path_prefix:/my-company/}

마지막 단계 이후 /my-company/my-other-project로 이동

  1. 유저는 유럽에 있으므로 DNS가 유럽의 라우터로 해석됩니다.
  2. 라우터 캐시에 이제 /my-company/* => Cell EU0가 있으므로 라우터는 Cell EU0를 선택합니다.
  3. Cell EU0은 올바른 응답을 반환하고 캐시 헤더를 다시 설정합니다.
sequenceDiagram participant user as User participant router_eu as Router EU participant cell_eu0 as Cell EU0 participant cell_eu1 as Cell EU1 user->>router_eu: GET /my-company/my-project router_eu->>cell_eu0: GET /my-company/my-project cell_eu0->>user: <h1>My Project... X-Gitlab-Cell-Cache={path_prefix:/my-company/}

마지막 단계 이후 /gitlab-org/gitlab로 이동

  1. 유저는 유럽에 있으므로 DNS가 유럽의 라우터로 해석됩니다.
  2. 이 URL에 대한 캐시된 값이 없으므로 라우터는 무작위로 Cell EU0을 선택합니다.
  3. Cell EU0은 라우터를 Cell US0로 리디렉션합니다.
  4. Cell US0은 올바른 응답을 반환하고 캐시 헤더를 다시 설정합니다.
sequenceDiagram participant user as User participant router_eu as Router EU participant cell_eu0 as Cell EU0 participant cell_us0 as Cell US0 user->>router_eu: GET /gitlab-org/gitlab router_eu->>cell_eu0: GET /gitlab-org/gitlab cell_eu0->>router_eu: 302 /gitlab-org/gitlab X-Gitlab-Cell-Redirect={cell:Cell US0} router_eu->>cell_us0: GET /gitlab-org/gitlab cell_us0->>user: <h1>GitLab.org... X-Gitlab-Cell-Cache={path_prefix:/gitlab-org/}

이 경우 사용자가 “기본 기관”에 속해 있지 않기 때문에 그들의 TODO 카운터에 일반적인 할 일이 포함되지 않을 것입니다. 이를 UI 어딘가에 강조하는 것을 선택할 수 있습니다. 향후 반복에서는 그들의 기본 기관으로부터 이를 가져올 수 있을 것입니다.

/로 이동

  1. 유저는 유럽에 있으므로 DNS가 유럽의 라우터로 해석됩니다.
  2. / 경로에 대한 라우터 캐시가 없습니다 (구체적으로 Rails는 이 경로를 캐시하도록 요청하지 않습니다).
  3. 라우터는 무작위로 Cell EU0을 선택합니다.
  4. Rails 애플리케이션은 유저의 기본 기관이 /my-organization임을 알고 있기 때문에 유저를 /organizations/my-organization/-/dashboard로 리디렉션합니다.
  5. 라우터는 /organizations/my-organization/*에 대한 캐시된 값이 존재하므로 요청을 POD EU0으로 보냅니다.
  6. Cell EU0은 오늘날의 대시보드 전망과 동일한 새로운 페이지 /organizations/my-organization/-/dashboard를 제공합니다. 역시 이 페이지의 데이터는 UI에서 명확히 표시된 기관에 속한 데이터만 포함한다는 메시지가 (선택적으로) 제시됩니다. 또한 이것이 옳지 않은 경우 기본 기관을 변경할 수 있다는 메시지도 표시됩니다.
sequenceDiagram participant user as User participant router_eu as Router EU participant cell_eu0 as Cell EU0 user->>router_eu: GET / router_eu->>cell_eu0: GET / cell_eu0->>user: 302 /organizations/my-organization/-/dashboard user->>router: GET /organizations/my-organization/-/dashboard router->>cell_eu0: GET /organizations/my-organization/-/dashboard cell_eu0->>user: <h1>My Company Dashboard... X-Gitlab-Cell-Cache={path_prefix:/organizations/my-organization/}

/대시보드로 이동

위와 같이, 레일 응용프로그램은 이미 /를 대시보드 페이지로 리다이렉트하므로 사용자는 /organizations/my-organization/-/dashboard에 도착하게 됩니다.

로그인한 채 /not-my-company/not-my-project로 이동 (그러나 해당 프로젝트/그룹에 액세스할 수 없음)

  1. 유럽에 있는 사용자이므로 DNS는 유럽 라우터로 해석됨
  2. 라우터는 /not-my-companyCell US1에 위치한다는 것을 알고 있으므로 해당 요청을 해당 셀로 보냄
  3. 사용자는 액세스 권한이 없으므로 Cell US1에서 404를 반환함
sequenceDiagram participant user as 사용자 participant router_eu as 라우터 EU participant cell_us1 as 셀 US1 user->>router_eu: GET /not-my-company/not-my-project router_eu->>cell_us1: GET /not-my-company/not-my-project cell_us1->>user: 404

새로운 최상위 네임스페이스 생성

사용자는 네임스페이스를 어떤 조직에 속할지 선택하도록 요청됩니다. my-organization을 선택하면 다른 모든 네임스페이스와 동일한 셀에 위치하게 됩니다. 아무것도 선택하지 않으면 기본적으로 GitLab.com Public으로 설정되며, 사용자에게 현재 조직의 데이터와 격리되어 동일한 페이지에서 두 조직의 데이터를 볼 수 없음을 명확히합니다.

/gitlab-org의 일부인 GitLab 팀 회원의 경험

해당 사용자는 레거시 사용자로 간주되며, 기본 조직이 GitLab.com Public으로 설정됩니다. 이 조직은 실제로 존재하지 않지만 레일 응용프로그램은 이 조직을 해석하여 해당 사용자가 /dashboard와 같은 레거시 글로벌 기능을 사용할 수 있는 권한이 있다는 것을 인지합니다. 또한 레일 백앤드는 /dashboard와 같은 모호한 경로를 렌더링할 기본 셀을 알고 있습니다. 마지막으로 사용자가 /my-organization과 같은 다른 셀로 이동하는 것을 허용하지만, 이때 사용자는 MRs/이슈/할 일과 같은 데이터가 누락될 수 있다는 메시지가 표시됩니다.

로그인하지 않은 채 /gitlab-org/gitlab로 이동

  1. 사용자는 미국에 있으므로 DNS는 미국 라우터로 해석됨
  2. 라우터는 /gitlab-orgCell US0에 위치한다는 것을 알고 있으므로 해당 셀로 요청을 보냄
  3. Cell US0은 응답 제공
sequenceDiagram participant user as 사용자 participant router_us as 라우터 US participant cell_us0 as 셀 US0 user->>router_us: GET /gitlab-org/gitlab router_us->>cell_us0: GET /gitlab-org/gitlab cell_us0->>user: <h1>GitLab.org... X-Gitlab-Cell-Cache={path_prefix:/gitlab-org/}

/로 이동

  1. 사용자는 미국에 있으므로 DNS는 미국 라우터로 해석됨
  2. 라우터는 / 경로에 대한 캐시가 없음 (rails가 이 경로를 캐시하도록 지시하지 않음)
  3. 라우터는 무작위로 Cell US1을 선택함
  4. 레일 응용프로그램은 사용자의 기본 조직이 GitLab.com Public임을 알고 있으므로 사용자를 /dashboards로 리디렉션함 (레거시 사용자만 /dashboard를 볼 수 있음)
  5. 라우터는 /dashboard 경로에 대한 캐시가 없음 (rails가 이 경로를 캐시하도록 지시하지 않음)
  6. 라우터는 무작위로 Cell US1을 선택함
  7. 레일 응용프로그램은 사용자의 기본 조직이 GitLab.com Public임을 알고 있으므로 사용자가 /dashboards를로드할 수 있음 (레거시 사용자만 /dashboard를 볼 수 있음) 및 사용자를 레거시 셀인 Cell US0으로 리디렉션함
  8. Cell US0은 현재와 동일한 글로벌 뷰 대시보드 페이지 /dashboard을 제공함
sequenceDiagram participant user as 사용자 participant router_us as 라우터 US participant cell_us0 as 셀 US0 participant cell_us1 as 셀 US1 user->>router_us: GET / router_us->>cell_us1: GET / cell_us1->>user: 302 /dashboard user->>router_us: GET /dashboard router_us->>cell_us1: GET /dashboard cell_us1->>router_us: 302 /dashboard X-Gitlab-Cell-Redirect={cell:Cell US0} router_us->>cell_us0: GET /dashboard cell_us0->>user: <h1>대시보드...

로그인한 채 /my-company/my-other-project로 이동 (그러나 해당 프로젝트에 액세스할 수 없음)

404를 받게 됩니다.

인증되지 않은 사용자의 경험

글로벌 경로인 /dashboard와 같은 경로는 로그인 페이지로 이동하며, 인증되지 않은 사용자는 기본 조직을 선택할 수 없기 때문에 이동합니다.

새로운 고객 가입

이들에게 기존 조직에 속해 있는지 또는 새로운 조직을 만들고 싶은지 물어봅니다. 둘 중 아무것도 선택하지 않으면 기본적으로 GitLab.com Public 조직에 가입하게 됩니다.

조직이 셀에서 다른 셀로 이동

TODO

URL에 네임스페이스가 포함되지 않은 GraphQL/API 요청

TODO

검색 창의 자동 완성 제안 기능(최근 이슈/MR 기억)

TODO

글로벌 검색

TODO

관리자

/admin 페이지로 이동

  1. 라우터가 무작위 셀 Cell US0을 선택함
  2. Cell US0은 사용자를 /admin/cells/cellus0로 리디렉션함
  3. Cell US0은 관리자 영역 페이지를 렌더링하고 /admin/cellss/cellus0/* => Cell US0 캐시 헤더를 반환함. 관리자 영역 설정은 발산을 피하기 위해 모든 셀에 대해 공유되지만 URL 및 UI에서 특정 셀이 페이지를 제공함이 명시됩니다. 이 페이지에서 동적 데이터가 생성되고 운영자가 특정 셀을 볼 수 있어야 하므로 해당 정보가 중요합니다.

더 해결해야 할 기술적 문제

모든 셀 사이에서 사용자 세션 복제

현재 사용자 세션은 Redis에 저장되지만 각 셀은 고유한 Redis 인스턴스를 가지게 됩니다. 우리는 이미 세션을 위해 전용 Redis 인스턴스를 사용하고 있으므로 gitlab_users PostgreSQL 데이터베이스처럼 모든 셀과 공유할 수 있습니다. 그러나 중요한 고려 사항은 대부분의 경우 동일한 지역에서 세션을 검색하려고 하기 때문에 지연 시간입니다.

대안적으로 사용자 세션을 모든 세션 데이터를 인코드하는 JWT 페이로드로 이동시킬 수 있지만, 이에는 단점이 있습니다. 예를 들어, 세션의 유효 기간이 만료될 때 해당 사용자의 비밀번호가 변경되거나 다른 이유로 인해 세션을 만료시키기가 어렵습니다.

셀 간 데이터 마이그레이션 방법

셀 간 데이터 마이그레이션에는 모든 데이터 리포지터리를 고려해야 합니다:

  1. PostgreSQL
  2. 공유 상태의 Redis
  3. Gitaly
  4. Elasticsearch

타이밍 공격을 통한 비공개 그룹의 존재 유출 가능성

현재 이러한 타이밍 공격은 권한 확인 방식이기 때문에 이론적으로 이미 가능합니다. 그러나 타이밍의 차이가 식별할 수 있는 정도로 작을 것으로 예상됩니다.

이러한 위험을 완화하는 기술적 기법 중 하나는 라우터가 셀에서 404를 반환하는 요청에 임의의 지연을 추가하는 것일 수 있습니다.

모든 셀 간에 러너를 공유해야 할까요?

우리에게는 2가지 옵션이 있으며, 어떤 것이 더 쉬운지 결정해야 합니다:

  1. 러너 등록 및 대기열 테이블을 분해하고 모든 셀 간에 공유합니다. 이는 확장성에 영향을 미칠 수 있으며, 이는 그룹/프로젝트 러너를 포함하는지 여부를 고려해야 할 것입니다. 이는 확장성에 관한 우려가 있으므로 이러한 높은 트래픽 테이블이 공유되어야 할 수도 있습니다.
  2. 러너는 셀 당 등록되며, 아마도 각 셀마다 별도의 러너 풀이 있거나 여러 셀에 동일한 러너를 등록하는 것이 큐잉에 영향을 미칠 수 있습니다.

모든 셀 간에 충돌하지 않아야 하는 유일한 ID를 어떻게 보장할까요?

이 프로젝트는 적어도 네임스페이스와 프로젝트가 중복되지 않는 고유한 ID를 가지고 있다고 가정하며, 많은 요청들은 ID에 따라 경로 지정되어야 합니다. 해당 테이블이 다른 데이터베이스에 걸쳐 있기 때문에 고유한 ID를 보장하기 위해서는 새로운 해결책이 필요할 것입니다. 아마도 GraphQL 및 다른 API가 라우팅되는 방법과 다른 설계 목표에 따라서 다른 테이블에서도 고유한 ID가 필요할 것이며, 모든 테이블의 기본 키를 고유하게 유지하려는 결정을 내릴 수도 있습니다.