Status | Authors | Coach | DRIs | Owning Stage | Created |
---|---|---|---|---|---|
rejected | - |
- 요청 흐름
- 관리자
- 해결해야 할 더 많은 기술적 문제
- 모든 셀에서 러너를 공유해야합니까?
- 모든 셀에 대해 충돌하지 않아야 하는 항목을위한 고유 ID를 어떻게 보장합니까?
이 제안은 [라우팅 서비스 제안](../routing-service.md)에 의해 대체되었습니다.
<!-- vale gitlab.FutureTense = NO -->
이 문서는 작업 중이며 Pods 디자인의 초기 단계를 나타냅니다. 중요한 측면들이 문서화되지 않았지만, 향후 추가할 예정입니다. 이는 Pods의 하나의 가능한 아키텍처이며, 구현할 접근 방식을 결정하기 전에 대안과 대조할 것을 의도하고 있습니다. 이 접근 방식을 선택하지 않기로 결정해도 이 문서는 유지될 것이며, 이 접근 방식을 선택하지 않은 이유를 문서화할 수 있도록 할 것입니다.
# 제안: 요청 버퍼링을 사용하는 상태가 없는 라우터
`gitlab_users`, `gitlab_routes`, `gitlab_admin` 관련 테이블을 분해하여 모든 셀 간에 공유할 수 있도록 합니다. 셀은 사용자를 인증하고 요청을 올바른 셀로 보내도록 허용하기 위해, 소유하지 않은 리소스에 대한 요청을 받을 수 있지만 올바른 셀로 다시 리디렉션할 수 있습니다.
라우터는 상태가 없으며 `routes` 데이터베이스에서 읽지 않으므로, 모든 데이터베이스와의 상호 작용은 여전히 Rails 모놀리스에서 발생합니다. 이 아키텍처는 낮은 트래픽 데이터베이스가 지역 간에 복제되도록 함으로써 지역을 지원합니다.
사용자들은 셀의 개념에 직접 노출되지 않지만, 대신 선택한 조직에 따라 다른 데이터를 볼 수 있습니다. [조직](../goals.md#organizations)은 응용 프로그램에서 격리를 강제하고 어떤 요청이 어떤 셀로 라우트될지를 결정할 수 있도록 도입될 새로운 엔터티가 될 것입니다. 단, 하나의 조직은 단일 셀에만 있을 수 있습니다.
## 차이점
이 제안과 [러닝 라우트를 사용한 제안](proposal-stateless-router-with-routes-learning.md)의 주요 차이점은 이 제안이 항상 요청을 셀 중 하나로 보내도록 한다는 것입니다. 요청이 처리되지 못할 경우, 해당 헤더와 함께 요청이 다시 전달됩니다. 이에는 요청이 버퍼링되어야 한다는 점이 필요합니다. 또한 요청 디코딩은 레일즈에 의해 URI 또는 본문을 통해 이루어질 수 있습니다. 즉, 각 요청이 한 번 이상 보내질 수 있으며 그 결과로 한 번 이상 처리될 수 있음을 의미합니다.
[러닝 라우트를 사용한 제안](proposal-stateless-router-with-routes-learning.md)은 항상 URI에 라우팅 정보가 인코딩되어야 하며, 라우터가 사전 요청을 보내야 한다는 것을 요구합니다.
## 다이어그램에서 요약
이 그림은 사용자 요청이 DNS를 통해 가장 가까운 라우터로 라우팅되고, 라우터가 요청을 보낼 셀을 선택하는 방법을 보여줍니다.
```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
더 많은 상세정보
이 그림은 라우터가 실제로 모든 셀로 요청을 보낼 수 있음을 보여줍니다. 사용자는 지리적으로 가장 가까운 라우터를 가집니다. ```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 기본)]; db_gitlab_routes[(gitlab_routes 기본)]; db_gitlab_users_replica[(gitlab_users 복제본)]; db_gitlab_routes_replica[(gitlab_routes 복제본)]; db_cell_us0[(gitlab_main/gitlab_ci 셀 US0)]; db_cell_us1[(gitlab_main/gitlab_ci 셀 US1)]; db_cell_eu0[(gitlab_main/gitlab_ci 셀 EU0)]; db_cell_eu1[(gitlab_main/gitlab_ci 셀 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` 스키마로 분해됩니다.
1. `routes` 테이블은 `gitlab_routes` 스키마로 분해됩니다.
1. `application_settings` 및 아마도 몇 가지의 기타 인스턴스 수준의 테이블은 `gitlab_admin` 스키마로 분해됩니다.
1. `routes` 테이블에 `routes.cell_id`라는 새로운 열이 추가됩니다.
1. 새로운 Router 서비스가 생성되어 요청을 어느 셀로 라우팅할지 선택합니다.
1. GitLab에 조직이라는 새로운 개념이 도입될 것이며 사용자는 "기본 조직"을 선택할 수 있습니다. 기본 조직은 사용자 수준 설정입니다. 기본 조직은 `/dashboard`와 같은 모호한 경로에서 `/organizations/my-organization/-/dashboard`와 같은 조직 범위의 경로로 사용자를 리디렉션하기 위해 사용됩니다. 레거시 사용자들은 `Cell US0`에서 전역 리소스를 계속 사용할 수 있는 특별한 기본 조직을 가질 것입니다. 모든 기존 네임스페이스는 초기에 이 공개 조직으로 이동합니다.
1. 셀이 자체가 소유하지 않은 `routes.cell_id`에 대한 요청을 받으면, 라우터가 요청을 올바른 셀로 보낼 수 있도록 `302`와 `X-Gitlab-Cell-Redirect` 헤더가 포함된 상태로 응답합니다. 올바른 셀은 또한 이 요청을 기억하기 위해 요청을 어떻게 캐싱해야 하는지 나타내는 `X-Gitlab-Cell-Cache` 헤더를 설정할 수 있습니다. 예를 들어, 요청이 `/gitlab-org/gitlab`인 경우 헤더에 `/gitlab-org/* => Cell US0`와 같은 내용이 인코딩될 것입니다(예: `/gitlab-org/`로 시작하는 모든 요청은 항상 `Cell US0`로 라우팅됩니다).
1. 셀이 (캐시에서) 어떤 셀로 요청을 보낼지 모르는 경우, 해당 지역 내에서 임의의 셀을 선택합니다.
1. `gitlab_users` 및 `gitlab_routes`에 대한 쓰기는 `US` 지역의 주 PostgreSQL 서버로 전송되지만 읽기는 동일한 지역의 레플리카에서 와도 됩니다. 이로 인해 이러한 쓰기에는 지연이 추가되지만 기대되는 것은 GitLab의 나머지에 비해 빈번하지 않을 것입니다.
## 첫 번째 이터레이션에서 기본 조직의 상세 설명
모든 사용자에게 `users.default_organization`이라는 새로운 열이 추가됩니다. 사용자 설정에서 이를 제어할 수 있습니다. 우리는 `GitLab.com Public` 조직이라는 개념을 도입할 것입니다. 모든 기존 사용자에게 이 조직이 기본 조직으로 설정됩니다. 이 조직은 사용자가 `Cell US0`(예: 초기 GitLab.com 인스턴스)의 모든 네임스페이스에서 데이터를 볼 수 있도록 허용합니다. 기존 사용자들은 심지어 언제 글로벌 페이지(예: `/dashboard`)를 보고 있다고 알리지 않는 이 행동을 무시할 수 있습니다.
`GitLab.com Public` 이외의 새로운 사용자는 기본 조직이 `GitLab.com Public`이 아닌 다른 조직을 가진다면 구분된 사용자 경험이 생기며 로드하는 모든 페이지가 항상 특정 조직에 대해 범위가 정해진 것임을 완전히 인식하게 될 것입니다. 이러한 사용자들은 `/dashboard`와 같은 글로벌 페이지를 로드할 수 없으며 항상 `/organizations/<DEFAULT_ORGANIZATION>/-/dashboard`로 리디렉션됩니다. 이는 레거시 API 및 해당 사용자가 조직에 대해만 사용할 수 있는 API로 제한될 수 있습니다.
## Admin Area 설정의 상세 설명
관리 영역 설정의 유지 및 동기화가 괴로울 것으로 생각되어 이를 피하기 위해 우리는 모든 관리 영역 설정을 `gitlab_admin` 스키마에서 분해 및 공유할 것으로 믿고 있습니다. 이는 (다른 공유 스키마와 유사하게) 쓰기 트래픽이 매우 적기 때문에 안전해야 합니다.
다른 셀이 다른 설정이 필요한 경우(예: Elasticsearch URL 등), 관련 `application_settings` 행에서 동적으로 셀마다 다른 설정을 설정할 수 있는 템플릿형식을 사용할지 또는 그것이 어려울 경우 `per_cell_application_settings`라는 새 테이블을 도입하여 각 셀마다 다른 설정을 설정할 수 있도록 할 것입니다. 이는 여전히 `gitlab_admin` 스키마의 일부이며 중앙에서 이를 관리하고 모든 셀의 설정을 동기화하기 간소화할 수 있도록 해줍니다.
## 장점
1. 라우터는 상태를 갖지 않으며 많은 지역에서 운영될 수 있습니다. 우리는 사용자에게 가장 가까운 지역으로 해결하도록 하는 Anycast DNS를 사용합니다.
1. 셀은 잘못된 셀에 대한 네임스페이스의 요청을 받을 수 있으며 사용자는 여전히 올바른 응답을 받게 됩니다. 또한 라우터 캐싱을 통해 다음 요청이 올바른 셀로 보내지게 보장합니다.
1. 대부분의 코드는 여전히 `gitlab` 레일 코드 기반에 존재합니다. 라우터는 실제로 GitLab URL이 어떻게 구성되는지 이해할 필요가 없습니다.
1. `gitlab_users`, `gitlab_routes`, `gitlab_admin`의 읽고 쓰는 책임이 여전히 레일에게 있기 때문에 레일 애플리케이션에 필요한 변경은 도메인 모델을 분리하고 새 인터페이스를 구축하는 서비스를 추출하는 것보다는 최소화될 것입니다.
1. 별도의 라우팅 서비스보다는 레일 앱에서 더 복잡한 규칙을 인코딩할 수 있으며 일부 기존 API 엔드포인트에 대해서도 작동할 수 있을 수 있습니다.
1. 모든 새 인프라(라우터만)는 선택 사항입니다. 단일 셀 자체 관리 설치에서는 심지어 라우터를 실행할 필요도 없으며 다른 새로운 서비스도 없습니다.
## 단점
1. `gitlab_users`, `gitlab_routes`, 및 `gitlab_admin` 데이터베이스는 여러 지역에 복제되어야하며 쓰기 작업은 여러 지역에 이루어져야 할 수 있습니다. 해당 테이블에 대한 쓰기 TPS(초당 트랜잭션)를 분석하여 이것이 실행 가능한지 여부를 결정해야 합니다.
2. 여러 다른 셀에서 데이터베이스에 대한 액세스를 공유하는 것은 모든 셀이 Postgres 스키마 수준에서 결합되어 있음을 의미합니다. 이는 데이터베이스 스키마의 변경이 모든 셀의 배포와 함께 신중하게 이루어져야 함을 의미합니다. 이는 API를 제어하는 공유 서비스가 있는 아키텍처와 비교하여 셀이 서로 밀접하게 유사한 버전으로 유지되도록 제한합니다.
3. 대부분의 데이터가 올바른 지역에 저장되어 있지만 다른 지역에서 프록시로 전달되는 요청이 있을 수 있으며 이는 특정 유형의 규정 준수에 문제가 될 수 있습니다.
4. `gitlab_users` 및 `gitlab_routes` 데이터베이스의 데이터는 모든 지역에 복제되어야 하며 이는 특정 유형의 규정 준수에 문제가 될 수 있습니다.
5. 라우터 캐시는 매우 크게 설정되어야 할 수 있으며(예: 긴 꼬리와 같은) 다양한 URL이 있다면 해당 경우에는 사용자 쿠키에 2단계 캐싱을 구현하여 사용자의 자주 액세스하는 페이지가 항상 처음에 올바른 셀로 이동하도록 해야 할 수 있습니다.
6. 여러 셀에서 `gitlab_users` 및 `gitlab_routes`에 대한 공유 데이터베이스 액세스는 여러 셀에서 호출된 서비스를 추출하는 것과 비교하여 이례적인 아키텍처 결정입니다.
7. 매우 가능성이 높으므로 GraphQL URL의 캐시 가능한 요소를 찾을 수 없으며, 기존의 GraphQL 엔드포인트는 대부분 `routes` 테이블에 없는 id에 매우 의존하므로 셀은 데이터가 있는 셀을 알 수 없을 것입니다. 따라서 아마도 경로에 조직 컨텍스트를 포함하도록 GraphQL 호출을 업데이트해야 할 것으로 예상됩니다. (예: `/api/organizations/<organization>/graphql`).
8. 이 아키텍처는 구현된 엔드포인트가 주어진 셀에서 쉽게 액세스할 수 있는 데이터만 액세스할 수 있지만 여러 셀에서 정보를 집계할 가능성은 적을 것으로 예상됩니다.
9. 알려지지 않은 경로는 우리가 `Cell US0`로 가정하는 가장 최근 배포로 전송됩니다. 이것은 새롭게 추가된 엔드포인트가 최신 셀에서만 해독 가능할 것으로 가정하므로 필요합니다. 이후에 이 셀은 주어진 요청을 처리할 수 있는 올바른 셀로 리디렉션할 것입니다. 요청 처리가 무거울 수 있으므로 어떤 셀은 이로 인해 상당한 양의 트래픽을 받을 수 있습니다.
## 데이터베이스 구성 예시
공유 `gitlab_users`, `gitlab_routes` 및 `gitlab_admin` 데이터베이스를 처리하는 동시에, `gitlab_main` 및 `gitlab_ci` 데이터베이스를 전용으로 처리하는 방식은 이미 `config/database.yml`을 사용하는 방식에 의해 처리되어야 합니다. 또한, 단일 US 기본을 사용하여 전용 EU 복제본을 처리하는 것도 이미 처리되어야 합니다. 위에서 설명한 셀 아키텍처의 데이터베이스 구성 장면 일부에 대한 일부 스니펫은 아래와 같습니다.
<details><summary>셀 US0</summary>
```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
</details>
셀 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
```
요청 흐름
-
gitlab-org
은 최상위 네임스페이스로,GitLab.com Public
조직 내Cell US0
에 있습니다. -
my-company
는 최상위 네임스페이스로,my-organization
조직 내Cell EU0
에 있습니다.
my-organization
의 결제 사용자 경험
이러한 사용자는 기본적으로 /my-organization
으로 설정된 기본 조직을 가지고 있으며 해당 조직 외부의 모든 글로벌 경로를로드할 수 없을 것으로 예상됩니다. 다른 프로젝트/네임스페이스를로드할 수 있지만 페이지 상단의 MR/Todo/Issue 카운트가 첫 번째 반복에서 올바르게 채워지지 않을 것으로 예상됩니다. 사용자는 이 제한을 인식하게 될 것입니다.
/my-company/my-project
에 로그인한 상태에서 이동
- 사용자는 유럽에 있으므로 DNS는 유럽의 라우터로 해석됩니다.
- 라우터 캐시 없이
/my-company/my-project
를 요청하면, 라우터는 무작위로셀 EU1
을 선택합니다. -
셀 EU1
은/my-company
가 없지만셀 EU0
에 존재한다는 것을 알고 라우터를셀 EU0
로 리디렉션합니다. -
셀 EU0
는 올바른 응답을 반환하고 동시에 라우터의 캐시 헤더를 설정합니다./my-company/* => 셀 EU0
- 이제 라우터는
/my-company/*
에 일치하는 모든 요청 경로를셀 EU0
로 보내도록 캐시하고 기억합니다.
/my-company/my-project
에 로그인하지 않은 상태에서 이동
- 사용자는 유럽에 있으므로 DNS는 유럽의 라우터로 해석됩니다.
- 라우터는 아직
/my-company/*
를 캐시하지 않았기 때문에 무작위로셀 EU1
을 선택합니다. -
셀 EU1
은 로그인 플로우를 통해 사용자를 리디렉션합니다. - 그럼에도 불구하고 사용자는 라우터 캐시 없이
/my-company/my-project
를 요청하여, 라우터는 무작위의 셀셀 EU1
을 선택합니다. -
셀 EU1
은/my-company
가 없지만셀 EU0
에 존재한다는 것을 알고 라우터를셀 EU0
로 리디렉션합니다. -
셀 EU0
는 올바른 응답을 반환하고 동시에 라우터의 캐시 헤더를 설정합니다./my-company/* => 셀 EU0
- 이제 라우터는
/my-company/*
에 일치하는 모든 요청 경로를셀 EU0
로 보내도록 캐시하고 기억합니다.
마지막 단계 이후 /my-company/my-other-project
로 이동
- 사용자는 유럽에 있으므로 DNS는 유럽의 라우터로 해석됩니다.
- 이제 라우터 캐시에는
/my-company/* => 셀 EU0
이 있기 때문에 라우터는셀 EU0
을 선택합니다. -
셀 EU0
은 올바른 응답을 반환하고 다시 한번 캐시 헤더를 설정합니다.
마지막 단계 이후 /gitlab-org/gitlab
로 이동
- 사용자는 유럽에 있으므로 DNS는 유럽의 라우터로 해석됩니다.
- 이 URL에 대한 라우터의 캐시된 값이 없으므로 무작위로
셀 EU0
을 선택합니다. -
셀 EU0
는 라우터를셀 US0
로 리디렉션합니다. -
셀 US0
은 올바른 응답을 반환하고 다시 한번 캐시 헤더를 설정합니다.
이 경우 사용자는 “기본 조직”이 아니기 때문에 그들의 TODO 카운터에 일반적인 할 일이 포함되지 않습니다. 우리는 UI 어딘가에 이를 강조할 수 있습니다. 나중에 해당 사용자의 기본 조직에서 이를 위해 가져올 수 있는 미래의 반복이 있을 수 있습니다.
/
로 이동
- 사용자는 유럽에 있으므로 DNS는 유럽의 라우터로 해석됩니다.
- 라우터에는
/
경로에 대한 캐시가 없습니다(특히 Rails는이 경로를 캐시하도록 지시하지 않습니다). - 라우터는
Cell EU0
을 무작위로 선택합니다. - Rails 애플리케이션은 사용자의 기본 조직이
/my-organization
임을 알고 있으므로, 사용자를/organizations/my-organization/-/dashboard
로 리디렉션합니다. - 라우터는
/organizations/my-organization/*
에 대한 캐시된 값을 가지고 있으므로 요청을POD EU0
로 보냅니다. -
Cell EU0
은 새로운 페이지/organizations/my-organization/-/dashboard
를 제공합니다. 이 페이지는 현재의 대시보드 보기와 동일하지만 UI에서 명확하게 조직에 맞게 범위가 지정됩니다. - 사용자는 (선택 사항으로) 이 페이지의 데이터가 기본 조직에서만 제공된다는 메시지를 볼 수 있으며, 기본 조직이 잘못되었을 경우 기본 조직을 변경할 수 있다는 안내를 받습니다.
/dashboard
로 이동
위와 같이, rails 애플리케이션은 이미 /
를 대시보드 페이지로 리디렉션하므로,
사용자는 /organizations/my-organization/-/dashboard
에 있게 됩니다.
/not-my-company/not-my-project
로 이동(로그인되어 있지만이 프로젝트/그룹에 액세스할 수 없음)
- 사용자는 유럽에 있으므로 DNS는 유럽의 라우터로 해석됩니다.
- 라우터는
/not-my-company
가Cell US1
에 존재한다는 사실을 알고 있으므로 해당 셀로 요청을 보냅니다. - 사용자는 액세스 권한이 없기 때문에
Cell US1
은 404를 반환합니다.
새로운 최상위 네임스페이스 생성
사용자는 네임스페이스가 어느 조직에 속하는지 묻힐 것입니다.
그들이 my-organization
을 선택하면 그 네임스페이스는
다른 모든 my-organization
의 네임스페이스와 동일한 셀에 위치하게 될 것입니다.
아무것도 선택하지 않으면 기본적으로 GitLab.com Public
에 속한다는 의미이며,
이는 사용자에게 이미 존재하는 조직과 분리되어 있어서
단일 페이지에서 양쪽 데이터를 볼 수 없을 것이라는 것이 명확합니다.
/gitlab-org
의 구성원인 GitLab 팀 구성원의 경험
이러한 사용자는 레거시 사용자로 간주되며 기본 조직이 GitLab.com Public
으로 설정됩니다.
이 조직은 실제로 존재하지 않는 “메타” 조직으로 간주되지만,
Rails 애플리케이션은 이 조직을 해석하여 /dashboard
와 같은 레거시 글로벌 기능을
사용할 수 있음을 알고 있습니다. 이러한 레거시 글로벌 기능을 사용하기 위해
기본적으로 렌더링할 셀은 Cell US0
임을 알고 있습니다. 마지막으로 사용자는
/my-organization
와 같은 다른 셀에 있는 조직으로 이동할 수 있지만,
그렇게 하면 일부 데이터가 누락될 수 있다는 메시지가 표시됩니다(예: MRs/이슈/Todos 카운트 등).
로그인하지 않은 채 /gitlab-org/gitlab
로 이동
- 사용자는 미국에 있으므로 DNS는 미국 라우터로 해석됩니다.
- 라우터는
/gitlab-org
가Cell US0
에 존재한다는 사실을 알고 있으므로 해당 셀로 요청을 보냅니다. -
Cell US0
은 응답을 제공합니다.
/
로 이동
- 사용자는 미국에 있으므로 DNS는 미국 라우터로 해석됩니다.
- 라우터에는
/
경로에 대한 캐시가 없습니다(특히 Rails는이 경로를 캐시하도록 지시하지 않습니다). - 라우터는
Cell US1
을 무작위로 선택합니다. - Rails 애플리케이션은 사용자의 기본 조직이
GitLab.com Public
임을 알고 있으므로 사용자를/dashboards
로 리디렉션합니다(레거시 사용자만/dashboard
글로벌 뷰를 볼 수 있습니다). - 라우터에는
/dashboard
경로에 대한 캐시가 없습니다(특히 Rails는이 경로를 캐시하도록 지시하지 않습니다). - 라우터는
Cell US1
을 무작위로 선택합니다. - Rails 애플리케이션은 사용자의 기본 조직이
GitLab.com Public
임을 알고 있으므로 사용자가/dashboards
를 로드할 수 있게 허용하고Cell US0
(레거시 셀)로 리디렉션합니다. -
Cell US0
은 동일한 대시보드 뷰인 전역 뷰 대시보드 페이지/dashboard
를 제공합니다.
/my-company/my-other-project
에 로그인한 상태로 이동합니다 (그러나이 프로젝트는 비공개이므로 액세스할 수 없음)
404 오류가 발생합니다.
비인증 사용자의 경험
흐름은 인증된 사용자와 유사하지만 /대시 보드
와 같은 전역 라우트는 기본 조직을 선택할 수없는 경우 로그인 페이지로 리디렉션됩니다.
새 고객이 가입합니다
이들은 이미 조직의 구성원이거나 생성하고 싶은지 묻습니다. 둘 다 선택하지 않으면 기본 GitLab.com Public
조직에 있게 됩니다.
하나의 셀에서 다른 셀로 조직을 이동합니다
TODO
URL에 네임스페이스가 포함되지 않은 GraphQL/API 요청
TODO
검색 모음에서 최근 이슈/MR을 기억하는 자동 완성 제안 기능
TODO
전역 검색
TODO
관리자
/admin
페이지 로드
- 라우터가 무작위 셀
Cell US0
을 선택합니다. - Cell US0이 사용자를
/admin/cells/cellus0
로 리디렉션합니다. - Cell US0은 관리자 영역 페이지를 렌더링하고 또한 캐시 헤더를 반환하여
/admin/cellss/cellus0/* => Cell US0
를 캐시합니다. 관리자 영역 페이지에는 다른 선택할 수있는 셀을 보여주는 드롭다운 목록이 있으며 쿼리 매개 변수를 변경합니다.
포스트그레스의 관리자 영역 설정은 발산을 피하기 위해 모든 셀에서 공유되지만, URL 및 UI에서 어떤 셀이 관리자 영역 페이지를 제공하는지 동적 데이터가 생성되고 사용자가 특정 셀을 보고 싶어할 수 있기 때문에 명확하게 표시됩니다.
해결해야 할 더 많은 기술적 문제
모든 셀 간의 사용자 세션 복제
오늘날 사용자 세션은 Redis에 저장되지만 각 셀은 고유한 Redis 인스턴스를 갖습니다. 이미 세션용으로 전용 Redis 인스턴스를 사용하고 있으므로 gitlab_users
PostgreSQL 데이터베이스와 마찬가지로 이를 모든 셀과 공유하는 것을 고려할 수 있습니다. 그러나 주요 고려 사항은 여전히 대부분의 세션을 동일한 지역에서 검색하고 싶다는 것입니다.
대안으로 사용자 세션이 JWT 페이로드로 이동하여 모든 세션 데이터를 인코딩할 수 있지만 이러한 단점이 있습니다. 예를 들어 사용자 세션을 만료시키기가 어렵다는 것입니다. 사용자의 비밀번호가 변경되었을 때나 기타 이유로 세션이 만료되어야 하는 경우에 대비할 수 없습니다.
어떻게 셀간에 마이그레이션을 수행합니까?
셀 간의 데이터 마이그레이션에는 모든 데이터 스토어를 고려해야 합니다:
- PostgreSQL
- 공유 상태인 Redis
- Gitaly
- Elasticsearch
타이밍 공격을 통해 개인 그룹의 존재를 누설하는 것이 여전히 가능합니까?
EU에 라우터가 있고 EU 라우터가 기본적으로 EU에 위치한 셀로 리디렉션한다고 가정하면 그들의 지연 시간을 알 수 있습니다 (예: 10ms라고 가정). 이제 요청이 되돌아와 미국으로 리디렉션되는 경우 다른 지연 시간 (왕복이 약 60ms라고 가정)을 알 수 있으므로 404가 미국 셀에서 반환된 것을 추론할 수 있고 실제로 404가 403임을 알 수 있습니다.
이러한 타이밍 공격은 이미 현재의 권한 확인 방식으로 이론적으로 가능하지만 타이밍 차이는 감지할 수 없을 만큼 충분히 작을 것으로 생각됩니다.
이러한 위험을 완화하기 위한 한 가지 기술은 라우터가 셀에서 404를 반환하는 모든 요청에 무작위 지연을 추가하는 것일 수 있습니다.
모든 셀에서 러너를 공유해야합니까?
2개의 옵션이 있으며 더 쉬운 옵션을 결정해야합니다:
- 러너 등록 및 대기 테이블을 분해하고 모든 셀 간에 공유합니다. 이는 확장 가능성에 영향을 줄 수 있으며 그룹/프로젝트 러너도 포함해야하는지 여부를 고려해야합니다. 이러한 테이블은 확장 가능성 문제를 일으킬 수 있기 때문에 이러한 테이블은 다른 공유가 필요합니다.
- 러너는 셀별로 등록되며, 아마도 모든 셀에 대해 별도의 러너 풀을 갖거나 많은 셀에 동일한 러너를 등록하게 되는데, 이는 대기 큐에 영향을 줄 수 있는데, 우리의 경우 어떤 것이 더 적합한지 고려해야합니다.
모든 셀에 대해 충돌하지 않아야 하는 항목을위한 고유 ID를 어떻게 보장합니까?
이 프로젝트는 적어도 네임스페이스와 프로젝트가 모든 셀에서 고유한 ID를 갖는다고 가정합니다. 많은 요청이 ID를 기반으로 경로를 지정해야하기 때문에 이러한 테이블이 다른 데이터베이스에 걸쳐 있기 때문에 고유한 ID를 보장하는 데는 새로운 솔루션이 필요합니다. 아마도 다른 API 및 다른 디자인 목표에 대한 라우팅을 어떻게 해결할 것인지에 따라 고유 ID가 모든 테이블에 대해 필요할 가능성이 있습니다.