API Priority and Fairness (APF)

APF는 Kubernetes API 서버가 과부하 상황에서 요청을 우선순위와 공정성 기준으로 처리하기 위한 매커니즘입니다. "API Rate Limiting"이라고 부르기도 하지만, 단순히 요청 수를 막는 것이 아니라 어떤 요청을 먼저/덜 처리할지를 결정하는 것이 핵심입니다. Kubernetes v1.29에서 GA(stable)가 되었고, API 그룹은 flowcontrol.apiserver.k8s.io/v1입니다.

1. 왜 필요한가

과거 API 서버는 --max-requests-inflight, --max-mutating-requests-inflight 같은 전역 인플라이트 상한만 가지고 있었습니다. 이 방식의 문제는 모든 요청을 동등하게 취급한다는 점입니다.

예를 들어 어떤 컨트롤러가 무거운 LIST 조회를 대량으로 던지면 전역 상한이 차버려서, 정작 중요한 leader election이나 노드 heartbeat 같은 요청까지 막힙니다. 즉 덜 중요한 트래픽이 클러스터의 핵심 동작을 마비시킬 수 있습니다.

APF는 이 전역 상한을 대체해, 요청을 우선순위별로 나누고 한 종류의 요청이 다른 종류를 굶기지(starve) 않도록 격리합니다.

2. 핵심 리소스 두 가지

APF는 두 종류의 클러스터 리소스로 동작합니다.

2.1. FlowSchema

들어오는 요청을 분류합니다. 요청의 속성(user, group, verb, resource, namespace 등)을 규칙으로 매칭해서,

  • 어떤 PriorityLevel로 보낼지 결정하고
  • flow distinguisher(흐름 구분자)를 계산해 같은 우선순위 안에서 요청들을 다시 잘게 나눕니다.

2.2. PriorityLevelConfiguration

각 우선순위 레벨의 동시성(concurrency) 한도와 큐 동작을 정의합니다.

  • nominalConcurrencyShares: 전체 동시성을 각 레벨에 비례 배분하는 몫.
  • 큐 관련: queues, queueLengthLimit, handSize.
  • type: Exempt로 두면 제한·큐잉 없이 항상 통과시킵니다(예: system:masters).

전체 동시성 풀은 --max-requests-inflight + --max-mutating-requests-inflight 합으로 잡히고, 이를 레벨들이 share에 따라 나눠 갖습니다.

3. Flow Distinguisher와 격리

같은 PriorityLevel에 묶인 요청들도 flow라는 더 작은 단위로 나뉩니다. 구분 기준(distinguisher)은 보통 셋 중 하나입니다.

  • 요청 사용자(user) — 기본
  • 대상 리소스의 namespace
  • 없음(cluster-scoped 요청)

이렇게 나누는 이유는, 같은 우선순위라도 버그가 있는 한 클라이언트가 같은 레벨의 다른 클라이언트를 굶기지 못하게 하기 위해서입니다.

4. Shuffle Sharding과 handSize

flow를 큐에 배정할 때 shuffle sharding이라는 공정 큐잉 알고리즘을 씁니다.

  • handSize: 한 flow가 분산될 큐의 개수.
  • handSize를 키우면 저부하 flow와 고부하 flow의 격리가 좋아지지만, 그만큼 오버헤드도 커집니다.
  • 핵심 효과: 시끄러운(noisy) flow가 특정 큐들에만 영향을 주고, 다른 flow는 별도 큐 조합을 받아 충돌을 피합니다.

5. Seat과 Width

동시성 점유 단위를 seat이라고 합니다.

  • 대부분의 요청은 1 seat을 차지합니다.
  • LIST: 예상 객체 수에 비례해 여러 seat을 점유합니다(무거운 조회일수록 비쌈).
  • WATCH: 알림 폭주 예상치에 따라 seat을 점유합니다(APF 제한 대상이며 exempt 아님).
  • 쓰기(write): 알림 처리 비용 때문에 추가 seat 시간이 붙습니다.

요청이 차지하는 seat 수를 width라고 하며, 이 개념 덕분에 "요청 1건 = 부하 1"이라는 단순 가정 대신 실제 비용을 반영합니다.

6. Borrowing (동시성 빌려주기)

레벨별로 고정 배분만 하면 한가한 레벨의 여유 동시성이 낭비됩니다. APF는 이를 빌려줄 수 있게 합니다.

  • lendablePercent: 이 레벨이 남에게 빌려줄 수 있는 동시성 비율.
  • borrowingLimitPercent: 이 레벨이 남에게서 빌릴 수 있는 최대 비율.
  • 저사용 레벨이 고사용 레벨에 일시적으로 capacity를 빌려주어 전체 활용도를 높입니다.

7. 과부하 시 동작

  • 레벨 한도를 초과한 요청은 shuffle sharding으로 큐에 쌓입니다.
  • 큐 용량까지 넘으면 HTTP 429 (Too Many Requests) 로 거절되고, Retry-After 헤더로 재시도 시점을 알려줍니다.
  • Exempt 요청은 제한·큐잉 대상이 아니라 거절되지 않습니다. 헬스체크(/healthz·/livez·/readyz)나 일부 long-running 요청이 여기 해당합니다.

8. 진단

응답 헤더

요청이 어떤 schema/level로 분류됐는지 헤더로 확인할 수 있습니다.

  • X-Kubernetes-PF-FlowSchema-UID
  • X-Kubernetes-PF-PriorityLevel-UID

주요 메트릭

  • apiserver_flowcontrol_rejected_requests_total: 거절(429)된 요청 수.
  • apiserver_flowcontrol_current_inqueue_requests: 현재 큐에 쌓인 요청 수.
  • apiserver_flowcontrol_current_executing_requests: 현재 실행 중 요청 수.
  • apiserver_flowcontrol_request_wait_duration_seconds: 큐 대기 시간.

디버그 엔드포인트

  • /debug/api_priority_and_fairness/dump_priority_levels
  • /debug/api_priority_and_fairness/dump_queues
  • /debug/api_priority_and_fairness/dump_requests

9. Reference

Document History

  • 2026-06-16T17:02:46+09:00 - Written by Claude Opus 4.8 (1M context) via Claude Code
🔒 Admin 로그인