API 우선순위와 공정성

API 우선순위와 공정성 (API Priority and Fairness)

과부하 상황에서 쿠버네티스 API 서버의 동작을 제어하는 것은 클러스터 관리자의 핵심 작업이에요. kube-apiserver 에는 인바운드 요청의 홍수로부터 API 서버가 과부하되거나 잠재적으로 충돌하지 않도록, 수락될 미해결(outstanding) 작업의 양을 제한하는 일부 제어(--max-requests-inflight--max-mutating-requests-inflight 명령줄 플래그)가 있어요. 하지만 이 플래그들만으로는 트래픽이 많을 때 가장 중요한 요청이 통과되도록 보장하기에 충분하지 않아요.

API 우선순위와 공정성(APF) 기능은 앞서 언급한 최대 처리 중(맥스 인플라이트) 제한을 개선하는 대안이에요. APF는 요청을 더 세밀한 방식으로 분류하고 격리해요. 또한 제한된 양의 대기열(queueing)을 도입해 아주 짧은 버스트의 경우 요청이 거부되지 않도록 해요. 요청은 공정 대기열(fair queuing) 기법을 사용해 대기열에서 처리되므로, 예를 들어 잘못된 동작을 하는 컨트롤러 가 (같은 우선순위 수준에서도) 다른 것들을 기아 상태로 만들 필요가 없어요.

이 기능은 인포머(informer)를 사용하고 API 요청 실패에 지수 백오프(exponential back-off)로 대응하는 표준 컨트롤러와, 이렇게 작동하는 다른 클라이언트와 잘 작동하도록 설계되었어요.

출처: 문서

본문

API 우선순위와 공정성 활성화/비활성화

API 우선순위와 공정성 기능은 명령줄 플래그로 제어되며 기본적으로 활성화돼 있어요. 사용 가능한 kube-apiserver 명령줄 옵션과 활성화·비활성화 방법에 대한 일반적인 설명은 Options 를 참고해요. APF의 명령줄 옵션 이름은 --enable-priority-and-fairness 예요. 이 기능은 또한 다음을 가진 API Group 을 포함해요: (a) 1.29에서 도입되어 기본적으로 활성화된 안정적인 v1 버전, (b) 기본적으로 활성화되고 v1.29에서 deprecated된 v1beta3 버전. kube-apiserver 호출에 다음 명령줄 플래그를 추가해 API 그룹 베타 버전 v1beta3 을 비활성화할 수 있어요:

kube-apiserver \
--runtime-config=flowcontrol.apiserver.k8s.io/v1beta3=false \
 # …and other flags as usual

--enable-priority-and-fairness=false 명령줄 플래그는 API 우선순위와 공정성 기능을 비활성화할 거예요.

재귀 서버 시나리오

API 우선순위와 공정성은 재귀 서버 시나리오에서 주의해서 사용해야 해요. 이는 어떤 서버 A가 요청을 처리하는 동안 서버 B로 보조 요청(subsidiary request)을 발행하는 시나리오예요. 서버 B가 다시 서버 A로 추가 보조 호출을 할 수도 있어요. 우선순위와 공정성 제어가 원래 요청과 일부 보조 요청 모두에 적용되는 상황에서는 재귀가 아무리 깊어도 우선순위 역전(priority inversion) 및/또는 교착 상태(deadlock)의 위험이 있어요.

재귀의 한 예는 kube-apiserver 가 서버 B로 admission 웹훅 호출을 발행하고, 그 호출을 처리하는 동안 서버 B가 kube-apiserver 로 다시 추가 보조 요청을 하는 경우예요. 또 다른 재귀 예는 APIService 객체가 kube-apiserver 에 특정 API 그룹에 대한 요청을 커스텀 외부 서버 B로 위임하도록 지시하는 경우("애그리게이션" 이라고 불리는 것 중 하나)예요.

