11 KiB
id, kind, slug, title, topic, topicName, project, status, basisVersion, studio, sourceRevision, assets, source
| id | kind | slug | title | topic | topicName | project | status | basisVersion | studio | sourceRevision | assets | source | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 68811272-5352-4409-aa20-7e22e601ede8 | CONCEPT | numa-locality-for-vcpu-and-memory | NUMA 에서는 vCPU 배치와 메모리 배치를 함께 본다 | memory-virtualization | 메모리 가상화 | virtualization | 초안 | multi-socket NUMA x86-64 · Linux lscpu 와 numactl · numastat · libvirt virsh vcpupin 과 vcpuinfo | https://hyeonworks.com/studio/documents/68811272-5352-4409-aa20-7e22e601ede8/edit | no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다 |
|
|
NUMA 에서는 vCPU 배치와 메모리 배치를 함께 본다
RAM 을 하나의 균일한 자원처럼 다루면 어느 CPU 가 읽든 비용이 같다. CPU 소켓이 둘 이상인 NUMA 시스템에서는 그 가정이 성립하지 않는다. 소켓마다 가까운 RAM 이 따로 있고, 다른 소켓의 RAM 을 읽으면 인터커넥트를 건너므로 추가 비용이 붙을 수 있다. 가상 머신에서 이것이 걸리는 이유는 게스트 vCPU 가 호스트에서는 QEMU 의 vCPU 스레드이기 때문이다. 그 스레드가 도는 노드와 그 가상 머신의 메모리가 놓인 노드가 어긋나면, 게스트 안에서는 단순한 메모리 접근인 동작이 실제 하드웨어에서는 다른 노드까지 건너가는 접근이 된다. 그래서 vCPU 를 어느 CPU 에 묶었는지만 보고 배치를 끝내지 않고 메모리가 어느 노드에 있는지를 함께 본다. CPU 가상화 쪽 문서가 메모리 배치와 NUMA 튜닝을 여기로 넘겼다.
관계
- KVM 에서 vCPU 가 물리 CPU 에서 실행되기까지 게스트 vCPU 가 QEMU vCPU 스레드로 호스트 스케줄러 위에서 실행된다는 것이 그쪽 설명이다. 이 글은 그 스레드가 도는 노드와 메모리가 있는 노드를 잇는다.
- Guest 메모리 주소가 물리 RAM 에 닿기까지 — GVA · GPA · HPA 변환이 끝나 닿는 HPA 가 어느 노드의 RAM 인지가 여기서 갈린다. 변환 방식은 그쪽이 설명한다.
- 이 호스트의 NUMA 토폴로지는 가상 머신 성능을 고려해야 할 구조인가 노드가 하나인지 둘 이상인지를 확정하는 질문이다. 그 답이 나오기 전에는 이 글의 어긋남이 이 환경에 있는지 알 수 없다.
- QEMU 메모리는 vCPU 가 도는 NUMA node 와 같은 node 에 있는가 이 글이 말한 어긋남을 이 호스트에서 실제로 재는 질문이다.
- NUMA remote access 가 이 작업의 지연을 실제로 바꾸는가 배치가 어긋나 있다는 사실과 그것이 지연을 바꾼다는 사실은 다르다. 뒤쪽을 그 질문이 받는다.
- 메모리 증상 하나로 계층을 단정하지 않는다 그 기준이 가르는 다섯 갈래 가운데 NUMA 갈래를 이 글이 설명한다.
본문
어느 CPU 가 어느 RAM 을 읽느냐로 비용이 갈린다
지금까지 RAM 은 하나의 균일한 자원처럼 다룰 수 있었다. CPU 소켓이 둘 이상인 NUMA 시스템에서는 어느 CPU 가 어느 RAM 에 접근하느냐에 따라 비용이 달라질 수 있다. NUMA(Non-Uniform Memory Access)는 이름 그대로 메모리 접근 비용이 균일하지 않다는 뜻이다.
구조는 이렇다. NUMA 노드마다 CPU 소켓이 있고 그 소켓에 붙은 로컬 RAM 이 있으며, 노드들은 인터커넥트(interconnect)로 이어져 있다. CPU 가 자기 노드의 RAM 을 읽으면 로컬 접근(local access)이고, 인터커넥트를 건너 다른 노드의 RAM 을 읽으면 원격 접근(remote access)이다. 일반적으로 원격 접근이 로컬 접근과 동일한 비용이라고 가정할 수 없으며, 추가 지연과 대역폭 비용이 있을 수 있다.
게스트의 메모리 접근이 인터커넥트를 건널 때
게스트 vCPU 는 호스트에서 QEMU 의 vCPU 스레드다. 그 스레드는 호스트 Linux 스케줄러를 거쳐 호스트 논리 CPU 에 배치되는데, 그 논리 CPU 는 어느 NUMA 노드엔가 속해 있다.
한 가상 머신의 vCPU 스레드가 노드 0 의 CPU 에서 실행되는데 그 가상 머신을 받치는 호스트 물리 페이지가 노드 1 에 있다고 하자. 그러면 노드 0 의 CPU 가 인터커넥트를 지나 노드 1 의 RAM 을 읽게 된다. 게스트 안에서는 그냥 메모리 접근 한 번이고 게스트 OS 는 그 요청이 소켓을 건넜는지 알지 못하는데, 비용은 그 아래 하드웨어에서 붙는다.
vCPU pinning 만으로는 끝나지 않는다
vCPU 를 특정 CPU 집합에 묶는 설정을 pinning 이라고 한다. 어떤 가상 머신의 vCPU 를 노드 0 의 CPU 에 pinning 했는데 그 가상 머신의 RAM 이 주로 노드 1 에 배치되어 있으면, pinning 이후에도 원격 접근이 많아질 수 있다. 묶은 것은 실행 위치이고 메모리가 어디에 있는지는 그 설정이 정하지 않기 때문이다.
그래서 vCPU 를 어디에서 실행할지와 메모리를 어느 노드에 두고 묶을지를 함께 봐야 NUMA locality 가 정해진다. 근거 문서가 든 이상적인 구성은 한 가상 머신의 vCPU 넷이 모두 노드 0 의 CPU 에서 실행되고 그 가상 머신의 메모리도 노드 0 의 RAM 에 있는 모양이다.
이 호스트가 노드 몇 개인지는 근거 문서에 없다. 하나로 나오면 지금 말한 어긋남은 이 환경에 성립하지 않는다.
큰 가상 머신에서는 게스트에게 토폴로지를 보여 준다
가상 머신이 커지면 그 안에서도 같은 문제가 생긴다. vCPU 열여섯 개와 RAM 64 GiB 를 가진 가상 머신을 하나의 균일한 메모리로 보이게 하면, 게스트 스케줄러는 어느 vCPU 가 어느 메모리에 가까운지 알 방법이 없다. 그래서 큰 가상 머신에서는 게스트에게 NUMA 토폴로지 자체를 노출할 수 있다. 게스트 NUMA 노드 0 에 vCPU 0~7 과 RAM 절반, 노드 1 에 vCPU 8~15 와 나머지 절반을 두는 식이다.
노출한 뒤에는 게스트가 인식하는 토폴로지와 실제 호스트 배치가 합리적으로 대응되도록 구성한다. 게스트 NUMA 0 이 호스트 NUMA 0 에, 게스트 NUMA 1 이 호스트 NUMA 1 에 대응하지 않으면, 게스트가 로컬이라고 판단해 고른 메모리가 호스트에서는 원격이 된다.
이 프로젝트의 가상 머신이 그런 크기인지는 근거 문서에 적혀 있지 않다. vCPU 수도 설정한 RAM 도 나오지 않아서, 이 절이 이 환경에 걸리는 이야기인지는 그 값을 적은 뒤에 정해진다.
이 장비의 토폴로지부터 읽는다
호스트가 NUMA 노드 한 개라면 노드를 건너는 원격 접근 문제가 주요 이슈가 아닐 수 있으므로, 실제 환경에서는 토폴로지를 먼저 측정하고 NUMA 최적화가 필요한지 판단한다.
lscpu
numactl --hardware
lscpu 는 노드 수와 노드별 CPU 목록을 알려 준다. 근거 문서가 든 출력 예시는 이런 모양이고, 이 테스트 서버에서 읽은 값이 아니다.
NUMA node(s): 2
NUMA node0 CPU(s): 0-7
NUMA node1 CPU(s): 8-15
numactl --hardware 는 여기에 노드별 메모리 크기와 노드 사이 거리를 더해 준다. 노드가 둘 이상으로 나오면 그다음은 이 가상 머신들이 어디에 있는지를 본다.
numastat -p <QEMU_PID>
virsh vcpupin <VM_NAME>
virsh vcpuinfo <VM_NAME>
numastat 은 지정한 프로세스의 메모리가 노드마다 얼마씩 있는지 보여 주므로, QEMU 프로세스를 지정하면 그 가상 머신의 메모리가 어느 노드에 얼마나 놓여 있는지 나온다. virsh vcpupin 과 virsh vcpuinfo 는 같은 가상 머신의 vCPU 가 어느 CPU 에 묶여 있고 어디서 실행 중인지 알려 준다. 두 출력을 나란히 놓아야 앞 절의 어긋남이 이 장비에 있는지 없는지 말할 수 있다.
근거 문서가 번호를 붙여 둔 문장
근거 문서는 이 대목에서 고정한 문장에 번호를 붙여 두었다. 실험 기록에서 어느 문장을 확인했는지 가리킬 때 이 번호를 쓴다.
| 번호 | 근거 문서가 고정한 문장 |
|---|---|
| CLAIM-MEM-18 | NUMA 시스템에서는 vCPU placement와 memory placement를 함께 봐야 한다. |
이 문서가 확정하지 않는 것
이 글이 확정하는 것은 배치가 어긋나면 무엇이 원격 접근이 되는가까지다. 이 테스트 서버에서 잰 값은 하나도 없다.
이 호스트가 노드 하나인지 여럿인지가 정해지지 않았다. 노드 하나로 나오면 앞 절의 어긋남이 이 환경에 성립하지 않으므로 NUMA 를 현재 실험에서 뒤로 미룬다. 여럿으로 나와야 QEMU 프로세스의 노드별 메모리 분포와 vCPU 배치를 나란히 적는 확인이 의미를 갖는다. 토폴로지 확인은 CPU 가상화 쪽 질문이 받고 있다.
배치가 어긋나 있다는 것과 그 어긋남이 이 작업의 지연을 바꾼다는 것도 다른 사실이다. 근거 문서는 토폴로지만 보고 성능 문제라고 단정하지 말라고 적었다. vCPU 와 메모리를 같은 노드로 맞춘 구성과 원격 접근이 많아지도록 바꾼 구성에서 같은 작업을 같은 조건으로 돌려 지연과 처리량을 견줘야 답이 나온다. 이 가상 머신들에 게스트 NUMA 를 노출했는지도 근거 문서에 없다. 세 확인은 각각 열린 질문으로 두었고 관계에 걸어 두었다.