대규모의 persistent memory 에 대한 보장을 위해서는 많은 부분의 변화가 요구되었었고, 커널에 대한 페이지 캐쉬 기능이 계속 필요로 하는 부분인지에 대한 의문이 제기되었다고 한다.
이번 2017 linux.conf.au 에서 매튜 윌콕스 (Matthew Wilcox) 는 여전히 페이지 캐쉬가 필요 할뿐만 아니라 그 역할이 더 커져야한다고 주장했다.
하지만 이 야이기를 하기 전 우선 몇년 전 그는 기억하지 못하지만 했던 실수를 바로 잡아야 할 필요가 있다고 필자는 언급한다.
그는 "컴퓨팅은 캐쉬가 전부다" 라는 주제로 발표를 시작했다.
( 윌콕스는 그가 이때 뭔 개소리를 했는지 까맣게 잊고 있었을 것이다.. 라고 필자가 ㅎㅎ)
그가 갖고있던 최신 랩탑은 초당 백억개의 Instruction 을 처리할 수 있었는데 이것은 오직 캐쉬미스가 발생하지 않았을 때의 가능한 이야기이며, 이 시스템에서 제공가능한 캐쉬라인은 5300만 라인이기 때문에, 많은 캐쉬미스를 불러오지 않아 시스템 성능에 영향을 미치지 않는다고 했다.
만약 원하던 데이타가 메인메모리에 캐쉬되지 않았고 저장장치 ( 비록 SSD 라고 할 지라도 ) 에서 불러와야 하는 경우 상황은 더 악화 될 수 있다.
이건 항상 있어왔던 일이며 심지어 PDP-11 (16bit 미니컴퓨터 약 1990년대 시리즈) 에서도 조차 이 캐쉬미스로 인한 성능저하 현상은 존재한다.
결과적으로 오늘날 CPU speed 는 매우 빠르게 증가하여 메모리와 스토리지의 속도를 넘어섰기 때문에, 데이타를 적절하게 캐싱하지 않을때의 비용상승이 발생하게 되었다.
The page cache
Unix 시스템들은 1975년 6th-edition 버젼을 시작으로 버퍼 캐쉬를 도입해 파일시스템과 디스크 사이에 위치시켜 디스크 블록을 메모리에 캐쉬하기 시작한다.
리눅스는 시작부터 버퍼캐쉬를 도입, 사용하였다.
1995년 커널 1.3.50 버젼을 발표하면서 토발즈는 이 버퍼캐쉬를 페이지캐쉬로 전환하는, 리눅스역사의 매우 큰 혁신을 수행한다.
페이지캐쉬는 버퍼캐쉬와 달리 가상파일시스템 레이어 (VFS) 와 파일시스템 사이에서, 요구된 페이지를 캐쉬하여 이미 존재할 경우 low level 에 속하는 파일시스템 코드를 전혀 호출할 필요 없도록 하였다..
처음 버퍼캐쉬와 페이지 캐쉬는 구분되어 사용되었으나 1999 년 이후 Ingo Molnar 에 의해 완벽히 통합되었고, 버퍼캐쉬라는 이름은 아직까지 사용하고 있으나 전반적인 엔트리는 페이지캐쉬를 의미하게 되었다.
페이지 캐쉬에는 주어진 인덱스에서 비슷한 페이지를 찾아내거나, 페이지가 존재하지 않을 경우 새로 생성하거나, 디스크로 내려쓰기를 하는등 많은 기능을 내장하고 있으며,
더티페이지를 디스크에 Push 하고 페이지를 잠그거나, 해제하고 캐쉬로 부터 제거하는 기능을 갖고 있다.
각각의 스레드들은 페이지의 상태의 변화를 기다릴 수 있으며, 주어진 상태에서 페이지를 검색 할 수 있는 인터페이스또한 제공한다. 이 페이지 캐쉬는 또한 영구적인 스토리지에서 발생할 수 있는 에러를 추적하고 유지하는 기능또한 제공한다.
페이지 캐쉬에 대한 잠금은 내부적인 처리방법을 갖고 있으며, 이 잠금처리를 내부적으로 다루는 것에 대한 수준을 가지고 많은 논란과 분쟁이 있었으나, 결과적으로 내부에서 잠금을 처리하도록 정리되었다. 페이지가 변경될 경우 엑세스 제어를 위한 스핀락 형태의 잠금처리가 수행되지만, 조회를 위한 접근의 경우 RCU 메카니즘을 통해 잠금없이 처리한다.
캐싱이라는 것은 사실 미래를 예측하는 기술이라 할 수 있다. 캐쉬가 너무 커지면 제거할 페이지를 결정하는 다양한 경험적 방법이 적용된다.
일단 한번 "사용된" 페이지는 다시 사용되지 않을 것으로 예상하고 "Inactive 영역" 로 이동시킨다.
만약 또 다시 요청이 와 두번째로 사용하게 될 경우 "Active 영역" 으로 이동시킨다.
또 사용되지 않을 경우 다시 Inactive 로 이동된다.
예외적인 부분은 "shadow" 엔트리를 이용하여 Inactive 리스트를 벗어나는 잘못된 페이지에 대해서 추적하고 리클레임을 수행한다.
Hugepage 는 한동안 페이지 캐싱 부분에서 큰 도전과제였다. 커널의 Transparent Hugepage 기능 (THP) 은 초기에는 오직 anonymous ( file 기반이 아닌 ) 메모리에서 동작하므로 이것을 처리하기 위해서는 다시 Regular 영역으로 이동해야 하는 등의 추가 비용이 필요하다.
페이지캐쉬에서 휴지페이지를 처리하기 위한 여러가지 고민들이 이루어 졌었고, 단일 페이지 리스트에 대한 큰 세트를 새로 추가하는 방식으로 처리되었으나, WilCox 는 이 방식은 매우 "어리석다" 라고 까대며, 2016 리눅스 컨퍼런스에서 휴지페이지를 직접 처리할 수 있는 방식의 코드를 제안하였으나 적용되고 있지는 않다고 했다. (이때부터 필자인 Corbet 은 윌콕스를 까기로 작정한것 같다.... )
Do we still need the page cache?
최근에 Dave Chinner 는 Wilcox 가 초기 제공하였던 Persistent memory 에 있는 파일데이타를 저장하기 위한 Direct Access 를 도와주는 DAX subsystm 을 이용하면 Page cache 를 통하지 않기 때문에더이상 페이지 캐쉬를 사용할 필요가 없어진다고 주장하였다. 윌콕스는 자신은 분쟁을 일으키려고 한 행동이 아니라고 했으나, 결국 이는 논란이 되었다. ( Corbet 이 말한 윌콕스의 실수 라고 생각되고 Corbet 은 이사람 싫어한다 확실히 ㅎ)
특히 토발즈의 경우 페이지캐쉬의 중요성을 누구보다 잘 알고 알려왔는데, 기본적으로 로우레벨 파일시스템의 코드가 자주 호출되는 것은 좋지 않다고 생각하기 때문이였다.
Wilcox 는 직접적으로 I/O 를 처리하게 해주는 DAX 코드를 디자인 한 본인이였으므로 페이지 캐쉬가 완전 필요 없다고 결론지었었지만, 마지막에 토발즈가 이야기 한 것 처럼 로우레벨의 파일시스템 코드가 자주 호출되는 것은 좋지 않은게 사실이기 때문에, 그는 자신이 잘못되었었다고 인정했다.
현 커널에서 어플리케이션은 Persistent memory 에 있는 어떤 데이타를 읽기 위해서는 read 와 같은 시스템콜을 이용해야 하는데, 이때 DAX 가 사용될 수 있다.
요청된 데이타가 현재 페이지 캐쉬에 존재하지 않는다면, VFS layer 는 파일시스템으로 부터 read_iter() 를 호출한다. 이것은 다시 DAX 코드를 호출하고 DAX 코드는 파일의 offset 을 블록 넘버로 변환하기 위해 파일시스템 코드를 호출하고, 블럭의 Virtual memory 획득을 하고 그 블럭의 내용을 메모리에 할당하여 어플리케이션이 해당 블록을 사용 할 수 있도록 Block layer 를 다시 쿼리한다.
벌써 복잡한 과정이 더 필요하게 된 셈.... ( 쓰는내내 헛갈렸... )
이 과정은 최악은 아니었지만 개선될 필요가 있었다. (이게 Corbet 이 말하고 싶은 Wilcox 의 얼토당토않던 옛 주장을 까는것 )
페이지에 없을 경우 read_iter() 가 호출되는 것 까지는 동일하지만, 굳이 다시 DAX 가 filesystem 과 Block layer 를 매번 호출 할 필요 없이, 페이지 캐쉬에 요청을 하게 되면 된다는 점이다. 이렇게 되면 데이타가 페이지캐쉬에 있을 경우 알아서 처리되고 저수준 코드는 호출 될 필요가 없어진다.
토발즈가 위에서 언급한 페이지캐쉬에 대한 글(바로 위 글)을 쓸때, 그는 이렇게 이야기 했다 :
그건 잠금에 대한 끔찍한 참사임.. 그냥 내말 좀 처 들으셈, 네 말대로 파일시스템에서 병렬적 경로탐색 같은 것을 할 때 매우 세밀하고 정교하게 Locking 이 가능할 것이라 생각한다면, 그냥 계속 잠이나 쳐 자고 꿈이나 꾸고 있으삼.
Wilcox 는 이번 컨퍼런스에서 "그가 옳다.. DAX 의 locking 은 정말 끔찍한 수준이다" 라고 인정했다고 한다. 그는 원래 비교적 간단한 locking 만으로 가능한 많은 것을 커버할 수 있을거라 착각했으나, 각각의 복잡한 엣지케이스(극단적 상황으로 인한 논리적 문제) 를 만나게 되었다고 한다.
DAX locking 은 이제 "완전 추한" 상판임을 인정했고, 페이지 캐쉬를 무시할 수 있다고 했다가 생겨난 많은 문제들에 사과와 함께 문제를 고치겠다고 고백하였다.
(필자가 확실히 싫어함 ㅋㅋㅋ)
Future work
그는 DAX 와 페이지캐쉬에 대한 몇가지 enhancement 가 필요하다고 결론을 맺었다. 앞서 언급한 Hugepage 에 대한 향상을 지원하는 것이 그중 하나이고, 이미 이것들은 kernel-mm tree 에 놓여졌고 곧 완료 될 예정이라고 한다.
Page 구조체의 사용을 Page-frame numbers(PFN) 로 대체하는 것은 아직까지는 거대한 메모리 배열을 위해서 많은 수의 페이지 구조체들을 커널에 저장하는 것이 필요한지에 대한 요구가 매우 적기 때문에 계속 논의중이라 전한다.
그는 현재 시스템의 페이지 크기 보다 큰 Block size 를 갖고 있는 파일시스템에 대한 개념을 재조명 하고 싶어하며, 이제 페이지 캐쉬는 하나의 페이지 사이즈보다 더 큰 것을 다룰 수 있어야 한다며, 이 "단순한 코딩의 문제" 를 함께 할 팀을 구한다고 전했다. (약간 끝까지 까는느낌 -_-)
Huge swap 에 대한 항목들 또한 관심영역 중 하나라고 전했다.
우리는 huge anonymous pages 를 이용하지만 이것이 swap out 될 때는 regular pages 에서 해제되어야 하고, 이것은 옳은 해결이 아니라고 했다.
이 부분은 스왑 퍼포먼스를 향상시키는 일이지만 hugepages 를 그대로 유지시키는 방향으로 재조절 되야 한다. 영구적 메모리 swap 공간에 있는 데이타는 계속 엑세스 될 수 있으므로, 특별히 큰 수정이 필요하지 않을 경우 그대로 유지시키는 것이 더 명확할 수 있다는 것은 이 부분에 도움이 될 수 있다.
(즉, Hugepage 를 swap out 하려고 Memory zone 을 변환하거나 복제하고 파괴하는 동작 보다는, 계속 엑세스될 수 있는 데이타라는 것을 전제로 하여 Persisdent 영역의 스왑 방식을 도입해서 그대로 두는 것이 성능향상에 도움이 될 수 있다는 것을 의미한다고 볼 수 있다..)
컨퍼런스 영상은 아래 링크를 이용하면 되며 Page-cache locking 에 대한 유용한 보너스섹션도 소개하고 있다.