원래 요청이 특정 우선순위 수준에 속하는 것으로 알려지고 보조 제어 요청이 더 높은 우선순위 수준으로 분류될 때 이것이 한 가지 가능한 해결책이에요. 원래 요청이 어떤 우선순위 수준에도 속할 수 있다면 보조 제어 요청은 우선순위와 공정성 제한에서 면제되어야 해요. 그렇게 하는 한 방법은 아래에서 논의되는 분류와 처리를 구성하는 객체를 사용하는 것이에요. 또 다른 방법은 위에서 논의한 기법을 사용해 서버 B의 우선순위와 공정성을 완전히 비활성화하는 것이에요. 세 번째 방법은 서버 B가 kube-apiserver 가 아닐 때 사용하기 가장 간단한 것으로, 코드에서 우선순위와 공정성을 비활성화한 상태로 서버 B를 빌드하는 거예요.

개념 (Concepts)

API 우선순위와 공정성 기능에는 여러 개별 기능이 포함돼 있어요. 인바운드 요청은 FlowSchema 를 사용해 요청의 속성으로 분류되고 우선순위 수준에 할당돼요. 우선순위 수준은 별도의 동시성 한도를 유지해 격리 수준을 더해 주므로, 서로 다른 우선순위 수준에 할당된 요청이 서로를 기아 상태로 만들 수 없어요. 우선순위 수준 내에서 공정 대기열 알고리즘은 서로 다른 흐름(flow) 의 요청이 서로 기아 상태가 되는 것을 방지하고, 평균 부하가 허용 가능할 정도로 낮을 때 버스티 트래픽이 요청 실패를 유발하지 않도록 요청을 대기열에 넣을 수 있게 해줘요.

우선순위 수준 (Priority Levels)

APF가 활성화되지 않은 상태에서 API 서버의 전체 동시성은 kube-apiserver 플래그 --max-requests-inflight--max-mutating-requests-inflight 에 의해 제한돼요. APF가 활성화되면 이 플래그들로 정의된 동시성 한도가 합산된 다음 그 합이 구성 가능한 우선순위 수준 집합에 나누어져요. 각 인바운드 요청은 단일 우선순위 수준에 할당되고, 각 우선순위 수준은 특정 한도가 허용하는 만큼만 동시 요청을 처리해요.

예를 들어 기본 구성에는 리더 선출(leader election) 요청, 내장 컨트롤러의 요청, 파드의 요청을 위한 별도의 우선순위 수준이 포함돼 있어요. 이는 API 서버에 요청을 홍수로 보내는 잘못된 동작의 파드가 리더 선출이나 내장 컨트롤러의 작업이 성공하는 것을 막을 수 없음을 의미해요.

우선순위 수준의 동시성 한도는 주기적으로 조정되어, 사용률이 낮은 우선순위 수준이 사용률이 높은 수준에 일시적으로 동시성을 빌려줄 수 있어요. 이 한도는 아래에서 언급되는 구성 객체에서 파생된 명목 한도와 우선순위 수준이 빌려줄 수 있고 빌릴 수 있는 동시성의 경계에 기반해요.

요청이 점유하는 좌석 (Seats Occupied by a Request)

위의 동시성 관리 설명은 기본 스토리지예요. 요청은 기간이 서로 다르지만 우선순위 수준의 동시성 한도와 비교할 때 주어진 순간에는 동일하게 계산돼요. 기본 스토리지에서 각 요청은 동시성 한 단위를 점유해요. "좌석(seat)" 이라는 단어는 동시성 한 단위를 의미하는 데 사용되며, 기차나 비행기의 각 승객이 고정 공급된 좌석 중 하나를 차지하는 방식에서 영감을 받았어요.

하지만 일부 요청은 둘 이상의 좌석을 차지해요. 그중 일부는 서버가 많은 수의 객체를 반환할 것으로 추정하는 list 요청이에요. 이 요청들은 서버에 특히 무거운 부담을 주는 것으로 밝혀졌어요. 이런 이유로 서버는 반환될 객체 수를 추정하고 해당 추정 수에 비례하는 수의 좌석을 차지하는 것으로 요청을 간주해요.

