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 -

이 제안은 routing service proposal에 의해 대체되었습니다.

이 문서는 진행 중인 작업이며 Cells 설계의 초기 단계를 나타냅니다. 중요한 측면들이 문서화되지 않았지만, 향후 추가할 예정입니다. 이것은 Cells를 위한 하나의 아키텍처이며, 우리는 구현할 접근 방법을 결정하기 전에 대안과 대조할 것을 의도하고 있습니다. 이 문서는 이 접근 방식을 선택하지 않기로 결정해도 그 이유를 문서화하고자 유지될 것입니다.

제안: Routes Learning을 사용하는 상태 없는 라우터

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

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

사용자는 Cells의 개념에 직접 노출되지 않고 대신 선택한 조직에 따라 다른 데이터를 볼 수 있습니다. 조직은 응용 프로그램에서 격리를 강화하고 어떤 요청이 어떤 Cell로 라우팅될지 결정할 수 있도록 하기 위해 새로운 개체로 소개됩니다.

차이점

이 제안과 요청 버퍼링을 사용하는 제안과의 주된 차이점은 이 제안이 사전 API 요청 (/api/v4/internal/cells/learn)을 사용하여 요청 본문을 올바른 Cell로 리디렉션하는 데 사용합니다. 이는 각 요청이 한 번만 처리되도록 보내지만, URI가 어떤 Cell로 방향을 전달해야 하는지를 디코딩하는 데 사용됨을 의미합니다.

다이어그램에서 요약

이는 사용자 요청이 DNS를 통해 가장 가까운 라우터에 라우팅되고 라우터가 요청을 보낼 Cell을 선택하는 방법을 보여줍니다.

graph TD; user((사용자)); dns[DNS]; router_us(라우터); router_eu(라우터); cell_us0{Cell 미국0}; cell_us1{Cell 미국1}; cell_eu0{Cell 유럽0}; cell_eu1{Cell 유럽1}; 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

더 자세한 내용

이는 라우터가 실제로 어떤 Cell에 요청을 보낼 수 있는지를 보여줍니다. 사용자는 지리적으로 가장 가까운 라우터를 받게 될 것입니다.

graph TD; user((사용자)); dns[DNS]; router_us(라우터); router_eu(라우터); cell_us0{Cell 미국0}; cell_us1{Cell 미국1}; cell_eu0{Cell 유럽0}; cell_eu1{Cell 유럽1}; 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_usersgitlab_routes는 미국 지역에만 존재하지만 다른 지역으로 복제됩니다. 복제는 다이어그램을 읽는 데 너무 어려우므로 화살표가 없습니다.

graph TD; user((사용자)); dns[DNS]; router_us(라우터); router_eu(라우터); cell_us0{Cell 미국0}; cell_us1{Cell 미국1}; cell_eu0{Cell 유럽0}; cell_eu1{Cell 유럽1}; 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 미국0)]; db_cell_us1[(gitlab_main/gitlab_ci Cell 미국1)]; db_cell_eu0[(gitlab_main/gitlab_ci Cell 유럽0)]; db_cell_eu1[(gitlab_main/gitlab_ci Cell 유럽1)]; 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;

사전 항공 요청 학습

요청을 처리하는 동안 URI는 디코딩되고, 각 캐시되지 않는 엔드포인트에 대해 사전 항공 요청이 전송됩니다.

GitLab Rails에서 엔드포인트를 요청할 때, 루트 가능한 경로에 대한 정보를 반환합니다. GitLab Rails는 path_info를 디코딩하고 기존 엔드포인트와 일치시키며 루트 가능한 엔터티(프로젝트와 같은)를 찾을 것입니다. 라우터는 이를 일시적인 캐시 정보로 처리할 것입니다.

  1. 접두어 일치: /api/v4/internal/cells/learn?method=GET&path_info=/gitlab-org/gitlab-test/-/issues

    {
       "path": "/gitlab-org/gitlab-test",
       "cell": "cell_0",
       "source": "routable"
    }
    
  2. 일부 엔드포인트는 정확한 일치를 요구할 수 있습니다: /api/v4/internal/cells/learn?method=GET&path_info=/-/profile

    {
       "path": "/-/profile",
       "cell": "cell_0",
       "source": "fixed",
       "exact": true
    }
    

첫 번째 이터레이션의 기본 조직 상세 설명

