API 우선순위와 공정성

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

FEATURE STATE: Kubernetes v1.29 [stable]

과부하 상황에서 Kubernetes API server의 동작을 통제하는 것은 클러스터 관리자에게 중요한 작업이에요. kube-apiserver--max-requests-inflight--max-mutating-requests-inflight 같은 플래그로 수용할 미해결 작업을 제한해 요청 홍수로 인한 과부하·크래시를 막을 수 있지만, 이 플래그만으로는 트래픽이 많은 시기에 가장 중요한 요청이 통과하도록 보장하지 못해요.

API Priority and Fairness (APF) 기능은 이런 max-inflight 한계를 개선한 대안이에요. APF는 요청을 더 세밀하게 분류·격리하고, 제한적인 큐잉을 도입해 짧은 순간의 폭주에도 요청이 거부되지 않도록 해요. 요청은 공정 큐잉(fair queuing) 기법으로 큐에서 디스패치되므로, 예를 들어 잘못 동작하는 컨트롤러 하나가 다른 요청들을 굶기지 않아요.

주의: 원격 명령 실행이나 로그 tailing 같은 "장시간 실행" 요청은 APF 필터를 적용받지 않아요. 다만 APF는 watch 요청에는 적용돼요.

활성화/비활성화

APF는 기본으로 활성화되어 있고, --enable-priority-and-fairness 플래그로 제어해요. 이 기능은 flowcontrol.apiserver.k8s.io API 그룹과 관련되며, v1.29에 안정화된 v1 버전과 deprecated된 v1beta3 버전이 있어요.

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

--enable-priority-and-fairness=false로 기능을 끌 수 있어요.

개념

들어오는 요청은 FlowSchema가 요청 속성으로 분류하고, 우선순위 레벨(priority level)에 할당돼요. 우선순위 레벨은 별도의 동시성 한계를 유지해 서로 굶기지 않게 하고, 레벨 내에서는 공정 큐잉 알고리즘이 서로 다른 flow가 서로를 굶기지 않게 하며 폭주 트래픽으로 인한 실패를 방지해요.

  • 우선순위 레벨 (Priority Levels): APF가 켜지면 --max-requests-inflight 플래그들의 합을 설정 가능한 우선순위 레벨들로 나눠요. 각 요청은 하나의 레벨에 할당되고, 각 레벨은 자신의 한계만큼만 동시에 디스패치해요. 예를 들어 기본 설정에는 leader-election 요청, 내장 컨트롤러 요청, Pod 요청용 레벨이 따로 있어서, Pod 하나가 API server에 요청을 쏟아부어도 leader election이나 내장 컨트롤러 동작을 막지 못해요.
  • 요청이 차지하는 좌석 (Seats): 각 요청은 하나의 동시성 단위("seat")를 차지해요. 그런데 일부 list 요청은 서버가 되돌려줄 객체 수를 추정해 그 수에 비례하는 여러 좌석을 차지해요.
  • watch 요청 실행 시간 조정: watch 요청은 초기 알림 버스트가 끝나면 좌석을 놓는 것으로 간주하고, 쓰기 요청은 실제 쓰기 후에도 추가 알림 전송 시간만큼 좌석을 더 차지해요.
  • 큐잉 (Queuing): 같은 우선순위 레벨의 요청을 flow로 할당하고 shuffle sharding 기법으로 큐에 배정해, 낮은 강도의 flow를 높은 강도의 flow로부터 격리해요.
  • 면제 요청 (Exempt requests): 매우 중요하다고 간주되는 일부 요청은 아무 제한도 받지 않아요. 이 면제 덕분에 잘못 구성된 flow control이 API server를 완전히 중단시키는 일을 막아요.

리소스

flow control API는 두 종류의 리소스를 사용해요.

  • PriorityLevelConfiguration: 각 우선순위 레벨을 나타내며, 미해결 요청 수와 큐잉된 요청 수에 독립적인 한계를 가져요.
  • FlowSchema: 개별 들어오는 요청을 분류해 각각 하나의 PriorityLevelConfiguration에 매칭해요.

예를 들어 default 네임스페이스의 Pod가 실행하는 비싼 list event 요청을 격리하고 싶다면, matchingPrecedence: 8000을 갖는 FlowSchema를 만들어 catch-all PriorityLevelConfiguration에 매핑할 수 있어요. catch-all 레벨은 동시성 몫이 매우 작고 큐잉을 하지 않아요.

문제 해결 시 좌석 수를 늘리려면 max-requests-inflight/max-mutating-requests-inflight 값을 키우거나, 더 큰 동시성 레벨의 PriorityLevelConfiguration을 참조하는 새 FlowSchema를 만들거나, NominalConcurrencyShares를 늘리는 방법을 쓸 수 있어요.

더 알아보기 (Learn more)