watch 요청에 대한 실행 시간 조정

API 우선순위와 공정성은 watch 요청을 관리하지만, 이것은 기본 동작에서 몇 가지 더 벗어남을 수반해요. 첫 번째는 watch 요청이 좌석을 차지하는 것으로 간주되는 기간에 관한 것이에요. 요청 매개변수에 따라 watch 요청에 대한 응답은 관련 기존 객체 모두에 대한 create 알림으로 시작될 수도 있고 아닐 수도 있어요. API 우선순위와 공정성은 초기 알림 버스트(있는 경우)가 끝나면 watch 요청이 좌석을 사용한 것으로 간주해요.

일반 알림은 서버가 객체 생성/업데이트/삭제를 통보받을 때마다 관련 watch 응답 스트림 모두에 동시 버스트로 전송돼요. 이 작업을 설명하기 위해 API 우선순위와 공정성은 모든 쓰기 요청이 실제 쓰기가 끝난 후 좌석을 차지하는 추가 시간을 보내는 것으로 간주해요. 서버는 전송될 알림 수를 추정하고 쓰기 요청의 좌석 수와 좌석 점유 시간을 이 추가 작업을 포함하도록 조정해요.

대기열 (Queuing)

우선순위 수준 내에서도 많은 수의 서로 다른 트래픽 소스가 있을 수 있어요. 과부하 상황에서 하나의 요청 스트림이 다른 것들을 기아 상태로 만들지 못하게 하는 것이 중요해요(특히 단일 버그 클라이언트가 kube-apiserver에 요청을 홍수로 보내는 비교적 흔한 경우, 그 버그 클라이언트는 다른 클라이언트에 측정 가능한 영향을 거의 주지 않는 것이 이상적이에요). 이것은 같은 우선순위 수준에 할당된 요청을 처리하는 데 공정 대기열 알고리즘을 사용해 처리돼요. 각 요청은 일치하는 FlowSchema 이름과 흐름 구분자(flow distinguisher) — 요청하는 사용자, 대상 리소스의 네임스페이스, 또는 아무것도 아닌 것 중 하나 — 로 식별되는 흐름 에 할당되고, 시스템은 같은 우선순위 수준의 서로 다른 흐름의 요청에 대략 동일한 가중치를 주려고 해요. 많은 인스턴스가 있는 컨트롤러는 서로 다른 인스턴스를 서로 다르게 처리할 수 있도록 서로 다른 사용자 이름으로 인증해야 해요.

요청을 흐름으로 분류한 후 API 우선순위와 공정성 기능은 요청을 대기열에 할당할 수 있어요. 이 할당은 셔플 샤딩(shuffle sharding) 으로 알려진 기법을 사용하는데, 이는 대기열을 비교적 효율적으로 사용해 저강도 흐름을 고강도 흐름으로부터 절연해요.

대기열 알고리즘의 세부 사항은 각 우선순위 수준에 대해 조정 가능하며, 관리자가 메모리 사용, 공정성(총 트래픽이 용량을 초과할 때 독립적인 흐름이 모두 진행될 것이라는 속성), 버스티 트래픽에 대한 허용, 대기열로 인해 추가되는 지연 사이에서 트레이드오프할 수 있게 해줘요.

면제 요청 (Exempt requests)

일부 요청은 이 기능이 부과하는 제한에 전혀 적용되지 않을 만큼 충분히 중요하다고 간주돼요. 이러한 면제는 잘못 구성된 흐름 제어 구성이 API 서버를 완전히 비활성화하는 것을 방지해요.

리소스 (Resources)

흐름 제어 API는 두 종류의 리소스를 포함해요. PriorityLevelConfiguration 은 사용 가능한 우선순위 수준, 각 수준이 처리할 수 있는 사용 가능한 동시성 예산의 몫을 정의하고, 대기열 동작을 미세 조정할 수 있게 해줘요. FlowSchema 는 개별 인바운드 요청을 분류해 각각을 단일 PriorityLevelConfiguration에 일치시키는 데 사용돼요.

