메모리 계층화에는 두 부분이 있습니다. 메커니즘은 페이지를 압축 메모리, SSD, 원격 용량으로 보내고 fault에서 되돌립니다. 정책은 어느 페이지를 보낼지, 앞으로 다시 쓸 가능성이 있어 미리 가져올지를 정합니다. Linux는 두 기능을 커널에 묶어 성숙한 swap 경로를 제공하지만 새 정책을 배포하려면 느리고 위험한 커널 변경이 필요합니다.

Google의 PageFlex는 두 역할을 분리합니다[1]. fault handler, swap backend, cgroup 제어, 일반 애플리케이션 인터페이스는 Linux에 남깁니다. 지연에 덜 민감한 회수 및 prefetch 결정만 eBPF가 돕는 정책 코드와 사용자 공간 agent에 위임합니다. userfaultfd는 zswap refault에 50% 넘는 비용을 더할 수 있고 custom memory library는 애플리케이션과 기존 인프라를 바꿔야 하는데, 이 경계는 두 비용을 피합니다.

목표는 page fault 자체를 프로그래밍 가능하게 만드는 것이 아닙니다. fault는 정책 daemon을 왕복하기에 너무 민감합니다. PageFlex는 비동기로 실행할 수 있는 결정에 필요한 event와 상태를 외부에 제공하고, 기존 madvise 동작으로 묶은 hint를 집행합니다. 빠르고 호환돼야 하는 메커니즘을 옮기지 않고 정책만 교체합니다.

모든 페이지를 복사하지 않는 eBPF 관측

페이징 정책에는 가상주소 목록보다 많은 정보가 필요합니다. allocation, free, swap-in, swap-out, access bit, 주기적 scan event를 사용할 수 있고 페이지별 age, frequency, weight도 유지해야 합니다. 이 상태를 event마다 사용자 공간으로 복사하면 커널 배포 비용이 메모리 대역폭과 context switch 비용으로 바뀝니다.

PageFlex는 선택한 페이징 event에 eBPF handler를 설치합니다. 정책은 필요한 신호만 구독하고 handler는 페이지에 연결된 작은 영속 필드를 갱신하며 사용자 공간 처리 전에 상태를 집계할 수 있습니다. eBPF 검증기가 메모리 접근과 실행을 제한하므로 정책 코드는 무제한 kernel module이 아니라 통제된 커널 정보만 받습니다.

회수 정책은 일반적인 page weight로 표현합니다. LRU 계열은 최근성, LFU는 횟수, Hyperbolic caching은 빈도와 나이를 함께 쓸 수 있습니다. 사용자 공간 agent는 주기적으로 후보를 받아 weight로 정렬하고 묶음 회수를 요청합니다. 실제 페이지 전환과 설정된 swap backend 실행은 계속 Linux가 담당합니다.

Prefetch도 같은 경계를 사용합니다. event handler가 fault와 access pattern을 관측하면 사용자 공간 구성요소가 추세를 찾고 묶음 page-in hint를 보냅니다. PageFlex는 page-fault 경로를 바꾸지 않고 Linux read-ahead와 stride access용 Leap을 다시 구현합니다. 원문은 Hyperbolic weight update 17줄, 기존 Leap 코드에 추가한 로직 21줄을 보고해 완전한 pager보다 작은 인터페이스임을 보여 줍니다.

PageFlex는 Linux 페이징 메커니즘 옆에 정책 경계를 둡니다. 커널 page event가 검증된 eBPF handler를 실행해 작은 page weight를 갱신합니다. 사용자 공간 agent는 fault path 밖에서 페이지를 정렬하거나 예측하고 묶은 madvise hint를 반환합니다. Linux는 기존 backend와 동일한 application ABI로 reclaim, swap, refault를 계속 실행합니다. 이 글을 위해 새로 만든 도판.

관측과 동작의 구분은 안전성에도 중요합니다. 잘못된 정렬은 나쁜 victim을 골라 성능을 낮출 수 있지만 disk I/O, page-table 복구, fault handler를 구현하지는 않습니다. 운영자는 정책 코드를 교체하면서 이미 시험하고 관측하는 메커니즘을 보존할 수 있습니다.

같은 정책으로 확인한 기본 비용

더 나은 정책을 주장하기 전에 PageFlex는 기능이 같은 구현을 비교합니다. 자체 LRU 모델을 사용한 Redis와 합성 벤치마크는 같은 기능의 커널 g-swap 정책보다 최대 1% 느렸습니다. PageFlex의 Linux read-ahead 구현은 SSD와 비슷한 backend에서 prefetch가 없을 때보다 76% 빨랐고 커널 구현의 82% 개선에 가까웠습니다. Prefetch 이점이 없는 조건의 지원 비용은 0.8%였습니다.

마이크로초 단위 경로는 fault를 커널에 남긴 이유를 보여 줍니다. zswap의 일반 swap-in 중앙값은 약 3.5µs였습니다. PageFlex prefetch hit는 이미 페이지가 상주해 약 1.08µs였고, miss는 커널 기본 major fault에 가까우면서 eBPF 등의 비용으로 약 0.5~1µs가 추가됐습니다. 반면 userfaultfd 왕복은 정교한 victim 정책의 이점을 모두 소비할 수 있습니다.

애플리케이션 영향이 작아도 제어 작업은 측정됩니다. 주기적인 page-table scan은 페이지마다 eBPF를 실행해 커널 g-swap 구현보다 17% 느렸고, 사용자 공간에서 syscall로 페이지 동작을 집행하는 과정은 14% 느렸습니다. 회수는 비동기이므로 PageFlex는 최대 64페이지를 묶습니다. 페이지마다 syscall 하나를 실행하면 경계 비용이 너무 커집니다.