모든 사용자는 새로운 열 users.default_organization을 받게 되며, 사용자 설정에서 제어할 수 있을 것입니다. 우리는 GitLab.com Public 조직의 개념을 도입할 것입니다. 모든 기존 사용자에게 이 조직을 기본 조직으로 설정할 것입니다. 이 조직은 사용자가 Cell US0 (즉, 우리의 원본 GitLab.com 인스턴스)의 모든 네임스페이스에서 데이터를 볼 수 있도록 할 것입니다. 이 동작은 기존 사용자에게는 보이지 않을 것이므로, 그들은 심지어 /dashboard와 같은 전역 페이지를 보고 있을 때에도 조직에 대한 범위로 제한된 것임을 알리지 않을 것입니다.

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

관리 영역 설정의 상세 설명

우리는 관리 영역 설정을 유지하고 동기화하는 것은 괴로우며 고통스러울 것이라고 믿고, 따라서 우리는 관리 영역 설정을 분해하고 공유할 것입니다. 이는 기록 작업이 매우 적기 때문에(다른 공유 스키마와 유사) 안전할 것입니다.

다른 셀들이 다른 설정이 필요한 경우(예: Elasticsearch URL), 해당 application_settings 행에 동적으로 템플릿 형식을 사용하거나 셀당 1개의 행을 허용하여 셀당 다른 설정을 설정할 수 있는 per_cell_application_settings라는 새로운 테이블을 도입할 것입니다. 이는 여전히 gitlab_admin 스키마의 일부이며 공유되므로 중앙에서 관리하고 모든 셀의 설정을 동기화하는 것을 단순화할 수 있을 것입니다.

장점

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

단점

  1. gitlab_users, gitlab_routes, gitlab_admin 데이터베이스는 여러 지역에 복제되어야 하며 쓰기는 여러 지역에 걸쳐 이루어져야 할 수 있습니다. 이에 대한 실현 가능성을 결정하기 위해 해당 테이블의 쓰기 TPS에 대한 분석을 수행해야 합니다.
  2. 여러 다른 셀에서 데이터베이스에 대한 액세스를 공유하는 것은 모든 셀이 PostgreSQL 스키마 수준에서 결합되어 있음을 의미하며, 이는 데이터베이스 스키마에 대한 변경을 모든 셀과 함께 신중하게 수행해야 함을 제한하므로 이로 인해 셀이 공유 서비스를 가진 아키텍처에 비해 비교적 유사한 버전으로 유지될 것입니다.
  3. 대부분의 데이터는 올바른 지역에 저장되지만, 다른 지역에서 프록시로 전송된 요청이 특정 유형의 준수에 문제가 될 수 있습니다.
  4. gitlab_users, gitlab_routes 데이터베이스의 데이터는 모든 지역에 복제되어야 하는 문제가 될 수 있습니다.
  5. 라우터 캐시는 URL의 여러 다양한 유형(즉, 긴 꼬리)을 받는 경우 매우 크게 필요할 수 있으며, 그런 경우에는 사용자 쿠키에 2차 캐싱을 구현하여 사용자의 자주 액세스하는 페이지가 항상 처음부터 올바른 셀로 이동하도록 하는 것이 필요할 수 있습니다.
  6. 여러 셀에서 gitlab_usersgitlab_routes에 대한 공유 데이터베이스 액세스는 여러 셀에서 호출되는 서비스를 추출하는 것에 비해 일반적이지 않은 아키텍처 결정입니다.
  7. GraphQL URL의 캐시 가능한 요소를 찾지 못할 가능성이 매우 높으며, 기존의 GraphQL 엔드포인트는 ID에 매우 의존하므로 셀이 데이터가 있는 셀을 모르게 될 가능성이 높습니다. 따라서 우리는 아마도 경로에 조직 컨텍스트를 포함하여 GraphQL 호출을 업데이트해야 할 것으로 생각됩니다. (예: /api/organizations/<organization>/graphql).
  8. 이 아키텍처는 구현된 엔드포인트가 특정 셀에서 즉시 액세스할 수 있는 데이터만 액세스할 수 있지만, 여러 셀에서 정보를 집계할 가능성은 낮을 것입니다.
  9. 알 수 없는 경로는 최신 배포로 전송되며, 우리는 그것이 Cell US0로 가정할 수 있기 때문에 최신 셀에서만 디코드될 것임을 가정합니다. 아마도 이것은 경량 처리되는 internal/cells/learn에 대해서는 문제가 되지 않을 것입니다. 그리고 이것은 성능에 영향을 미칠 가능성이 없을 것입니다.