PriorityLevelConfiguration

PriorityLevelConfiguration은 단일 우선순위 수준을 나타내요. 각 PriorityLevelConfiguration은 미해결 요청 수에 대한 독립적인 한도와 대기열 요청 수에 대한 제한을 가져요.

PriorityLevelConfiguration의 명목 동시성 한도는 절대 좌석 수로 지정되지 않고 "명목 동시성 몫(nominal concurrency shares)" 으로 지정돼요. API 서버의 총 동시성 한도는 기존 PriorityLevelConfiguration들에 이 몫에 비례해 분배되어 각 수준에 좌석 기준 명목 한도를 줘요. 이를 통해 클러스터 관리자는 --max-requests-inflight(또는 --max-mutating-requests-inflight) 의 다른 값으로 kube-apiserver 를 재시작해 서버로의 총 트래픽 양을 확장·축소할 수 있고, 모든 PriorityLevelConfiguration은 허용된 최대 동시성이 같은 분율만큼 증가(또는 감소)하는 것을 볼 수 있어요.

우선순위 수준이 빌려줄 수 있고 빌릴 수 있는 동시성의 경계는 PriorityLevelConfiguration에서 수준의 명목 한도의 백분율로 표현돼요. 이것들은 명목 한도와 곱하고 / 100.0 반올림해 절대 좌석 수로 해석돼요. 우선순위 수준의 동적으로 조정된 동시성 한도는 (a) 명목 한도에서 대여 가능한 좌석을 뺀 하한과 (b) 명목 한도에 빌릴 수 있는 좌석을 더한 상한 사이에 제약돼요. 각 조정에서 동적 한도는 각 우선순위 수준이 최근에 수요가 나타난 대여 좌석을 되찾은 다음 방금 설명한 경계 내에서 우선순위 수준의 최근 좌석 수요에 공동으로 공정하게 대응함으로써 파생돼요.

단일 PriorityLevelConfiguration에 할당된 인바운드 요청의 양이 허용된 동시성 수준보다 많을 때 사양의 type 필드가 추가 요청에 일어날 일을 결정해요. Reject 유형은 초과 트래픽이 즉시 HTTP 429(Too Many Requests) 오류로 거부됨을 의미해요. Queue 유형은 임계값 이상의 요청이 대기열에 들어가고, 셔플 샤딩과 공정 대기열 기법이 요청 흐름 간 진행을 균형 있게 하는 데 사용됨을 의미해요.

대기열 구성은 우선순위 수준에 대한 공정 대기열 알고리즘을 조정할 수 있게 해줘요. 알고리즘의 세부 사항은 enhancement proposal 에서 읽을 수 있지만, 간단히 말하면:

다음은 흥미로운 셔플 샤딩 구성 모음과, 각각에 대해 예시적인 코끼리(고강도 흐름) 수에 대해 주어진 쥐(저강도 흐름)가 코끼리들에게 짓눌릴 확률을 보여주는 테이블이에요. 이 테이블을 계산하는 https://play.golang.org/p/Gi0PLgVHiUg 을 참고해요.

HandSize Queues 1 elephant 4 elephants 16 elephants
12 32 4.428838398950118e-09 0.11431348830099144 0.9935089607656024
10 32 1.550093439632541e-08 0.0626479840223545 0.9753101519027554
10 64 6.601827268370426e-12 0.00045571320990370776 0.49999929150089345
9 64 3.6310049976037345e-11 0.00045501212304112273 0.4282314876454858
8 64 2.25929199850899e-10 0.0004886697053040446 0.35935114681123076
8 128 6.994461389026097e-13 3.4055790161620863e-06 0.02746173137155063
7 128 1.0579122850901972e-11 6.960839379258192e-06 0.02406157386340147
7 256 7.597695465552631e-14 6.728547142019406e-08 0.0006709661542533682
6 256 2.7134626662687968e-12 2.9516464018476436e-07 0.0008895654642000348
6 512 4.116062922897309e-14 4.982983350480894e-09 2.26025764343413e-05
6 1024 6.337324016514285e-16 8.09060164312957e-11 4.517408062903668e-07