이 수치들은 섞어 해석하면 안 됩니다. 1% 미만 성능 저하는 평가한 작업에서 같은 정책을 실행한 종단 간 결과이고, 17%와 14%는 특정 제어 동작의 차이입니다. 해당 동작이 전체 실행시간의 작은 부분이므로 동시에 성립하지만, scan을 매우 자주 하거나 정책 주기를 짧게 만들면 제어 비용이 critical path로 이동할 수 있습니다.

정책이 달라질 때 생기는 유연성의 가치

프레임워크의 목적은 전체 배포 환경의 kernel에 아직 없는 정책을 실행하는 것입니다. 빈도에 유리하도록 만든 합성 작업에서 PageFlex LFU는 같은 성능 저하를 유지하며 LRU보다 최대 두 배 많은 메모리를 offload했습니다. 실제 작업 추적에서는 Hyperbolic caching이 최대 5% 더 절약했습니다. PageFlex Leap은 Linux read-ahead가 찾지 못하는 stride access의 refault rate를 75.4% 줄였습니다.

한 프로세스 안에서도 정책을 다르게 적용할 수 있습니다. key/value 서비스의 index, cache, background 영역에 서로 다른 weight를 줄 수 있습니다. 논문의 성능 목표 아래에서 workload-aware 정책은 LRU보다 한 key/value 작업의 메모리를 최대 36%, GAPBS PageRank는 6% 더 절약했습니다. 애플리케이션 영역이나 단계에서 페이지 의미를 가져오면서 load/store 경로는 투명하게 유지한 결과입니다.

상한 수치는 구조가 잘 맞는 조건을 설명할 뿐 전체 배포 환경의 절감률은 아닙니다. LFU는 재사용 빈도가 미래를 예측할 때 유리하지만 단계가 바뀌면 과거에 자주 쓰던 페이지를 오래 보관할 수 있습니다. Stride prefetch는 접근 간격이 일정할 때 이기고 불규칙하면 I/O와 메모리를 낭비합니다. 세분화는 운영자가 검증하고 되돌려야 할 정책 구성 수를 늘립니다.

운영 기능으로서의 호환성

하이퍼스케일 페이징은 이미 kernel reclaim, cgroup feedback, compressed memory, SSD swap, metric, SLO controller를 결합합니다. 메커니즘을 교체하면 장애 처리와 모든 backend를 다시 시험해야 합니다. PageFlex의 ABI 호환 설계에서는 수정하지 않은 프로세스가 Linux를 통해 fault와 reclaim을 계속 실행합니다. 정책은 cgroup이나 memory region에 적용하고 서비스 relink 없이 제거할 수 있습니다.

장애 범위도 줄어듭니다. 사용자 공간 agent가 늦으면 page fault가 기다리는 대신 회수 결정이 오래된 상태가 됩니다. eBPF handler가 검증기를 통과하지 못하면 로드되지 않으며 기존 커널 fallback이 남습니다. 정책으로 인한 장애를 없애지는 않지만, 무제한 module의 memory corruption과 다른 형태로 제한합니다.

그래도 kernel hook과 페이지별 예약 필드가 필요하므로 upstream 호환 및 rebase 작업은 남습니다. Verifier는 임의 메모리 접근을 막지만 정책 결정의 이점을 증명하지 않습니다. Fleet admission에는 handler 시간, scan 주기, map memory, syscall rate, 정책 종류 수에 대한 예산이 필요합니다.

정책 경계를 정하는 기준

PageFlex는 메커니즘이 안정적이고 교체 비용이 크며 정책은 커널보다 빠르게 바뀌고 결정을 묶어 실행할 수 있을 때 적합합니다. Proactive reclamation과 prefetch는 이 조건을 만족합니다. Demand fault, page-table update, swap-device completion은 그렇지 않으므로 커널에 남습니다.

같은 원칙은 storage placement, network routing, accelerator scheduling에도 적용됩니다. 빠른 메커니즘과 느린 optimizer가 있다면 optimizer만 유연한 환경으로 옮겨 검증된 데이터 경로를 보존할 수 있습니다. 인터페이스는 전체 경로 상태를 복사하지 않으면서 더 나은 결정에 충분한 정보만 제공해야 합니다.

도입 전에는 먼저 같은 정책을 재현해 애플리케이션 성능 저하, fault latency, scan CPU, syscall rate, 정책 metadata memory를 측정해야 합니다. 그 다음 새 정책은 같은 offload 비율이 아니라 같은 애플리케이션 SLO에서 비교해야 합니다. 더 비싼 refault를 늘려 메모리만 많이 비우는 정책은 효율 개선이 아닙니다.

일반화할 기여는 이 위임선입니다. PageFlex는 Linux 메커니즘과 application contract를 지키고, eBPF로 제한된 커널 관측을 수행하며, 복잡한 정렬은 더 빨리 바꿀 수 있는 코드로 옮깁니다. 같은 정책의 종단 간 비용을 1% 아래로 유지하면서 세분화 정책을 실용화할 수 있음을 보여 줬고, 모든 scan과 metadata update, batch, 잘못된 예측이 여전히 성능 예산 안에 들어와야 한다는 비용도 함께 드러냈습니다.

출처와 저작권 안내

이 글은 Silicon & Systems가 작성한 편집 분석으로, 구조와 측정, 한계를 우리 표현으로 다시 썼습니다. 원문의 문장, 표, 도판은 재수록하지 않았고 도판은 이 글을 위해 새로 만들었습니다. 전체 논문은 USENIX ATC 2025 발표 페이지에서 확인할 수 있으며, 저작권은 저자에게 있습니다. 2025.