- Published on
sched_ext 서브 스케줄러 — 커널 7.1에 절반만 도착한 cgroup별 스케줄러
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 들어가며 — 헤드라인과 커밋 로그 사이의 간극
- 복습 — sched_ext가 뭐였나
- 왜 서브 스케줄러인가 — cpuset의 한계
- 지금까지의 방법 — scx_flatcg는 계층을 평탄화한다
- 설계 — cgroup에 스케줄러를 붙인다
- 7.1에 실제로 들어간 것 — 그리고 빠진 것
- 타임라인 — 왜 이렇게 오래 걸리나
- 7.2에서 이어지는 작업
- 그래서 지금 뭘 해야 하나
- 마치며
- 참고 자료
들어가며 — 헤드라인과 커밋 로그 사이의 간극
리눅스 7.1이 2026년 6월 14일에 릴리스됐습니다. 스케줄러 쪽 헤드라인 하나는 이것이었습니다 — sched_ext에 cgroup 서브 스케줄러 지원이 들어갔다. 문장만 보면 꽤 큰 사건입니다. cgroup마다 다른 CPU 스케줄러를 붙일 수 있다는 뜻이니까요. 컨테이너를 굴리는 사람이라면 귀가 솔깃할 만합니다.
그런데 같은 소식을 LWN의 머지 윈도 요약에서 읽으면 톤이 확연히 다릅니다. Jonathan Corbet은 7.1 머지 윈도 정리에서 이렇게 썼습니다. 원문 그대로 옮기면 이렇습니다.
The extensible scheduler class (sched_ext) subsystem now has the beginning of support for sub-schedulers, meaning that each control group can run with its own custom CPU scheduler. As of 7.1, this implementation is not complete (it lacks the enqueue path in particular), but much of the needed core structure is there.
핵심은 두 번째 문장입니다 — 7.1 기준으로 이 구현은 완성되지 않았고, 특히 enqueue 경로가 빠져 있습니다. 들어온 것은 "서브 스케줄러 지원의 시작"이지 서브 스케줄러가 아닙니다.
이 글은 그 간극에 관한 이야기입니다. 무엇을 하려는 기능이고, 왜 필요하고, 7.1에 실제로 뭐가 들어갔고, 뭐가 아직 없고, 그래서 지금 당신이 뭘 해야 하는지(대체로 "아무것도")를 정리합니다.
복습 — sched_ext가 뭐였나
CFS에서 EEVDF까지의 흐름은 따로 정리했으니 여기서는 sched_ext만 짧게 복습합니다.
sched_ext는 커널 6.12에 병합된 확장 스케줄러 클래스입니다(원래 6.11을 노렸다가 한 사이클 밀렸습니다). 스케줄링 정책을 BPF 프로그램으로 작성해서 런타임에 적재·교체할 수 있게 해 줍니다. struct sched_ext_ops에 콜백을 채워 넣고 로드하면, 그때부터 그 BPF 코드가 어떤 태스크를 어느 CPU에서 언제 돌릴지 결정합니다.
여기서 가장 중요한 설계 결정은 안전장치입니다. 커널 문서의 표현을 그대로 옮기면 이렇습니다.
System integrity is maintained no matter what the BPF scheduler does. The default scheduling behavior is restored anytime an error is detected, a runnable task stalls, or on invoking the SysRq key sequence SysRq-S.
BPF 스케줄러가 무슨 짓을 하든 시스템 무결성은 유지되고, 에러가 감지되거나 실행 가능한 태스크가 멈추면 기본 스케줄링 동작으로 자동 복귀합니다. SysRq-S로 손수 걷어낼 수도 있습니다. 이 워치독이 있기 때문에 "커널 스케줄러를 사용자 코드로 갈아 끼운다"는 무모해 보이는 아이디어가 실제로 성립합니다.
왜 서브 스케줄러인가 — cpuset의 한계
문제 설정은 Tejun Heo가 올린 패치 시리즈 커버레터에 잘 나와 있습니다. 상황은 이렇습니다. 큰 머신 한 대에 성격이 다른 워크로드가 여럿 얹혀 있습니다. 각자 원하는 스케줄링 정책이 다릅니다. 지연에 민감한 서비스, 처리량이 중요한 배치 잡, 게임처럼 상호작용성이 중요한 것들이 한 상자 안에 섞여 있습니다.
지금까지의 답은 하드 파티셔닝이었습니다. 커버레터의 문장을 그대로 옮기면 이렇습니다.
Traditional approaches rely on hard partitioning via cpuset, but this approach lacks the dynamism required by modern workloads.
cpuset으로 CPU를 갈라 주는 방식은 현대 워크로드가 요구하는 동적인 성질이 없다는 것입니다. 왜 부족한지도 커버레터가 구체적으로 설명합니다.
Users typically care less about specific CPU assignments and more about optimizations available on larger machines: opportunistic over-commit, improved latency for critical workloads while preserving bandwidth fairness, control mechanisms beyond simple CPU time (such as memory bandwidth isolation), and intelligent placement to optimize cache locality.
풀어 쓰면 이렇습니다. 사람들이 진짜 원하는 건 "이 워크로드는 3번부터 7번 코어"가 아닙니다. 큰 머신을 공유해야만 얻을 수 있는 것들 — 기회주의적 오버커밋, 대역폭 공정성은 지키면서 중요한 워크로드의 지연은 개선하기, 단순 CPU 시간을 넘어선 제어(메모리 대역폭 격리 같은), 캐시 지역성을 살리는 배치 — 을 원합니다. CPU를 미리 잘라 놓으면 이 중 어느 것도 못 합니다. 잘린 조각 안에서 놀 뿐이니까요.
그리고 왜 커널이 이걸 대신 못 해 주냐는 질문에 대한 답이, Phoronix가 인용한 두 번째 버전 커버레터의 문장입니다.
Applications often have domain-specific knowledge that generic schedulers cannot possess. Database systems understand query priorities and lock holder criticality.
애플리케이션은 범용 스케줄러가 가질 수 없는 도메인 지식을 갖고 있습니다. DB는 어떤 쿼리가 급한지, 어떤 스레드가 락을 쥐고 있어서 지금 안 돌리면 다 같이 막히는지 압니다. 커널은 모릅니다. sched_ext의 원래 논지가 "그럼 아는 쪽이 정책을 쓰게 하자"였고, 서브 스케줄러는 그 논지를 머신 전체가 아니라 cgroup 단위로 내리는 시도입니다.
지금까지의 방법 — scx_flatcg는 계층을 평탄화한다
오해를 피하기 위해 짚어야 할 게 있습니다. sched_ext가 cgroup을 아예 몰랐던 건 아닙니다. 예제 스케줄러 중에 scx_flatcg가 있고, 커널 문서는 이걸 이렇게 설명합니다.
implements hierarchical weight-based cgroup CPU control by compounding each cgroup's share at every level into a single flat scheduling layer
계층적 가중치 기반 cgroup CPU 제어를 구현하되, 각 cgroup의 몫을 레벨마다 곱해서 하나의 평탄한 스케줄링 레이어로 합쳐 버립니다. 이름의 flat이 그 뜻입니다.
이게 중요한 대비입니다. 기존 방식은 계층을 표현하되 마지막에 납작하게 눌러서 스케줄러 하나가 전부 처리합니다. 가중치는 지켜지지만, cgroup마다 다른 정책을 쓰는 건 여전히 불가능합니다. 결국 스케줄러는 하나니까요. 서브 스케줄러가 바꾸려는 게 정확히 이 지점입니다 — 계층을 누르지 말고, 계층의 각 지점에 진짜로 다른 스케줄러를 앉히자.
설계 — cgroup에 스케줄러를 붙인다
Corbet의 Sub-schedulers for sched_ext(2026년 1월 29일)가 v1 기준으로 구조를 잘 정리해 뒀습니다. 핵심 규칙은 한 문장입니다.
Each task in the system will be governed by the scheduler attached to its control group (or to the nearest ancestor group).
시스템의 모든 태스크는 자기 컨트롤 그룹에 붙은 스케줄러의 지배를 받습니다. 그 그룹에 스케줄러가 없으면 가장 가까운 조상 그룹의 것을 따릅니다. DNS 리졸브나 파일시스템 권한 상속과 같은 익숙한 패턴입니다.
커버레터의 표현으로는 이렇게 됩니다.
schedulers to attach anywhere in the cgroup hierarchy, with parent schedulers dynamically controlling CPU allocation to their children.
스케줄러는 cgroup 계층 어디에나 붙을 수 있고, 부모 스케줄러가 자식들에게 갈 CPU 할당을 동적으로 제어합니다. 여기서 역할 분담이 갈립니다. Corbet의 설명대로 CPU 컨트롤러는 여전히 "얼마나 많은 CPU 시간이 이들에게 주어지는가"를 담당하고, 서브 스케줄러는 그 시간 안에서 자기 그룹의 프로세스들을 어떻게 굴릴지를 담당합니다.
깊이에는 제한이 있습니다. 커버레터의 문장입니다.
The framework supports scheduling hierarchies up to SCX_SUB_MAX_DEPTH levels (currently set to 4).
SCX_SUB_MAX_DEPTH까지, 현재 값은 4입니다. 무한 중첩이 아니라 4단계입니다.
그림으로 그리면 이런 모양입니다.
root cgroup ── 루트 BPF 스케줄러 (자식들에게 CPU 배분)
│
├── /db ── scx 스케줄러 A (쿼리 우선순위·락 홀더를 아는 정책)
│
├── /web ── scx 스케줄러 B (지연 우선)
│ └── /web/batch ── 스케줄러 없음 -> 가장 가까운 조상(B)을 따름
│
└── /batch ── 스케줄러 없음 -> 루트 스케줄러를 따름
깊이 제한: SCX_SUB_MAX_DEPTH = 4
메커니즘 하나가 더 인상적입니다. Corbet이 짚은 보안 모델인데, kfunc에 암묵적 인자를 붙여서 bpf_prog_aux 구조체에 접근하게 만들었습니다. 덕분에 이렇게 됩니다.
BPF programs themselves need never specify which scheduler they are operating on.
BPF 프로그램이 자기가 어느 스케줄러 소속인지 스스로 밝힐 필요가 없습니다. 밝히게 두면 거짓말할 수 있으니까요 — 남의 스케줄러 큐를 건드리는 BPF 프로그램을 상상해 보면 왜 이게 필요한지 바로 보입니다. 커널이 프로그램 자체에서 소속을 읽어 냅니다.
7.1에 실제로 들어간 것 — 그리고 빠진 것
여기가 이 글의 본론입니다.
7.1에 들어간 것은 dispatch 경로입니다. dispatch는 Corbet의 정의로 "스케줄러에게 다음에 돌릴 태스크를 골라서 특정 CPU의 디스패치 큐에 넣으라고 지시하는" 콜백입니다. 즉 "이미 돌릴 준비가 된 태스크들 중에 뭘 언제 올릴까"를 계층적으로 처리하는 뼈대가 들어갔습니다.
빠진 것이 더 중요합니다. Corbet이 v1을 리뷰하며 짚은 미구현 항목은 이렇습니다.
select_cpu()콜백 — 태스크가 깨어날 때 어느 CPU로 보낼지 고르는 경로enqueue()콜백 — 태스크를 큐에 넣는 경로
그리고 bypass 모드는 재설계가 필요하다고 지적됐습니다. 이유가 구체적입니다.
allowing one sub-scheduler to toss processes into a global FIFO queue could lead to interference with other sub-schedulers
서브 스케줄러 하나가 프로세스를 전역 FIFO 큐에 던져 넣게 두면 다른 서브 스케줄러들과 간섭할 수 있다는 것입니다. 격리가 목적인 기능에서 격리가 새는 경로라 그냥 넘어갈 수 없는 문제입니다. 참고로 이 문제는 흔적을 남겼습니다 — 현재 커널 문서에서 서브 스케줄러가 언급되는 곳은 사실상 SCX_EV_SUB_BYPASS_DISPATCH 이벤트 카운터 설명 한 줄이고, 내용은 "tasks dispatched from sub-scheduler bypass DSQs (only relevant with CONFIG_EXT_SUB_SCHED)"입니다. 기능 문서가 아니라 진단 카운터로만 존재합니다.
커버레터 자신도 이 상태를 숨기지 않습니다.
While the enqueue path and other components require further development, this patchset establishes the core mechanisms for nested scheduler operation.
enqueue 경로와 다른 구성 요소는 추가 개발이 필요하지만, 이 패치셋은 중첩 스케줄러 동작의 핵심 메커니즘을 세운다. 정직한 문장입니다.
kernelnewbies의 7.1 변경사항 정리도 같은 선을 지킵니다 — sched_ext가 서브 스케줄러 지원을 추가했고, 이 기능의 목적은 "향후 릴리스에서" cgroup마다 다른 스케줄러를 쓸 수 있게 하는 것이라고 씁니다. 원문은 "The purpose of this feature is to eventually allow (in future releases) using different schedulers in different cgroups"입니다. eventually와 in future releases가 핵심 단어입니다.
정리하면 이렇습니다.
서브 스케줄러 — 무엇이 어디까지 왔나 (2026-07-16 기준)
dispatch 경로 [ 7.1에 병합됨 ]
enqueue 경로 [ 미완 — 후속 패치셋 개발 중 ]
select_cpu() 경로 [ v1 리뷰 시점 미구현 ]
bypass 모드 [ 재설계 필요 (전역 FIFO 간섭 문제) ]
cgroup별 다른 스케줄러 [ 아직 불가 — "향후 릴리스" ]
타임라인 — 왜 이렇게 오래 걸리나
시간 순서로 놓으면 이 기능의 속도가 보입니다.
2024-11 sched_ext 자체가 커널 6.12에 병합 (6.11 목표였다가 밀림)
2025-09-19 Tejun Heo, cgroup 서브 스케줄러 지원 RFC 패치셋 게시
2026-01-29 LWN "Sub-schedulers for sched_ext" — v1 리뷰
2026-02-25 v2 게시, sched_ext/for-7.1 브랜치에 표시
2026-03-04 7.1에 들어간 시리즈의 커버레터
2026-04-27 LWN 7.1 머지 윈도 정리 — "구현이 완성되지 않았다"
2026-06-14 리눅스 7.1 릴리스 (dispatch 경로 포함)
2026-06-18 LWN 7.2 머지 윈도 — "서브 스케줄러 지원 추가가 계속된다"
2026-07-16 (오늘) 메인라인은 7.2-rc3, 안정판은 7.1.3
RFC부터 부분 병합까지 9개월, 그리고 아직 쓸 수 없습니다. 여기서 Corbet이 v1 리뷰 때 남긴 예측을 다시 볼 필요가 있습니다.
One should thus not expect to see sub-scheduler support in the kernel for some time yet.
당분간 커널에서 서브 스케줄러 지원을 보리라 기대하지 말라. 1월에 쓴 이 문장은, 5개월 뒤 7.1에 "지원의 시작"이 들어왔음에도 여전히 유효합니다. 뼈대가 들어온 것과 기능을 쓸 수 있는 것은 다른 이야기이기 때문입니다. 커널에서 큰 기능이 조각으로 나뉘어 여러 사이클에 걸쳐 들어오는 건 정상이고, 오히려 건강한 방식입니다. 다만 그 조각 중 첫 번째가 병합됐다는 소식을 기능 출시로 읽으면 곤란합니다.
7.2에서 이어지는 작업
7.2 머지 윈도에서도 작업은 계속됩니다. Corbet의 7.2 머지 윈도 전반부 정리는 짧게 한 줄입니다 — "The addition of support for sub-schedulers in sched_ext continues."
Phoronix의 7.2 sched_ext 정리(2026년 6월 22일)가 조금 더 구체적입니다. 7.2에 들어간 것은 토폴로지 기반 CPU ID(CID), cmask 인프라, BPF arena 통합, 그리고 새 arena·CID 인터페이스를 실습하도록 다시 쓴 scx_qmap 예제입니다. 전부 인프라입니다.
그리고 풀 리퀘스트에 이 문장이 있습니다.
A follow-up patchset in development will complete enqueue-path support for hierarchical scheduling.
개발 중인 후속 패치셋이 계층적 스케줄링의 enqueue 경로 지원을 완성할 것이다. 미래 시제라는 점에 주의하십시오. 7.2에도 enqueue 경로는 없습니다. 7.2는 오늘 기준 아직 rc3이고, 릴리스도 안 됐습니다.
그래서 지금 뭘 해야 하나
정직하게 답하면 — 대체로 아무것도.
지금 할 수 없는 것
- cgroup마다 다른 BPF 스케줄러 붙이기. 이게 헤드라인이지만 아직 안 됩니다.
- 7.1로 커널을 올려서 이 기능의 이득을 보기. dispatch 경로 뼈대만으로는 워크로드에 아무 변화가 없습니다.
- 이 기능을 전제로 한 용량 계획이나 아키텍처 결정. enqueue 경로가 언제 완성될지, 완성된 형태가 지금 설계와 같을지 아무도 확답하지 않았습니다. 커버레터에는 upstream의 제대로 된 해법을 기다리는 임시 BPF 우회 조치도 포함돼 있었습니다.
지금 할 수 있는 것
- sched_ext 자체는 6.12부터 쓸 수 있습니다. 머신 전체에 스케줄러 하나를 붙이는 방식이고, 워치독 폴백이 있어서 실험 비용이 낮습니다.
- cgroup 가중치 기반 CPU 제어가 필요하면
scx_flatcg가 이미 있습니다. 계층을 평탄화하는 방식이라 정책은 하나지만, 많은 경우 이걸로 충분합니다. - 멀티테넌트 격리가 지금 당장 급하면 여전히 cpuset·cgroup CPU 컨트롤러가 답입니다. 커버레터가 지적한 한계(동적이지 않음)를 감수하는 대신, 오늘 동작합니다.
언제 다시 볼 것인가
enqueue 경로가 병합됐다는 소식이 나올 때입니다. 그전까지 이 기능은 로드맵이지 도구가 아닙니다. 그리고 병합된 뒤에도, sched_ext의 역사가 말해 주듯 — 6.11 목표가 6.12로 밀렸고, 서브 스케줄러 RFC가 9개월 만에 절반 왔습니다 — 여유 있게 잡는 편이 맞습니다.
마치며
정리하면 이렇습니다. sched_ext 서브 스케줄러는 좋은 아이디어입니다. 문제 설정이 정확하고(cpuset 하드 파티셔닝은 동적이지 않다), 논지가 일관되고(정책은 도메인 지식이 있는 쪽이 써야 한다), 설계가 합리적입니다(cgroup 계층에 스케줄러를 붙이고, 가장 가까운 조상을 상속하고, 4단계로 제한하고, 소속은 커널이 판별한다).
그리고 7.1에는 그중 dispatch 경로가 들어갔습니다. 그게 전부입니다. enqueue 경로가 없고, select_cpu()도 없고, bypass 모드는 재설계 대상이고, 커널 문서는 이 기능을 이벤트 카운터 한 줄로만 언급합니다. "각 컨트롤 그룹이 자기만의 커스텀 CPU 스케줄러로 돌 수 있다"는 문장은 지금 시제가 아니라 의도의 서술입니다.
이건 비판이 아닙니다. 커널이 일하는 방식이 원래 이렇고, 커버레터와 LWN과 kernelnewbies 모두 자기 상태를 정확하게 적어 뒀습니다 — "further development", "not complete", "eventually", "in future releases". 부정확했던 건 소스가 아니라 이걸 기능 출시로 읽는 독법입니다.
커널 릴리스 노트를 읽을 때 제가 쓰는 기준은 이겁니다. 병합됐다와 쓸 수 있다는 다른 사건이고, 큰 기능일수록 그 사이가 멉니다. 두 사건 사이의 거리를 재는 가장 싼 방법은 머지 윈도 요약에서 "not complete" 같은 단어를 찾는 것입니다. 대개 거기 적혀 있습니다.
참고 자료
- Sub-schedulers for sched_ext — Jonathan Corbet, LWN, 2026-01-29
- sched_ext: Implement cgroup sub-scheduler support — Tejun Heo의 패치셋 게시(LWN 사본), 2025-09-19
- The rest of the 7.1 merge window — Jonathan Corbet, LWN, 2026-04-27
- The 7.1 kernel has been released — LWN, 2026-06-14
- The first half of the 7.2 merge window — Jonathan Corbet, LWN, 2026-06-18
- Linux 7.1 변경사항 — kernelnewbies
- Sub-Scheduler Support Could Be One Of The Most Exciting Features To Come For Linux 7.1 — Phoronix, 2026-02-25
- Linux 7.2 sched_ext Continues Working Toward Sub-Scheduler Support — Phoronix, 2026-06-22
- Extensible Scheduler Class — 커널 공식 문서
- Sched_ext Merged For Linux 6.12 — Phoronix
- The Linux Kernel Archives — 현재 릴리스 현황
- 리눅스 CPU 스케줄러의 진화 — CFS에서 EEVDF까지(관련 글)