FlowSchema

FlowSchema는 일부 인바운드 요청을 일치시키고 우선순위 수준에 할당해요. 모든 인바운드 요청은 수치적으로 가장 낮은 matchingPrecedence 를 가진 것부터 시작해 위로 올라가며 FlowSchema에 대해 테스트돼요. 첫 번째 일치가 이겨요.

FlowSchema는 rules 중 적어도 하나가 일치하면 주어진 요청과 일치해요. 규칙은 subjects 중 적어도 하나 그리고 resourceRules 또는 nonResourceRules(인바운드 요청이 리소스 또는 비리소스 URL인지에 따라) 중 적어도 하나가 요청과 일치하면 일치해요.

subjects의 name 필드와 리소스 및 비리소스 규칙의 verbs, apiGroups, resources, namespaces, nonResourceURLs 필드에 대해 와일드카드 * 가 지정될 수 있어 주어진 필드의 모든 값과 일치하고, 사실상 고려에서 제거돼요.

FlowSchema의 distinguisherMethod.type 은 해당 스키마와 일치하는 요청이 흐름으로 분리되는 방식을 결정해요. ByUser 일 수 있는데, 하나의 요청 사용자가 다른 사용자의 용량을 기아 상태로 만들 수 없는 것이에요. ByNamespace 일 수 있는데, 한 네임스페이스의 리소스 요청이 다른 네임스페이스의 리소스 요청의 용량을 기아 상태로 만들 수 없는 것이에요. 또는 비어 있거나(distinguisherMethod 가 완전히 생략될 수도 있음) 이 FlowSchema와 일치하는 모든 요청이 단일 흐름의 일부로 간주될 수 있어요. 주어진 FlowSchema의 올바른 선택은 리소스와 특정 환경에 따라 달라져요.

기본값 (Defaults)

각 kube-apiserver는 필수(mandatory)와 권장(suggested) 두 종류의 APF 구성 객체를 유지해요.

필수 구성 객체 (Mandatory Configuration Objects)

네 개의 필수 구성 객체는 고정된 내장 가드레일(guardrail) 동작을 반영해요. 이것은 서버가 이 객체가 존재하기 전에 갖는 동작이며, 객체가 존재할 때 그 사양은 이 동작을 반영해요. 네 개의 필수 객체는 다음과 같아요.

권장 구성 객체 (Suggested Configuration Objects)

권장 FlowSchema와 PriorityLevelConfiguration은 합리적인 기본 구성을 구성해요. 원하면 이것들을 수정하거나 추가 구성 객체를 만들 수 있어요. 클러스터가 과부하를 경험할 가능성이 있다면 어떤 구성이 가장 잘 작동할지 고려해야 해요.

권장 구성은 요청을 6개의 우선순위 수준으로 그룹화해요:

권장 FlowSchema는 요청을 위의 우선순위 수준으로 안내하는 역할을 하며 여기서 열거되지 않아요.

필수 및 권장 구성 객체의 유지 관리

kube-apiserver 는 초기 및 주기적 동작을 사용해 필수 및 권장 구성 객체를 독립적으로 유지해요. 따라서 서로 다른 버전의 서버가 혼합된 상황에서는 서로 다른 서버가 이 객체의 적절한 내용에 대해 서로 다른 의견을 갖는 한 쿵쾅거림(thrashing)이 있을 수 있어요.

kube-apiserver 는 필수 및 권장 구성 객체에 대해 초기 유지 관리 패스를 수행하고, 그 후 이 객체의 주기적 유지 관리(1분마다)를 수행해요.

필수 구성 객체의 경우 유지 관리는 객체가 존재하고, 존재한다면 적절한 사양을 갖도록 보장하는 것으로 구성돼요. 서버는 서버의 가드레일 동작과 일치하지 않는 사양을 가진 생성이나 업데이트를 거부해요.

