Status | Authors | Coach | DRIs | Owning Stage | Created |
---|---|---|---|---|---|
accepted | - |
Cells: 라우팅 서비스
이 문서는 Cells에서 사용되는 라우팅 서비스의 설계 목표 및 아키텍처에 대해 설명합니다. 라우팅 서비스가 아키텍처에 어떻게 들어맞는지에 대해 더 잘 이해하려면 인프라 아키텍처를 참조하세요.
목표
라우팅 레이어는 사용자가 별도의 도메인으로 이동하지 않고도 모든 Cells를 단일 도메인(예: gitlab.com
) 아래에서 제공받을 수 있는 일관된 사용자 경험을 제공하는 것을 목표로 합니다.
사용자는 https://gitlab.com
을 사용하여 Cell을 활성화한 GitLab에 액세스할 수 있을 것입니다. URL 액세스에 따라 해당 정보를 제공할 수 있는 올바른 Cell로 투명하게 프록시될 것입니다. 예를 들어:
-
https://gitlab.com/users/sign_in
로 가는 모든 요청은 모든 Cells로 무작위로 분배됩니다. -
https://gitlab.com/gitlab-org/gitlab/-/tree/master
로 가는 모든 요청은 항상 예를 들어 Cell 5로 이동됩니다. -
https://gitlab.com/my-username/my-project
로 가는 모든 요청은 항상 Cell 1로 이동됩니다.
-
기술.
라우팅 서비스에 사용될 기술을 결정합니다. 선택은 최상의 성능을 발휘하는 언어 및 라우팅 레이어를 배포할 기대 위치에 따라 달라집니다. 서비스를 멀티 클라우드로 만들어야 하는 경우, CDN 제공업체에 배포해야 할 수도 있습니다. 그런 다음 서비스는 해당 CDN 제공업체와 호환되는 기술을 사용하여 작성되어야 합니다.
-
Cell 탐색.
라우팅 서비스는 모든 Cells의 상태를 탐색하고 모니터링할 수 있어야 합니다.
-
사용자는 단일 도메인을 통해 여러 Cells와 상호 작용할 수 있어야 함.
라우팅 서비스는 액세스하는 리소스에 따라 모든 요청을 올바른 Cell로 라우팅할 수 있는 지능을 가지고 있어야 합니다.
-
라우터 엔드포인트 분류.
상태가 없는 라우팅 서비스는 한 Cell에서 엔드포인트에 대한 정보를 가져와 캐시할 것입니다. 들어오는 요청(지문)을 정확히 기술할 수 있는 프로토콜을 구현해야 하므로 이를 한 Cell에 분류하고 그 결과를 캐시할 수 있습니다. 또한 부정적인 캐시와 캐시 삭제 메커니즘을 구현해야 합니다.
-
GraphQL 및 다른 모호한 엔드포인트.
대부분의 엔드포인트는 조직을 기준으로 한 고유한 샤딩 키가 있습니다. 이 샤딩 키는 엔드포인트를 분류하는 데 사용될 수 있습니다(직접 또는 그룹 또는 프로젝트를 통해 간접적으로). 일부 엔드포인트는 사용 방식에 대해 모호합니다(샤딩 키가 인코딩되어 있지 않음) 또는 샤딩 키가 페이로드 내에 깊이 저장되어 있습니다. 이러한 경우,
/api/graphql
과 같은 엔드포인트를 어떻게 처리할지 결정해야 합니다. -
작음.
라우팅 서비스는 구성 및 규칙에 따라 동작하며 별도의 비즈니스 로직을 구현하지 않습니다. 초기 단계의 프로젝트 소스 코드의 최대 크기는 테스트를 포함하여 1,000줄입니다. 하드 제한의 이유는 특별한 로직이 없도록 라우팅 서비스를 만들고 몇 일 안에 어떤 기술로든 다시 작성할 수 있도록 하기 위함입니다.
요구 사항
요구 사항 | 설명 | 우선순위 |
---|---|---|
탐색 | 모든 Cells의 상태를 탐색하고 모니터링할 수 있어야 함. | 높음 |
보안 | 인가된 Cells만 라우팅될 수 있어야 함. | 높음 |
단일 도메인 | 예: GitLab.com | 높음 |
캐싱 | 성능을 위해 라우팅 정보를 캐시할 수 있어야 함. | 높음 |
저지연 | 50 ms의 증가된 지연 | 높음 |
경로 기반 | 경로를 기준으로 라우팅 결정을 내릴 수 있어야 함. | 높음 |
복잡성 | 라우팅 서비스는 구성 및 소규모이어야 함. | 높음 |
롤링 | 혼합 버전의 Cells와 작동하는 라우팅 서비스. | 높음 |
피처 플래그 | 피처를 켜거나 끌 수 있고 % 롤아웃할 수 있어야 함. | 높음 |
점진적 롤아웃 | 변화를 천천히 롤아웃할 수 있어야 함. | 중간 |
상태가 없음 | 데이터베이스가 필요하지 않음. Cells는 모든 라우팅 정보를 제공함. | 중간 |
시크릿 기반 | 비밀 기반(예: JWT)으로 라우팅 결정을 내릴 수 있어야 함. | 중간 |
관측성 | 기존의 관측성 도구를 사용할 수 있어야 함. | 낮음 |
Self-managed | 셀프-매니지드에서 최종적으로 사용할 수 있어야 함. | 낮음 |
지역별 | 다른 지역으로 요청을 라우팅할 수 있어야 함. | 낮음 |
저지연
라우팅 서비스의 대상 지연 시간은 50 ms 미만이어야 합니다.
긴급함: 높음
요청을 살펴보면 p50 수준에서는 여유가 많지 않은 것으로 보입니다. 추가 50 _ms_를 더하면 p95 수준에서도 SLO 내에 있을 수 있습니다.
응용 프로그램의 3개 주요 진입점은 web
, api
, git
입니다. 각 서비스는 apdex 표준을 사용하여 지연을 기반으로 서비스 수준 지표 (SLI)를 할당받습니다. 이러한 SLI에 대한 해당 서비스 수준 목표 (SLO)는 대규모 요청에 대해 낮은 지연이 필요합니다. 이러한 서비스 앞에 라우팅 레이어를 추가했을 때 SLI에 영향을 미치지 않도록 하는 것이 중요합니다. 라우팅 레이어는 이러한 서비스를 위한 프록시이며 전체 요청 흐름에 대한 포괄적인 SLI 모니터링 시스템이 부족하므로 (Edge 네트워크 및 로드 밸런서와 같은 컴포넌트를 포함하여) 우리는 web
, git
, api
의 SLI를 대상으로 사용합니다.
우리가 사용하는 주요 SLI는 rails requests입니다. 요청의 긴급성에 따라 여러 만족
대상(apdex)이 있습니다:
긴급성 | 시간 (ms) |
---|---|
:high
| 250 ms |
:medium
| 500 ms |
:default
| 1000 ms |
:low
| 5000 ms |
분석
우리가 갖고있는 여유 공간을 계산하는 방법은 다음과 같습니다.
\mathrm{Headroom}\ {ms} = \mathrm{Satisfied}\ {ms} - \mathrm{Duration}\ {ms}
web
:
목표 시간 | 백분위수 | 여유 공간 |
---|---|---|
5000 ms | p99 | 4000 ms |
5000 ms | p95 | 4500 ms |
5000 ms | p90 | 4600 ms |
5000 ms | p50 | 4900 ms |
1000 ms | p99 | 500 ms |
1000 ms | p95 | 740 ms |
1000 ms | p90 | 840 ms |
1000 ms | p50 | 900 ms |
500 ms | p99 | 0 ms |
500 ms | p95 | 60 ms |
500 ms | p90 | 100 ms |
500 ms | p50 | 400 ms |
250 ms | p99 | 140 ms |
250 ms | p95 | 170 ms |
250 ms | p90 | 180 ms |
250 ms | p50 | 200 ms |
분석은 https://gitlab.com/gitlab-org/gitlab/-/issues/432934#note_1667993089에서 진행되었습니다.
api
:
목표 시간 | 백분위수 | 여유 공간 |
---|---|---|
5000 ms | p99 | 3500 ms |
5000 ms | p95 | 4300 ms |
5000 ms | p90 | 4600 ms |
5000 ms | p50 | 4900 ms |
1000 ms | p99 | 440 ms |
1000 ms | p95 | 750 ms |
1000 ms | p90 | 830 ms |
1000 ms | p50 | 950 ms |
500 ms | p99 | 450 ms |
500 ms | p95 | 480 ms |
500 ms | p90 | 490 ms |
500 ms | p50 | 490 ms |
250 ms | p99 | 90 ms |
250 ms | p95 | 170 ms |
250 ms | p90 | 210 ms |
250 ms | p50 | 230 ms |
분석은 https://gitlab.com/gitlab-org/gitlab/-/issues/432934#note_1669995479에서 진행되었습니다.
git
:
목표 시간 | 백분위수 | 여유 공간 |
---|---|---|
5000 ms | p99 | 3760 ms |
5000 ms | p95 | 4280 ms |
5000 ms | p90 | 4430 ms |
5000 ms | p50 | 4900 ms |
1000 ms | p99 | 500 ms |
1000 ms | p95 | 750 ms |
1000 ms | p90 | 800 ms |
1000 ms | p50 | 900 ms |
500 ms | p99 | 280 ms |
500 ms | p95 | 370 ms |
500 ms | p90 | 400 ms |
500 ms | p50 | 430 ms |
250 ms | p99 | 200 ms |
250 ms | p95 | 230 ms |
250 ms | p90 | 240 ms |
250 ms | p50 | 240 ms |
분석은 https://gitlab.com/gitlab-org/gitlab/-/issues/432934#note_1671385680에서 진행되었습니다.
비목표
아직 정의되지 않음.
제안
라우팅 서비스는 다음과 같은 설계 지침을 구현합니다:
- 단순:
- 라우팅 서비스는 요청을 버퍼로 처리하지 않습니다.
- 라우팅 서비스는 요청 헤더에 기반한 단일 셀로만 프록시를 할 수 있습니다.
- 상태가 없는:
- 라우팅 서비스는 영구 리포지터리를 갖고 있지 않습니다.
- 라우팅 서비스는 인메모리 및 외부 공유 캐시를 사용합니다.
- 제로 트러스트:
- 라우팅 서비스는 프록시되는 각 요청에 서명합니다.
- 신뢰는 JWT 토큰 또는 상호 인증 체계를 사용하여 설정됩니다.
- 셀은 제로 트러스트 모델을 따르는 한 공개 인터넷을 통해 이용할 수 있습니다.
- 구성 기반:
- 라우팅 서비스는 정적 셀 디렉터리으로 구성됩니다.
- 라우팅 서비스 구성은 서비스 배포의 일부로 적용됩니다.
- 규칙 기반:
- 라우팅 서비스는 모든 셀에서 수집한 라우팅 규칙으로 배포됩니다.
- 라우팅 서비스는 GitLab의 다른 버전에서 생성된 규칙 디렉터리을 지원합니다.
- 규칙에는 헤더, 헤더 내용 또는 경로로 일치시킬 수 있는 모든 기준이 포함됩니다.
- 중립적:
- 라우팅 서비스는 조직과 같은 고수준의 개념을 인식하지 않습니다.
- 분류는 규칙에 제공된 명세에 따라 수행되어 샤딩 키를 찾습니다.
- 샤딩 키 결과가 캐시됩니다.
- 캐시된 단일 샤딩 키는 많은 유사한 요청을 처리하는 데 사용됩니다.
다음 다이어그램은 사용자 요청이 DNS를 통해 라우팅 서비스로 전송되고, 라우터가 요청을 보낼 셀을 선택하는 방법을 보여줍니다.
라우팅 규칙
각 셀은 라우팅 서비스에서 사용될 사전 컴파일된 라우팅 규칙 디렉터리을 게시합니다.
- 라우팅 규칙은 요청의 디코딩 방법, 샤딩 키 검색, 및 라우팅 결정 방법을 설명합니다.
- 라우팅 규칙은 라우팅 서비스 배포 중에 컴파일됩니다.
- 배포 프로세스는 라우팅 서비스 구성에 속한 각 셀에서 최신 버전의 라우팅 규칙을 가져옵니다.
- 컴파워크플로는 모든 셀에서 라우팅 규칙을 Merge합니다.
- 충돌하는 규칙은 라우팅 서비스의 컴파일 또는 시작을 방지합니다.
- 각 라우팅 규칙 항목에는 Merge을 용이하게 하는 고유 식별자가 있습니다.
- 라우팅 서비스는 규칙 디렉터리이 변경된 경우에만 재배포됩니다. 이는 자주 발생하지 않을 것으로 예상됩니다. 왜냐하면 대부분의 새로 추가된 엔드포인트가 이미 이전의 경로 규칙을 준수할 것으로 기대하기 때문입니다.
- 구성에서 배포 중에 라우팅 규칙을 가져와야 하는 셀을 설명합니다.
- 게시된 라우팅 규칙은 secret을 기반으로한 라우팅 결정을 수행할 수 있습니다. 예를 들어, 세션 쿠키나 인증 토큰이
c100-
접두사를 가지고 있다면 모든 요청은 해당 셀로 전달되어야 합니다. - 셀은
/api/v4/internal/cells/route_rules.json
에서 라우팅 규칙을 게시합니다. - 셀에서 게시된 규칙은 해당 셀이 처리할 수 있는 엔드포인트만 포함합니다.
- 셀은 분할 키를 기반으로 동적 분류를 수행하도록 요청할 수 있습니다. 이를 위해
/api/v4/internal/cells/classify
를 호출하는 라우팅 규칙을 구성합니다. - 라우팅 규칙은 분류를 가속화하기 위해
prefix
를 사용해야 합니다. 컴파일 단계에서 라우팅 서비스는 모든 발견된 접두사를 결정 트리로 변환하여 이후의 정규식 일치를 가속화합니다. - 일부 접두사는 셀에 독립적이어야 합니다. 예를 들어 개인 액세스 토큰 접두사는 조직에 바인드되어야 하며 셀에 바인드되어서는 안됩니다. 우리는 조직을 하나의 셀에서 다른 셀로 옮길 때 개인 액세스 토큰이나 다른 토큰을 변경하지 않고도 조직을 이동할 수 있기를 원합니다.
- 라우팅 규칙은 배포의 일환으로 규칙을 동적으로 파싱하고 평가하는 비용을 피하기 위해 소스 코드로 이상적으로 컴파일되어야 합니다.
라우팅 규칙 JSON 구조는 모든 매처를 설명합니다:
{
"rules": [
{
"id": "<고유 식별자>",
"cookies": {
"<cookie_이름>": {
"prefix": "<일치하는 접두어>",
"match_regex": "<정규식 일치>"
},
"<cookie_이름2>": {
"prefix": "<일치하는 접두어>",
"match_regex": "<정규식 일치>"
}
},
"headers": {
"<header_이름>": {
"prefix": "<일치하는 접두어>",
"match_regex": "<정규식 일치>"
},
"<header_이름2>": {
"prefix": "<일치하는 접두어>",
"match_regex": "<정규식 일치>"
}
},
"path": {
"prefix": "<일치하는 접두어>",
"match_regex": "<정규식 일치>"
},
"method": ["<수락된 메서드 디렉터리>"],
// 여러 규칙이 일치하는 경우, 어떤 것이 우선하는지 정의합니다.
"priority": 1000,
// 요청을 수락하고 해당 셀로 프록시합니다.
"action": "proxy",
// 정규식 일치 그룹을 기반으로 요청을 분류합니다.
"action": "classify",
"classify": {
"keys": ["정규식 일치 캡처 그룹 디렉터리"]
}
}
]
}
셀 100에서 발행된 라우팅 규칙 예시로, 세션 쿠키와 secret을 기반으로한 라우팅 결정을 수행합니다. 라우팅 규칙이 secret을 기반으로 하고 있으며 다른 모든 매처보다 우선되어야 하므로 높은 우선순위가 할당됩니다:
{
"rules": [
{
"id": "t4mkd5ndsk58si6uwwz7rdavil9m2hpq",
"cookies": {
"_gitlab_session": {
"prefix": "c100-" // `c100-`로 시작하는 `_gitlab_session`을 수락합니다.
}
},
"action": "proxy",
"priority": 1000
},
{
"id": "jcshae4d4dtykt8byd6zw1ecccl5dkts",
"headers": {
"GITLAB_TOKEN": {
"prefix": "C100_" // `C100_`로 시작하는 `GITLAB_TOKEN`을 수락합니다.
}
},
"action": "proxy",
"priority": 1000
}
]
}
모든 셀에서 발행된 라우팅 규칙 예시로, 경로를 기반으로한 라우팅 결정을 수행합니다:
{
"rules": [
{
"id": "c9scvaiwj51a75kzoh917uwtnw8z4ebl",
"path": {
"prefix": "/api/v4/projects/", // 매칭 규칙 가속화
"match_regex": "^/api/v4/projects/(?<project_id_or_path_encoded>[^/]+)(/.*)?$"
},
"action": "classify",
"classify": {
"keys": ["project_id_or_path_encoded"]
}
}
]
}
분류
각 셀은 분류 엔드포인트를 구현합니다:
- 분류 엔드포인트는
/api/v4/internal/cells/classify
(또는 gRPC 엔드포인트)에 위치합니다. - 분류 엔드포인트는 샤딩 키 디렉터리을 허용합니다. 샤딩 키는 요청에서 디코드되며 셀이 제공한 라우팅 규칙을 기반으로합니다.
- 엔드포인트는 유사한 요청을 위해 캐시를 오염시킬 다른 동등한 샤딩 키를 반환합니다. 이는 각각의 유사한 요청을 분류하지 않고도 빠르게 처리할 수 있도록합니다.
- 라우팅 서비스는 셀의 상태를 추적하고 가중치, 셀의 상태 또는 기타 정의된 기준에 따라 셀에
classify
요청을 발행합니다. 가중치는 어떤 셀이 샤딩 키의 분류를 수행하기를 더 선호하는지 나타냅니다. - 라우팅 서비스는
classify
호출을 일정 시간 동안 재시도합니다. 셀이classify
에 반복적으로 실패하면 해당 셀이 건강하지 않다는 것을 나타냅니다. -
classify
결과는 반환된action
에 관계없이 캐시됩니다 (프록시 또는 거부). 거부된 분류는 발견되지 않은 샤딩 키를 위한 과도한 요청을 방지하기 위해 캐시됩니다. - 캐시된 응답은
만료
및새로고침
으로 정의된 시간 동안 유지됩니다.-
만료
는 사용되지 않으면 항목이 캐시에서 제거되는 시기를 정의합니다. -
새로고침
은 사용된 경우 재분류되어야 하는 시기를 정의합니다. - 요청이 분류되었다면 그 즉시 응답되어야 하므로 새로고침은 비동기적으로 수행됩니다. 새로고침은 항상 캐시가 항상 핫하고 최신 상태인지 보장하기 위해 수행됩니다.
-
## 요청:
{
"metadata": {
"rule_id": "c9scvaiwj51a75kzoh917uwtnw8z4ebl",
"headers": {
"all_request_headers": "value"
},
"method": "GET",
"path": "/api/v4/projects/100/issues"
},
"keys": {
"project_id_or_path_encoded": 100
}
}
## 응답:
{
"action": "proxy",
"proxy": {
"name": "cell_1",
"url": "https://cell1.gitlab.com"
},
"ttl": "10 minutes",
"matched_keys": [ // cache에 넣어야 하는 모든 동등 키 디렉터리
{ "project_id_or_path_encoded": 100 },
{ "project_id_or_path_encoded": "gitlab-org%2Fgitlab" },
{ "project_full_path": "gitlab-org/gitlab" },
{ "namespace_full_path": "gitlab-org" },
{ "namespace_id": 10 },
{ "organization_full_path": "gitlab-inc" },
{ "organization_id": 50 },
]
}
다음 코드는 샤딩 키를 찾을 수 없을 때 부정적인 응답을 나타냅니다:
# POST /api/v4/internal/cells/classify
## 요청:
{
"metadata": {
"rule_id": "c9scvaiwj51a75kzoh917uwtnw8z4ebl",
"headers": {
"all_request_headers": "value"
},
"method": "GET",
"path": "/api/v4/projects/100/issues"
},
"keys": {
"project_id_or_path_encoded": 100
}
}
## 응답:
{
"action": "reject",
"reject": {
"http_status": 404
},
"cache": {
"refresh": "10 minutes",
"expiry": "10 minutes"
},
"matched_keys": [ // cache에 넣어야 하는 모든 동등 키 디렉터리
{ "project_id_or_path_encoded": 100 },
]
}
설정
라우팅 서비스는 다음과 유사한 구성을 사용할 것으로 예상됩니다:
[[cells]]
name=cell_1
url=https://cell1.gitlab.com
key=ABC123
classify_weight=100
[[cells]]
name=cell_2
url=https://cell2.gitlab.com
key=CDE123
classify_weight=1
[cache.memory.classify]
refresh_time=10 minutes
expiry_time=1 hour
[cache.external.classify]
refresh_time=30 minutes
expiry_time=6 hour
유사한 모든 Cells, URL, 제로 트러스트 키, 가중치 및 요청이 얼마 동안 캐시될지에 대한 설정을 설명합니다. classify_weight
는 다른 Cells에 비해 셀이 분류 요청을 얼마나 자주 받아야 하는지를 정의합니다.
요청 흐름
- 두 개의 Cells가 있습니다.
-
gitlab-org
은GitLab.com Public
조직의Cell US0
에 거주하는 최상위 네임스페이스입니다. -
my-company
는my-organization
조직의Cell EU0
에 거주하는 최상위 네임스페이스입니다.
정적 라우팅 수행으로 구성된 라우터
- Cell US0은 모든 다른 공개 프로젝트를 지원합니다.
- Cells는 Cell EU0에 대해
eu0_
와 같은 접두사로 모든 비공개 조직, 그룹 및 프로젝트의 모든 비밀 및 세션 쿠키를 생성하도록 구성됩니다.- 개인 액세스 토큰은 조직 범위로 구성되며, 조직이 하나의 Cell의 일부인 경우, 생성된 PAT는 Cell 식별자로 접두어가 붙습니다.
- 세션 쿠키는 사용 중인 조직을 인코딩하며, 조직이 한 Cell의 일부인 경우, 생성된 세션 쿠키는 Cell 식별자로 접두어가 붙습니다.
- Cell EU0는 비공개 조직, 그룹 및 프로젝트만 허용합니다.
- Cell US0은 명시적으로 접두어가 붙지 않는 한 모든 요청에 대상 Cell입니다.
Cell US0:
{
"rules": [
{
"id": "tjh147se67wadjzum7onwqiad2b75uft",
"path": {
"prefix": "/"
},
"action": "proxy",
"priority": 1
}
]
}
Cell EU0:
{
"rules": [
{
"id": "t4mkd5ndsk58si6uwwz7rdavil9m2hpq",
"cookies": {
"_gitlab_session": {
"prefix": "eu0_"
}
},
"path": {
"prefix": "/"
},
"action": "proxy",
"priority": 1000
},
{
"id": "jcshae4d4dtykt8byd6zw1ecccl5dkts",
"headers": {
"GITLAB_TOKEN": {
"prefix": "eu0_"
}
},
"path": {
"prefix": "/"
},
"action": "proxy",
"priority": 1000
}
]
}
Cell EU0에 로그인한 상태로 /my-company/my-project
로 이동
- 사용자가 조직을
my-company
로 변경했기 때문에 세션 쿠키는eu0_
로 접두어가 붙었습니다. - 사용자가
/my-company/my-project
요청을 보내고, 쿠키가eu0_
로 접두어가 붙었기 때문에 Cell EU0로 리디렉션됩니다. -
Cell EU0
는 올바른 응답을 반환합니다.
#### '/my-company/my-project'로 이동 (로그인되지 않은 상태)
1. 사용자가 '/my-company/my-project'을 방문하고 세션 쿠키가 없기 때문에 요청이 'Cell US0'로 전달됩니다.
1. 사용자가 로그인합니다.
1. GitLab은 사용자의 기본 조직이 'my-company'임을 인지하고, 'my-company'와 상호 작용할 것으로 간주하여 세션 쿠키에 'eu0_'를 할당합니다.
1. 사용자가 세션 쿠키를 포함하여 다시 '/my-company/my-project'로 요청하면 해당 요청이 'Cell EU0'로 프록시됩니다.
1. 'Cell EU0'이 올바른 응답을 반환합니다.
```mermaid
sequenceDiagram
participant user as User
participant router as Router
participant cell_us0 as Cell US0
participant cell_eu0 as Cell EU0
user->>router: GET /my-company/my-project
router->>cell_us0: GET /my-company/my-project
cell_us0->>user: HTTP 302 /users/sign_in?redirect=/my-company/my-project
user->>router: GET /users/sign_in?redirect=/my-company/my-project
router->>cell_us0: GET /users/sign_in?redirect=/my-company/my-project
cell_us0-->>user: <h1>Sign in...
user->>router: POST /users/sign_in?redirect=/my-company/my-project
router->>cell_us0: POST /users/sign_in?redirect=/my-company/my-project
cell_us0->>user: HTTP 302 /my-company/my-project<br/>_gitlab_session=eu0_uwwz7rdavil9
user->>router: GET /my-company/my-project<br/>_gitlab_session=eu0_uwwz7rdavil9
router->>cell_eu0: GET /my-company/my-project<br/>_gitlab_session=eu0_uwwz7rdavil9
cell_eu0->>user: <h1>My Project...
마지막 단계 이후 ‘/gitlab-org/gitlab’로 이동
사용자가 ‘/my-company/my-project’을 방문하고 세션 쿠키가 없기 때문에 요청이 ‘Cell US0’로 전달됩니다.
분류에 기반한 동적 라우팅을 수행하도록 구성된 라우터
Cells는 요청을 분류할 수 있도록 경로 규칙을 게시합니다.
Cell US0와 EU0:
{
"rules": [
{
"id": "tjh147se67wadjzum7onwqiad2b75uft",
"path": {
"prefix": "/",
"regex": "^/(?top_level_group)[^/]+(/.*)?$",
},
"action": "classify",
"classify": {
"keys": ["top_level_group"]
}
},
{
"id": "jcshae4d4dtykt8byd6zw1ecccl5dkts",
"path": {
"prefix": "/"
},
"action": "proxy"
}
]
}
Cell EU0에 로그인된 상태로 ‘/my-company/my-project’로 이동
- ‘/my-company/my-project/’가 방문됩니다.
- 라우터가 샤딩 키 ‘top_level_group=my-company’를 디코딩합니다.
- 라우터가 이 샤딩 키가 캐시되어 있는지 확인합니다.
- 그렇지 않기 때문에, 분류 요청이 임의의 Cell에 ‘/classify’로 보내집니다.
- 분류의 응답이 캐시됩니다.
- 그 요청은 분류에 의해 반환된 Cell로 프록시됩니다.
로그인되지 않은 상태로 ‘/my-company/my-project’로 이동
- ‘/my-company/my-project/’가 방문됩니다.
- 라우터가 샤딩 키 ‘top_level_group=my-company’를 디코딩합니다.
- 라우터가 이 샤딩 키가 캐시되어 있는지 확인합니다.
- 그렇지 않기 때문에, 분류 요청이 임의의 Cell로 ‘/classify’로 보내집니다.
- 분류의 응답이 캐시됩니다.
- 분류에 의해 반환된 Cell로 프록시됩니다.
- 프로젝트가 비공개이기 때문에 사용자가 로그인되지 않은 상태로 있으면 로그인을 요청받습니다.
- 모든 Cells에서 처리되도록 정의된 로그인은 임의의 Cell로 프록시됩니다.
- 로그인 후 사용자가 다시 ‘/my-company/my-project/’를 방문합니다.
- ‘top_level_group=my-company’이 올바른 Cell로 프록시됩니다.
마지막 단계 이후 /gitlab-org/gitlab
로 이동합니다
-
/gitlab-org
가 캐시에서 찾을 수 없기 때문에 분류되고 나중에 올바른 Cell로 이동될 것입니다.
성능 및 신뢰성 고려 사항
- 각 Cell이 모든 분할 키를 분류할 수 있는 것이 기대됩니다.
- 분류는 모든 필요한 데이터를 소유하는 경우 클러스터 전체 데이터 제공자에 의해 수행될 수도 있습니다.
- 게시된 라우팅 규칙을 통해 정적 기준을 정의할 수 있으며, 이를 통해 라우팅 결정을 비밀로 하는 것이 가능합니다. 결과적으로 라우팅 서비스는 요청 처리에 대한 지연시간을 추가하지 않으며 뛰어난 신뢰성을 제공합니다.
- 새로운 분할 키를 학습할 때 페널티가 예상됩니다. 그러나 분할 키의 기수가 낮아서 다층 캐시가 매우 높은 캐시 히트 비율을 제공할 것으로 기대됩니다. 분할 키는 사실상 리소스(조직, 그룹 또는 프로젝트)로 매핑되며, 이에는 한정된 수가 있습니다.
대안
요청 버퍼링
요청 버퍼링을 사용하는 상태 없는 라우터
는 Cell이 다른 Cell로 요청을 리디렉션하기 위해 X-Gitlab-Cell-Redirect
로 응답하는 방법을 설명합니다:
- 이는 매우 메모리 집약적인 전체 요청(헤더 + 본문)을 버퍼링해야 하는 필요에 기반합니다.
- 이 제안은 Cell의 혼합 배포를 다루는 쉬운 방법을 제공하지 않습니다. 여기서 Cell은 다른 버전을 실행할 수 있습니다.
- 이 제안은 요청에 기반하고 있기 때문에 디코딩된 분할 키보다 요청을 기반으로 하므로, 정보를 캐싱하는 데 훨씬 더 많은 정보가 필요합니다.
요청 학습
라우트 학습을 사용하는 상태 없는 라우터
는 이 문서와 유사한 접근 방식을 기술합니다. 그러나 라우트 규칙 및 분류는 미리 정의된 형태의 /api/v4/internal/cells/learn
으로 진단하는 방식입니다:
- 이는 라우트 학습을 전체적으로 동적으로 만들어 Cells의 가용성에 의존합니다.
- 이 제안은 Cell의 혼합 배포를 다루는 쉬운 방법을 제공하지 않습니다. 여기서 Cell은 다른 버전을 실행할 수 있습니다.
- 이 제안은 요청에 기반하고 있기 때문에 디코딩된 분할 키보다 요청을 기반으로 하므로, 정보를 캐싱하는 데 훨씬 더 많은 정보가 필요합니다.
FAQ
- 라우팅 서비스가 규칙 세트를 어떻게 컴파일하고 언제 수행합니까?
정의되지 않았습니다.