예제 데이터베이스 구성

공유 gitlab_users, gitlab_routesgitlab_admin 데이터베이스를 처리하면서, 전용 gitlab_maingitlab_ci 데이터베이스는 이미 config/database.yml을 사용하는 방식으로 처리해야 합니다. 또한, gitlab_usersgitlab_routes의 미국 주요 데이터베이스와 별도의 유럽 복제본도 처리할 수 있어야 합니다. 위에서 설명한 Cell 아키텍처에 대한 데이터베이스 구성 일부의 스니펫은 아래와 같습니다.

셀 US0:

# 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

셀 EU0:

# 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는 최상위 네임스페이스이며, GitLab.com Public 조직 내 Cell US0에 있습니다.
  2. my-company는 최상위 네임스페이스이며, my-organization 조직 내 Cell EU0에 있습니다.

my-organization의 유료 사용자 경험

이러한 사용자는 기본 조직이 /my-organization로 설정되어 있으며, 이 조직 외의 전역 라우트를로드할 수 없습니다. 다른 프로젝트/네임스페이스를로드할 수 있지만, 페이지 상단의 MR/Todo/Issue 카운트는 처음에 올바르게 채워지지 않을 것입니다. 사용자는 이 제한을 인식하게 됩니다.

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

  1. 유저는 유럽에 있으므로 DNS는 유럽 라우터를 해석합니다.
  2. 그들은 라우터 캐시 없이 /my-company/my-project를 요청하므로, 라우터는 무작위로 Cell EU1을 선택합니다.
  3. /internal/cells/learnCell EU1에 보내지며, 리소스가 Cell EU0에 존재한다는 응답을 받습니다.
  4. 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: /api/v4/internal/cells/learn?method=GET&path_info=/my-company/my-project cell_eu1->>router_eu: {path: "/my-company", cell: "cell_eu0", source: "routable"} router_eu->>cell_eu0: GET /my-company/my-project cell_eu0->>user: <h1>My Project...

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

  1. 유저는 유럽에 있으므로 DNS는 유럽 라우터를 해석합니다.
  2. 라우터는 아직 /my-company/*를 캐시하지 않았으므로 무작위로 Cell EU1을 선택합니다.
  3. /internal/cells/learnCell EU1에 보내지며, 리소스가 Cell EU0에 존재한다는 응답을 받습니다.
  4. Cell EU0은 로그인 플로우를 통해 사용자를 리디렉션합니다.
  5. 사용자가 /users/sign_in을 요청하고, 무작위 Cell을 사용하여 /internal/cells/learn을 실행합니다.
  6. Cell EU1은 고정 경로로 cell_0을 응답합니다.
  7. 로그인 후 사용자는 Cell EU0에 캐시되고 저장된 /my-company/my-project을 요청합니다.
  8. 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: /api/v4/internal/cells/learn?method=GET&path_info=/my-company/my-project cell_eu1->>router_eu: {path: "/my-company", cell: "cell_eu0", source: "routable"} router_eu->>cell_eu0: GET /my-company/my-project cell_eu0->>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: /api/v4/internal/cells/learn?method=GET&path_info=/users/sign_in cell_eu1->>router_eu: {path: "/users", cell: "cell_eu0", source: "fixed"} router_eu->>cell_eu0: GET /users/sign_in?redirect=/my-company/my-project cell_eu0-->>user: <h1>Sign in... user->>router_eu: POST /users/sign_in?redirect=/my-company/my-project router_eu->>cell_eu0: POST /users/sign_in?redirect=/my-company/my-project cell_eu0->>user: 302 /my-company/my-project user->>router_eu: GET /my-company/my-project router_eu->>cell_eu0: GET /my-company/my-project router_eu->>cell_eu0: GET /my-company/my-project cell_eu0->>user: <h1>My Project...

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

  1. 사용자는 유럽에 있으므로 DNS가 유럽의 라우터로 해석됩니다.
  2. 이제 라우터 캐시에 /my-company/* => Cell EU0가 있으므로, 라우터가 Cell EU0을 선택합니다.
  3. Cell EU0은 올바른 응답 및 캐시 헤더를 다시 반환합니다.
sequenceDiagram participant user as 사용자 participant router_eu as 라우터 EU participant cell_eu0 as 셀 EU0 participant cell_eu1 as 셀 EU1 user->>router_eu: GET /my-company/my-project router_eu->>cell_eu0: GET /my-company/my-project cell_eu0->>user: <h1>내 프로젝트...

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

  1. 사용자는 유럽에 있으므로 DNS가 유럽의 라우터로 해석됩니다.
  2. 이 URL에 대해 라우터에 캐시된 값이 없으므로, 임의로 Cell EU0을 선택합니다.
  3. Cell EU0은 라우터를 Cell US0로 리디렉션합니다.
  4. Cell US0은 올바른 응답과 캐시 헤더를 다시 반환합니다.
sequenceDiagram participant user as 사용자 participant router_eu as 라우터 EU participant cell_eu0 as 셀 EU0 participant cell_us0 as 셀 US0 user->>router_eu: GET /gitlab-org/gitlab router_eu->>cell_eu0: /api/v4/internal/cells/learn?method=GET&path_info=/gitlab-org/gitlab cell_eu0->>router_eu: {path: "/gitlab-org", cell: "cell_us0", source: "routable"} router_eu->>cell_us0: GET /gitlab-org/gitlab cell_us0->>user: <h1>GitLab.org...

이 경우 사용자는 “기본 조직”에 있지 않으므로 일반적인 할 일 디렉터리에 포함되지 않습니다. 우리는 아마도 사용자에게 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은 UI에서 명확하게 조직에 대한 대시보드보기이지만, 새 페이지 /organizations/my-organization/-/dashboard를 제공합니다.
  7. 사용자는 선택적으로이 페이지의 데이터가 기본 조직에서만 온 것이며, 그들이 기본 설정 조직을 변경할 수 있다는 메시지가 표시됩니다.
sequenceDiagram participant user as 사용자 participant router_eu as 라우터 EU participant cell_eu0 as 셀 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>내 회사 대시보드... X-Gitlab-Cell-Cache={path_prefix:/organizations/my-organization/}

/dashboard로 이동

위와 같이, 그들은 이미 레일 응용프로그램이 /를 대시보드 페이지로 리디렉션할 것이기 때문에, /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와 같은 애매한 경로를 렌더링하기 위한 기본 셀이 Cell US0임을 알고 있습니다. 마지막으로 사용자가 /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...

/로 이동

  1. 사용자는 미국에 있으므로 DNS가 미국의 라우터로 해석됩니다.
  2. 라우터에는 / 경로에 대한 캐시가 없습니다 (구체적으로 Rails는 이 경로를 캐시하도록 지시하지 않습니다).
  3. 라우터는 무작위로 Cell US1을 선택합니다.
  4. Rails 애플리케이션은 사용자의 기본 조직이 GitLab.com Public임을 알고 있으므로 사용자를 /dashboards로 리디렉션합니다 (레거시 사용자만 /dashboard 전역 뷰를 볼 수 있음).
  5. 라우터에는 /dashboard 경로에 대한 캐시가 없습니다 (구체적으로 Rails는 이 경로를 캐시하도록 지시하지 않습니다).
  6. 라우터는 무작위로 Cell US1을 선택합니다.
  7. Rails 애플리케이션은 사용자의 기본 조직이 GitLab.com Public임을 알고 있으므로 사용자가 /dashboards를 로드할 수 있도록 합니다 (레거시 사용자만 /dashboard 전역 뷰를 볼 수 있음) 및 레거시 셀인 Cell US0로 리디렉션합니다.
  8. Cell US0은 현재 우리가 가지고 있는 것과 동일한 대시보드 뷰 페이지 /dashboard를 제공합니다.
sequenceDiagram participant user as 사용자 participant router_us as 미국 라우터 participant cell_us0 as 미국 셀 0 participant cell_us1 as 미국 셀 1 user->>router_us: GET / router_us->>cell_us1: GET / cell_us1->>user: 302 /dashboard user->>router_us: GET /dashboard router_us->>cell_us1: /api/v4/internal/cells/learn?method=GET&path_info=/dashboard cell_us1->>router_us: {path: "/dashboard", cell: "cell_us0", source: "routable"} router_us->>cell_us0: GET /dashboard cell_us0->>user: <h1>대시보드...

/my-company/my-other-project로 이동하면서 로그인했지만 (하지만 해당 프로젝트에 액세스 권한이 없음)

404가 표시됩니다.

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

로그인한 사용자의 경우와 유사한 흐름이지만 /dashboard와 같은 전역 경로는 기본 조직을 선택할 수 없으므로 로그인 페이지로 리디렉션됩니다.

새로운 고객이 가입하는 경우

기존 조직의 구성원이거나 새로 생성할지를 묻는 폼이 표시됩니다. 둘 다 선택하지 않으면 기본 GitLab.com Public 조직으로 이동합니다.

조직이 하나의 셀에서 다른 셀로 이동될 때

미정

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

미정

검색 바의 자동완성 제안 기능

미정

전역 검색

미정

관리자

/admin 페이지 로딩

  1. /adminCell US0에 잠겨 있습니다.
  2. 관리자에서 프로젝트와 같은 /admin의 일부 엔드포인트는 셀에 제한되며 사용자는 드롭다운에서 올바른 셀을 선택해야 하므로 /admin/cells/cell_0/projects와 같은 엔드포인트가 생성됩니다.

포스트그레SQL의 관리자 영역 설정은 발산을 피하기 위해 모든 셀에서 공유되지만 URL 및 UI에서 관리자 영역 페이지를 제공하는 셀을 명확히 표시합니다. 이러한 페이지에서 동적 데이터가 생성되며 운영자는 특정 셀을 보고 싶어 할 수 있습니다.

해결해야 할 더 많은 기술적 문제

모든 셀 간에 사용자 세션을 복제하는 방법

현재 사용자 세션은 Redis에 저장되지만 각 셀마다 고유한 Redis 인스턴스가 있을 것입니다. 이미 세션용 전용 Redis 인스턴스를 사용하므로 gitlab_users PostgreSQL 데이터베이스와 마찬가지로 모든 셀과 공유할 수도 있습니다. 그러나 주의할 점은 대부분의 경우 여전히 동일한 지역에서 세션을 가져오길 원할 것이므로 지연시간입니다.

대안으로는 사용자 세션을 JWT 페이로드로 이동시키는 것이 있을 수 있지만 이에는 단점이 있습니다. 예를 들어 사용자 세션의 만료를 어렵게 만들 수 있으며, 이는 사용자에 의해 제어되는 JWT에 세션이 있기 때문에 비밀번호 변경 시 또는 기타 이유로 세션을 만료시키는 것이 어려울 수 있습니다.

셀간 이관 방법

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

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

시간 공격을 통해 비공개 그룹의 존재를 누설하는 것이 여전히 가능한가요?

EU에 라우터가 있고 EU 라우터가 기본적으로 EU에 위치한 셀로 리디렉션한다고 가정하면 지연시간을 알 수 있습니다 (여기서 10밀리초로 가정합니다). 이제 요청이 되돌려지고 미국으로 리디렉션이 되면 다른 지연시간이 발생합니다 (여기서 왕복이 약 60밀리초로 가정합니다). 따라서 404가 미국 셀에서 반환된다는 것을 추론할 수 있습니다.

이러한 시간 공격은 이미 이제의 허가 확인 방식으로 이론적으로 가능하지만 타이밍 차이는 실제로는 감지하기에 너무 작을 것으로 생각됩니다.

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

모든 셀을 통합하는 것이 좋을까요?

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

  1. 실행자 등록 및 대기열 테이블을 분해하고 모든 셀과 공유합니다. 이것은 확장성에 대한 영향을 미칠 수 있으며 그룹/프로젝트 실행자가 포함될지 여부를 고려해야 합니다.
  2. 실행자는 셀마다 등록되며, 아마도 각 셀에 별도의 실행자 집합이 있거나 많은 셀에 동일한 실행자를 등록할 것입니다. 실행 큐가 나타날 수 있으므로 이것은 확장성에 대한 고려사항이 될 수 있습니다.

모든 셀 간에 충돌할 수 없는 항목에 대해 고유 ID를 보장하는 방법은 무엇인가요?

이 프로젝트는 최소한 네임스페이스와 프로젝트가 유니크한 ID를 갖는다고 가정합니다. 많은 요청이 ID를 기반으로 경로 지정되어야 하므로 이러한 테이블이 다른 데이터베이스에 걸쳐 있으므로 고유한 ID를 보장하는 것이 새로운 솔루션을 필요로 합니다. 이러한 유일한 ID가 필요한 다른 테이블들이 있을 것이고 GraphQL 및 다른 API의 경로 지정을 어떻게 해결할지에 따라 우리가 어떤 설계 목표를 해결하려고 하는지에 따라 고유 키를 갖는다는 것이 좋을 지도 결정될 수 있습니다.