권장 구성 객체의 유지 관리는 사양이 재정의될 수 있도록 설계돼요. 반면 삭제는 존중되지 않아요: 유지 관리가 객체를 복원할 거예요. 권장 구성 객체를 원하지 않는다면 그것을 유지하되 사양을 최소한의 결과를 갖도록 설정해야 해요. 권장 객체의 유지 관리는 또한 kube-apiserver 의 새 버전이 배포될 때 자동 마이그레이션을 지원하도록 설계돼요. 다만 서버의 혼합 인구가 있는 동안 잠재적으로 쿵쾅거림이 있을 수 있어요.

권장 구성 객체의 유지 관리는 객체가 존재하지 않으면 서버의 권장 사양으로 생성하는 것으로 구성돼요. 반면 객체가 이미 존재하면 유지 관리 동작은 kube-apiservers 또는 사용자가 객체를 제어하는지에 따라 달라져요. 전자의 경우 서버는 객체의 사양이 서버가 권장하는 것임을 보장해요. 후자의 경우 사양은 그대로 둬요.

누가 객체를 제어하는지에 대한 질문은 먼저 키 apf.kubernetes.io/autoupdate-spec 을 가진 어노테이션을 찾아 답해져요. 그런 어노테이션이 있고 값이 true 면 kube-apiservers가 객체를 제어해요. 그런 어노테이션이 있고 값이 false 면 사용자가 객체를 제어해요. 두 조건 중 어느 것도 성립하지 않으면 객체의 metadata.generation 이 상의돼요. 그것이 1이면 kube-apiservers가 객체를 제어해요. 그 외에는 사용자가 객체를 제어해요. 이 규칙은 릴리스 1.22에서 도입되었고 metadata.generation 의 고려는 더 단순한 이전 동작으로부터의 마이그레이션을 위한 것이에요. 권장 구성 객체를 제어하려는 사용자는 apf.kubernetes.io/autoupdate-spec 어노테이션을 false 로 설정해야 해요.

필수 또는 권장 구성 객체의 유지 관리는 또한 kube-apiservers가 객체를 제어하는지 여부를 정확히 반영하는 apf.kubernetes.io/autoupdate-spec 어노테이션이 있는지 보장하는 것을 포함해요.

유지 관리는 또한 필수도 권장도 아니지만 apf.kubernetes.io/autoupdate-spec=true 로 어노테이션된 객체를 삭제하는 것을 포함해요.

헬스 체크 동시성 면제

권장 구성은 보안 포트를 사용하지만 자격 증명을 제공하지 않는 경향이 있는, 로컬 kubelet의 kube-apiserver 헬스 체크 요청에 특별한 처리를 주지 않아요. 권장 구성으로 이 요청들은 global-default FlowSchema와 해당 global-default 우선순위 수준에 할당되며, 다른 트래픽이 그들을 밀어낼 수 있어요.

다음 추가 FlowSchema를 추가하면 이 요청들을 속도 제한에서 면제해요.

apiVersion: flowcontrol.apiserver.k8s.io/v1
kind: FlowSchema
metadata:
  name: health-for-strangers
spec:
  matchingPrecedence: 1000
  priorityLevelConfiguration:
    name: exempt
  rules:
    - nonResourceRules:
      - nonResourceURLs:
          - "/healthz"
          - "/livez"
          - "/readyz"
        verbs:
          - "*"
      subjects:
        - kind: Group
          group:
            name: "system:unauthenticated"

관측성 (Observability)

메트릭 (Metrics)

API 우선순위와 공정성 기능을 활성화하면 kube-apiserver는 추가 메트릭을 내보내요. 이를 모니터링하면 구성이 중요한 트래픽을 부적절하게 제한하고 있는지 확인하거나 시스템 상태를 해칠 수 있는 잘못된 동작의 워크로드를 찾는 데 도움이 될 수 있어요.

API 우선순위와 공정성 사용을 위한 모범 사례

