Google의 인프라는 대규모 확장으로 탄력적으로 작동하도록 설계되었습니다. 즉, 대부분의 레이어를 증가하는 트래픽 수요에 맞게 최대 규모까지 조정할 수 있습니다. 이를 가능하게 하는 핵심 디자인 패턴은 트래픽 패턴을 기반으로 동적으로 부하를 다시 할당하는 인프라 구성요소인 적응형 레이어입니다. 그러나 이렇게 조정하는 데는 시간이 필요합니다. Cloud Tasks를 사용 설정하면 매우 많은 양의 트래픽을 전달할 수 있으므로 인프라가 조정할 수 있는 속도보다 빠르게 트래픽이 증가하는 상황에서는 프로덕션이 위험에 노출될 수 있습니다.
개요
이 문서에서는 트래픽이 많은 큐에서 우수한 Cloud Tasks 성능을 유지할 수 있도록 권장사항의 가이드라인을 소개합니다. TPS가 많은 큐는 생성 또는 전달된 초당 태스크(TPS)가 500개 이상인 큐입니다. TPS가 많은 큐 그룹은 생성 또는 전달된 총 태스크가 최소 2,000개 이상인 큐의 서로 인접한 집합(예: [queue0001, queue0002, …, queue0099])입니다. 큐 또는 큐 그룹의 이전 TPS는 Stackdriver 측정항목, 'CreateTask' 태스크의 경우 api/request_count
, 태스크 시도의 경우 queue/task_attempt_count
를 사용하여 볼 수 있습니다. 트래픽이 많은 큐 및 큐 그룹은 다음 두 가지 광범위한 범주의 오류가 발생하기 쉽습니다.
큐 과부하는 개별 큐 또는 큐 그룹에 대한 태스크 생성과 태스크 전달이 큐 인프라가 조정할 수 있는 것보다 빠르게 증가할 때 발생합니다. 이와 유사하게 대상 과부하는 작업이 전달되는 비율이 다운스트림 대상 인프라에서 트래픽 급증을 야기할 때 발생합니다. 두 경우 모두 500/50/5 패턴을 따르는 것이 좋습니다. 즉, TPS가 500개 이상으로 확장될 때 5분마다 50% 이하로 트래픽을 늘립니다. 이 문서에서는 확장 위험을 야기할 수 있는 다양한 시나리오를 검토하여 이 패턴을 적용하는 방법을 예로 소개합니다.
큐 과부하
트래픽이 갑자기 증가할 때마다 큐 또는 큐 그룹이 과부하 상태가 될 수 있습니다. 따라서 이러한 큐에 다음 상황이 발생할 수 있습니다.
- 작업 생성 지연 시간 증가
- 작업 생성 오류율 증가
- 전달 비율 감소
이를 방지하기 위해 큐 또는 큐 그룹의 생성 및 전달 비율이 갑자기 급증할 수 있는 모든 상황에 대해 컨트롤을 설정하는 것이 좋습니다. 콜드 큐 또는 큐 그룹인 경우에는 최대 작업 수를 초당 500개로 제한하고 5분마다 50%씩 트래픽을 늘리는 것이 좋습니다. 이 증가 일정에 따르면 이론상으로 90분 후에는 초당 작업 수를 74만 개로 늘릴 수 있습니다. 이러한 상황이 발생할 수 있는 경우에는 여러 가지가 있습니다.
예를 들면 다음과 같습니다.
- Cloud Tasks 사용량이 많은 새로운 기능을 실행하는 경우
- 대기열 간에 트래픽을 이동하는 경우
- 큐 전반에서 트래픽을 재분산하는 경우
- 많은 수의 작업을 추가하는 배치 작업을 실행하는 경우
이러한 경우 500/50/5 패턴을 따르세요.
App Engine 트래픽 분할 사용
태스크가 App Engine 앱으로 생성된 경우 App Engine 트래픽 분할(표준/가변형)을 활용하여 트래픽 증가를 원활하게 처리할 수 있습니다. 버전(표준/가변형)에 따라 트래픽을 분할하면 속도 관리가 필요한 요청을 시간 경과에 따라 가동하여 큐 상태를 보호할 수 있습니다. 예를 들어 새로 확장된 큐 그룹으로 트래픽을 가동하는 경우를 고려해 보세요. [queue0000, queue0199]를 트래픽이 가장 많을 때 총 100,000개의 TPS를 수신하는 TPS가 많은 큐 시퀀스로 가정합니다.
[queue0200, queue0399]를 새 큐 시퀀스로 가정합니다. 모든 트래픽이 이동된 후 큐 시퀀스 수가 두 배가 되었고 새 큐 범위가 시퀀스의 총 트래픽의 50%를 수신합니다.
큐 수를 늘리는 버전을 배포할 때 트래픽 분할을 사용하여 트래픽을 먼저 새 버전으로 점진적으로 증가시켜 결과적으로 새 큐로 증가시키세요.
- 트래픽의 1%를 새 버전으로 이동하기 시작합니다. 예를 들어 100,000개 TPS의 1% 중 50%는 새 큐 세트에 500개의 TPS를 이동시킵니다.
- 다음 표에 설명된 것처럼 5분마다 새 버전에 전송되는 트래픽을 50%까지 늘립니다.
배포 시작 후 경과 시간(분) | 새 버전으로 이동된 총 트래픽 비율(%) | 새 큐에 대한 총 트래픽 비율(%) | 이전 큐에 대한 총 트래픽 비율(%) |
---|---|---|---|
0 | 1.0 | 0.5 | 99.5 |
5 | 1.5 | 0.75 | 99.25 |
10 | 2.3 | 1.15 | 98.85 |
15 | 3.4 | 1.7 | 98.3 |
20 | 5.1 | 2.55 | 97.45 |
25 | 7.6 | 3.8 | 96.2 |
30 | 11.4 | 5.7 | 94.3 |
35 | 17.1 | 8.55 | 91.45 |
40 | 25.6 | 12.8 | 87.2 |
45 | 38.4 | 19.2 | 80.8 |
50 | 57.7 | 28.85 | 71.15 |
55 | 86.5 | 43.25 | 56.75 |
60 | 100 | 50 | 50 |
출시로 인한 트래픽 급증
큐 또는 큐 그룹에 대한 트래픽을 크게 증가시키는 버전을 출시할 때 점진적 롤아웃이 이러한 증가를 원활하게 처리하는 중요한 메커니즘입니다. 초기 실행 시 새 큐에 대한 총 작업이 500개를 초과하지 않도록 인스턴스를 점진적으로 롤아웃하여 트래픽을 5분마다 50% 이하로 늘리세요.
TPS가 많은 새 큐 또는 큐 그룹
새로 만든 큐는 특히 취약합니다. 큐 그룹(예: [queue0000, queue0001, …, queue0199])은 초기 롤아웃 단계 동안 단일 큐만큼 중요합니다. 이러한 큐에는 점진적 롤아웃이 중요한 전략입니다. TPS가 많은 큐 또는 큐 그룹을 만드는 새로운 서비스 또는 업데이트된 서비스를 실행할 때 초기 부하가 TPS 500개 미만이고 5분 이상 간격을 두고 50% 이하로 증가하도록 단계적으로 실행하세요.
새로 확장된 큐 그룹
큐 그룹의 총 용량을 늘릴 때(예: [queue0000-queue0199에서 queue0000-queue0399]로 확장) 500/50/5 패턴을 따르세요. 롤아웃 절차의 경우 새 큐 그룹이 개별 큐과 다르지 않게 동작한다는 점에 유의해야 합니다. 그룹 내 개별 큐가 아니라 새 큐 그룹 전체에 500/50/5 패턴을 적용하세요. 이러한 큐 그룹 확장의 경우, 점진적 롤아웃이 중요한 전략입니다. 트래픽 소스가 App Engine인 경우 트래픽 분할을 사용할 수 있습니다(출시로 인한 트래픽 급증 참조). 서비스를 이전하여 태스크를 증가된 수의 큐에 추가할 때 초기 실행 시 새 큐에 대한 총 작업이 500개를 초과하지 않도록 하고 트래픽을 5분마다 50% 이하로 늘려 인스턴스를 점진적으로 롤아웃하세요.
긴급 큐 그룹 확장
경우에 따라 큐 그룹이 작업을 전달하는 것보다 더 빠른 속도로 작업이 큐 그룹에 추가될 것으로 예상되므로 기존 큐 그룹을 확장할 수 있습니다. 사전 순으로 정렬될 때 새 큐의 이름이 기존 큐 이름 사이에 균등하게 분산되는 경우, 인터리브 처리된 새 큐가 50% 미만이고 각 큐의 트래픽이 TPS 500개 미만이면 트래픽을 즉시 큐에 전송할 수 있습니다. 이 방법은 위 섹션의 설명대로 트래픽 분할 및 점진적 롤아웃 대신 사용됩니다.
이러한 유형의 인터리브 처리된 큐의 이름은 짝수로 끝나는 큐에 서픽스를 추가하는 방식으로 지정할 수 있습니다. 예를 들어 기존 큐가 [queue0000-queue0199]으로 200개이고 100개의 새 큐를 만들려는 경우 [queue0200-queue0299] 대신 [queue0000a, queue0002a, queue0004a, …, queue0198a]를 새 큐 이름으로 선택합니다.
추가로 늘려야 하는 경우 5분마다 최대 50% 이상의 큐를 인터리브 처리할 수 있습니다.
작업을 대규모/일괄로 큐에 추가
많은 수의 작업, 예를 들어 수백만, 수십억 개의 작업을 추가해야 하는 경우 이중 삽입 패턴이 유용할 수 있습니다. 단일 작업에서 작업을 만드는 대신 인젝터 큐를 사용하세요. 인젝터 큐에 추가된 각 작업은 팬아웃 처리되고 100개의 작업을 원하는 큐 또는 큐 그룹에 추가합니다. 인젝터 큐는 시간 경과에 따라 속도가 빨라질 수 있습니다. 예를 들어 TPS 5개로 시작한 다음 5분마다 50%씩 늘릴 수 있습니다.
이름이 지정된 작업
새 작업을 만들 때 Cloud Tasks는 기본적으로 작업에 고유한 이름을 할당합니다. name 매개변수를 사용하면 작업 이름을 직접 할당할 수 있습니다. 그러나 이렇게 하면 상당한 성능 오버헤드를 유발하며, 이에 따라 지연 시간이 증가하고 명명된 작업과 관련하여 오류율이 상승할 수 있습니다. 작업 이름이 타임스탬프처럼 순차적으로 지정되는 경우에는 이러한 비용이 대폭 증가할 수 있습니다. 따라서 이름을 직접 할당할 때는 작업 이름에 콘텐츠의 해시와 같이 고르게 분산되는 프리픽스를 사용하는 것이 좋습니다. 작업 이름 지정에 대한 자세한 내용은 문서를 참조하세요.
대상 과부하
큐에서의 전달이 단시간에 급증하는 경우 Cloud Tasks는 App Engine, Datastore, 네트워크 사용량 등 사용 중인 다른 서비스에 과부하를 유발할 수 있습니다. 작업의 백로그가 누적된 경우 큐의 일시중지를 해제하면 일시적으로 서비스에 과부하가 걸릴 수 있습니다. 이를 방지하기 위해서는 큐 과부하에 제안된 것과 동일한 500/50/5 패턴을 사용하는 것입니다. 즉, 큐가 TPS 500개 이상을 전달하는 경우 큐에 의해 트리거된 트래픽을 5분마다 50% 이하로 늘립니다. Stackdriver 측정지표를 사용하여 트래픽 증가를 사전에 모니터링하세요. Stackdriver 알림을 사용하여 잠재적으로 위험한 상황을 감지할 수 있습니다.
TPS가 많은 큐의 일시중지 해지 또는 다시 시작
큐 또는 일련의 큐가 일시중지가 해제되거나 다시 사용 설정된 경우, 큐가 전달을 다시 시작합니다. 큐에 태스크가 많이 있는 경우, 새로 사용 설정된 큐의 전달 비율이 TPS 0개에서 큐의 전체 용량으로 대폭 증가할 수 있습니다. 증가시키려면 시차를 두고 큐를 다시 시작하거나 Cloud Tasks의 maxDispatchesPerSecond
를 사용하여 큐 전달 비율을 조정합니다.
예약된 일괄 작업
동시에 전달하도록 예약된 작업 수가 많은 경우에도 대상 과부하의 위험을 초래할 수 있습니다. 한번에 많은 수의 작업을 시작해야 하는 경우 큐 비율 제어를 사용하여 전달 비율을 점진적으로 늘리거나 사전에 대상 용량을 명시적으로 늘리는 방법을 고려하세요.
팬아웃 처리 증가
Cloud Tasks를 통해 실행되는 서비스를 업데이트할 때 원격 호출 수를 늘리면 프로덕션에 위험이 발생할 수 있습니다. 예를 들어 TPS가 많은 큐의 태스크가 핸들러 /task-foo
를 호출한다고 가정해 봅시다. 새 출시 버전에서 비용이 많이 드는 여러 Datastore 호출을 핸들러에 추가하는 경우 /task-foo
를 호출하는 비용이 크게 증가할 수 있습니다. 이러한 출시 버전을 사용하면 사용자 트래픽 변화와 즉시 관련이 있는 Datastore 트래픽이 대폭 증가할 수 있습니다. 점진적 롤아웃 또는 트래픽 분할을 사용하여 갑작스런 증가를 관리하세요.
재시도
Cloud Tasks API를 호출할 때 실패 시 코드가 재시도할 수 있습니다. 그러나 서버 측 오류로 인해 상당 부분의 요청이 실패하는 경우 높은 비율의 재시도가 큐에 과부하를 발생시킬 수 있고 복구 속도를 저하시킬 수 있습니다. 따라서 서버 측 오류로 인해 클라이언트가 상당 부분의 요청이 실패한 것으로 감지하는 경우, 사이트 안정성 엔지니어링 도서의 과부하 처리 장에 설명된 적응형 제한 알고리즘 사용과 같이 나가는 트래픽의 상한을 설정하는 것이 좋습니다. Google의 gRPC 클라이언트 라이브러리는 이 알고리즘 변이를 구현합니다.