주어진 우선순위 수준이 허용된 동시성을 초과하면 요청은 증가된 지연을 경험하거나 HTTP 429(Too Many Requests) 오류로 드롭될 수 있어요. APF의 이러한 부작용을 방지하려면 요청을 처리할 충분한 좌석이 있도록 워크로드를 수정하거나 APF 설정을 조정할 수 있어요.

요청이 APF로 인해 거부되고 있는지 감지하려면 다음 메트릭을 확인해요:

  • apiserver_flowcontrol_rejected_requests_total: FlowSchema와 PriorityLevelConfiguration별로 거부된 총 요청 수.
  • apiserver_flowcontrol_current_inqueue_requests: FlowSchema와 PriorityLevelConfiguration별로 대기열에 있는 현재 요청 수.
  • apiserver_flowcontrol_request_wait_duration_seconds: 대기열에서 기다리는 요청에 추가된 지연.
  • apiserver_flowcontrol_priority_level_seat_utilization: PriorityLevelConfiguration별 좌석 사용률.

워크로드 수정

APF로 인한 요청 대기열·지연 추가·드롭을 방지하려면 요청을 최적화할 수 있어요:

  • 요청이 실행되는 속도를 줄여요. 고정 기간 동안 더 적은 수의 요청은 주어진 시간에 필요한 좌석 수를 줄일 거예요.
  • 많은 수의 비싼(expensive) 요청을 동시에 발행하지 않도록 해요. 요청은 더 적은 좌석을 사용하거나 더 낮은 지연을 갖도록 최적화될 수 있어 이 요청들이 좌석을 더 짧은 기간 보유하도록 해요. list 요청은 요청 중 가져오는 객체 수에 따라 1개 이상의 좌석을 차지할 수 있어요. 예를 들어 페이지네이션을 사용해 list 요청에서 가져오는 객체 수를 제한하면 더 짧은 기간 동안 총 좌석을 덜 사용할 거예요. 또한 list 요청을 watch 요청으로 교체하면 watch 요청은 초기 알림 버스트 동안에만 1개의 좌석을 차지하므로 총 동시성 몫이 더 낮아질 거예요. 1.27 이상 버전에서 스트리밍 리스트를 사용하는 경우 컬렉션의 전체 상태가 스트리밍되어야 하므로 watch 요청은 초기 알림 버스트 동안 list 요청과 같은 수의 좌석을 차지할 거예요. 두 경우 모두 watch 요청은 이 초기 단계 이후에는 좌석을 보유하지 않는다는 점을 유의해요.

APF로부터의 대기열 또는 거부 요청은 요청 수의 증가 또는 기존 요청의 지연 증가에 의해 유발될 수 있다는 점을 명심해요. 예를 들어 보통 1초가 걸리던 요청이 60초가 걸리기 시작하면, 이 지연 증가로 인해 요청이 평소보다 더 긴 기간 좌석을 점유하므로 APF가 요청을 거부하기 시작할 수 있어요. 워크로드의 큰 변화 없이 APF가 여러 우선순위 수준에서 요청을 거부하기 시작한다면 워크로드나 APF 설정이 아니라 컨트롤 플레인 성능에 근본적인 문제가 있을 가능성이 있어요.

우선순위와 공정성 설정

기본 FlowSchema와 PriorityLevelConfiguration 객체를 수정하거나 이 유형의 새 객체를 만들어 워크로드를 더 잘 수용할 수 있어요.

APF 설정은 다음을 위해 수정될 수 있어요:

  • 높은 우선순위 요청에 더 많은 좌석을 제공.
  • 다른 흐름과 공유된다면 동시성 수준을 기아 상태로 만들 비필수적이거나 비싼 요청을 격리.
높은 우선순위 요청에 더 많은 좌석 제공
  • 가능하다면 특정 kube-apiserver 의 모든 우선순위 수준에 걸쳐 사용 가능한 좌석 수는 max-requests-inflightmax-mutating-requests-inflight 플래그 값을 늘려 증가시킬 수 있어요. 또는 kube-apiserver 인스턴스 수를 수평으로 확장하면 충분한 요청 로드 밸런싱이 있다고 가정할 때 클러스터 전체에 걸쳐 우선순위 수준당 총 동시성을 증가시킬 거예요.
  • 더 큰 동시성 수준을 가진 PriorityLevelConfiguration을 참조하는 새 FlowSchema를 만들 수 있어요. 이 새 PriorityLevelConfiguration은 기존 수준이거나 자체 명목 동시성 몫 집합을 가진 새 수준일 수 있어요. 예를 들어 새 FlowSchema를 도입해 요청의 PriorityLevelConfiguration을 global-default에서 workload-low로 변경해 사용자에게 사용 가능한 좌석 수를 늘릴 수 있어요. 새 PriorityLevelConfiguration을 만들면 기존 수준에 지정된 좌석 수가 줄어들어요. 기본 FlowSchema나 PriorityLevelConfiguration을 편집하려면 apf.kubernetes.io/autoupdate-spec 어노테이션을 false로 설정해야 한다는 것을 기억해요.
  • 높은 우선순위 요청을 처리하는 PriorityLevelConfiguration의 NominalConcurrencyShares를 증가시킬 수도 있어요. 또는 1.26 이상 버전에서는 경쟁 우선순위 수준의 LendablePercent를 증가시켜 주어진 우선순위 수준이 빌릴 수 있는 더 높은 좌석 풀을 갖도록 할 수 있어요.
비필수 요청을 격리해 다른 흐름이 기아 상태가 되지 않게 하기

요청 격리를 위해 subject가 이 요청을 하는 사용자와 일치하는 FlowSchema를 만들거나 요청이 무엇인지(즉 resourceRules에 해당) 일치하는 FlowSchema를 만들 수 있어요. 다음으로 이 FlowSchema를 낮은 좌석 몫을 가진 PriorityLevelConfiguration에 매핑할 수 있어요.

예를 들어 default 네임스페이스에서 실행되는 파드의 list event 요청이 각각 10개의 좌석을 사용하고 1분 동안 실행된다고 가정해 보세요. 이 비싼 요청이 기존 service-accounts FlowSchema를 사용하는 다른 파드의 요청에 영향을 주는 것을 방지하려면 다음 FlowSchema를 적용해 이 list 호출을 다른 요청으로부터 격리할 수 있어요.

list event 요청을 격리하는 예시 FlowSchema 객체:

apiVersion: flowcontrol.apiserver.k8s.io/v1
kind: FlowSchema
metadata:
  name: list-events-default-service-account
spec:
  distinguisherMethod:
    type: ByUser
  matchingPrecedence: 8000
  priorityLevelConfiguration:
    name: catch-all
  rules:
    - resourceRules:
      - apiGroups:
          - '*'
        namespaces:
          - default
        resources:
          - events
        verbs:
          - list
      subjects:
        - kind: ServiceAccount
          serviceAccount:
            name: default
            namespace: default
  • 이 FlowSchema는 default 네임스페이스의 기본 서비스 어카운트가 수행하는 모든 list event 호출을 캡처해요. 일치 우선순위 8000은 기존 service-accounts FlowSchema가 사용하는 9000보다 낮으므로 이 list event 호출은 service-accounts가 아니라 list-events-default-service-account와 일치할 거예요.
  • catch-all PriorityLevelConfiguration은 이러한 요청을 격리하는 데 사용돼요. catch-all 우선순위 수준은 매우 작은 동시성 몫을 가지며 요청을 대기열에 넣지 않아요.

더 알아보기 (Learn more)

  • 흐름 제어 참조 문서 에서 문제 해결에 대해 더 자세히 알아볼 수 있어요.
  • API 우선순위와 공정성의 설계 세부 사항에 대한 배경 정보는 enhancement proposal 을 참고해요.
  • 제안과 기능 요청은 SIG API Machinery 나 기능의 slack channel 을 통해 할 수 있어요.