NUMA 관련 설명 내용
1. NUMA 아키텍처
# NUMA : Non-Uniform Memory Access, 불균형 메모리 접근 / 멀티 프로세서 환경에서 적용되는
# 메모리 접근 방식
# 리눅스 NUMA 확인
$ sudo yum install -y numactl
$ numactl --show
policy: default
preferred node: current
physcpubind: 0 1 2 3
cpubind: 0
nodebind: 0
membind: 0
# 기본정책 : default
# default : 별도 설정 없이 모든 프로세스에 적용, 현재 프로세스가 실행되고 있는 프로세서가
# 포함된 노드에서 먼저 메모리를 할당 받아 사용
# bind : 특정 프로세스를 특정 노드에 바인딩시키는 방식
# preferred : bind와 비슷하지만 선호하는 노드를 설정
# interleaved : 다수의 노드에서 거의 동일한 비율로 메모리를 할당
$ numactl -H
available: 1 nodes (0)
node 0 cpus: 0 1 2 3
node 0 size: 15898 MB
node 0 free: 1696 MB
node distances:
node 0
0: 10
# available : NUMA 노드가 1개로 구성
# node 0 cpus : node에 해당하는 cpu 번호
# node 0 : node 번호
# node distances : 노드가 메모리에 접근하는 시간을 의미, 로컬 메모리에 접근할 때
# 소요되는 시간을 "10"이다.
$ numastat -cm
Per-node system memory usage (in MBs):
Token Node not in hash table.
Token Node not in hash table.
Node 0 Total
------ -----
MemTotal 15898 15898
MemFree 2656 2656
MemUsed 13243 13243
Active 11814 11814
Inactive 1254 1254
Active(anon) 11618 11618
Inactive(anon) 1183 1183
Active(file) 197 197
Inactive(file) 72 72
Unevictable 0 0
Mlocked 0 0
Dirty 0 0
Writeback 0 0
FilePages 449 449
Mapped 75 75
AnonPages 12723 12723
Shmem 0 0
KernelStack 10 10
PageTables 37 37
NFS_Unstable 0 0
Bounce 0 0
WritebackTmp 0 0
Slab 45 45
SReclaimable 19 19
SUnreclaim 25 25
AnonHugePages 0 0
HugePages_Total 0 0
HugePages_Free 0 0
HugePages_Surp 0 0
# "numastat" 명령으로 NUMA 아키텍처에서 메모리 불균형 상태를 확인할 수 있다.
# 한쪽 노드의 메모리 사용률일 높으면 메모리 할당 정책에 따라 swap을 사용하는 경우도 있기 때문
# 전체 메모리에는 free 영역이 많이 있는데도 한쪽 노드에서 메모리 할당이 과하게 일어나면 swap을
# 사용하게 된다.
$ sudo cat /proc/6545/numa_maps
707800000 default anon=158911 dirty=158745 swapcache=166 active=134811 N0=158911 kernelpagesize_kB=4
736600000 default
7ffe00000 default file=/usr/lib/jvm/java-11-openjdk-11.0.7.10-4.amzn2.0.1.x86_64/lib/server/classes.jsa anon=70 dirty=62 mapped=71 mapmax=11 swapcache=8 active=34 N0=71 kernelpagesize_kB=4
7ffe47000 default
7fff00000 default file=/usr/lib/jvm/java-11-openjdk-11.0.7.10-4.amzn2.0.1.x86_64/lib/server/classes.jsa anon=106 dirty=81 swapcache=25 active=105 N0=106 kernelpagesize_kB=4
7fff6a000 default
...
# numa_maps로 프로세스가 어떤 메모리 할당 정책으로 실행되었는지를 확인할 수 있다.
# 위 방식은 NUMA "default" 방식으로 실행된 것을 알수 있다.
$ numastat 6545
Per-node process memory usage (in MBs) for PID 6545 (java)
Node 0 Total
--------------- ---------------
Huge 0.00 0.00
Heap 3.06 3.06
Stack 0.04 0.04
Private 898.62 898.62
---------------- --------------- ---------------
Total 901.71 901.71
# numastat 명령으로 확인하면 실제 프로세스가 어떤 노드로부터 메모리를 할당받아서
# 사용하고 있는지 확인할 수 있다.
# 위 코드를 보면 0번 노드에서 할당 받아 동작 중이다.
2. numad를 이용한 메모리 할당 관리
# numad를 통해 numa 메모리 할당 과정을 주기적으로 살펴보고 프로세스들을 최적화 하는 작업을 담당한다.
# numad를 통해 프로세스를 관리하면 메모리의 지역성을 높이고 성능을 최적화할 수 있다.
2.1 vm.zone_reclaim_mode
# 이 커널 파라미터는 numa 아키텍처에서 메모리 할당에 영향을 주는 파라미터
$ sudo cat /proc/buddyinfo
Node 0, zone DMA 1 0 0 1 2 1 1 0 1 1 3
Node 0, zone DMA32 9624 5461 3640 2697 1938 2185 1491 785 424 91 10
Node 0, zone Normal 215 501 7493 1774 1810 59 53 1 0 0 0
# DMA : Direct Memory Access, 오래된 하드웨어 동작을 위해 존재하는 영역
# Normal : 일반적인 용도로 사용되는 영역, 커널/프로세스 등이 메모리를 필요할 때 Normal
# 영역에서 메모리를 할당 받아서 사용한다.
# vm.zone_reclaim_mode : 메모리 영역(DMA, Normal)에서 특정 영역의 메모리가 부족한
# 경우 다른 영역의 메모리를 할당할 수 있게 해주느 파라미터이다.
# vm.zone_reclaim_mode 파라미터는 4개의 값을 가질 수 있음.
# 0 : disable을 의미, zone 안에서 재할당하지 않음
# - 값이 0이면, 페이지 캐시 등과 같은 재할당 대상 메모리들이 반환되지 않고 다른 노드에
# 있는 메모리를 할당 받아서 사용한다.
# 참고) 파일서버와 같이 다수의 I/O가 발생하는 서버의 경우 많은양의 페이지 캐시를 확보함으로써
# 이점이 크기 때문에 "0"으로 사용하는 것이 좋다.
# 1 : enable을 의미, zone 안에서 재할당을 한다는 의미
# - 값이 1이면, 페이지 캐시 확보보다는 메모리에 대한 로컬 액세스 방식이 성능상
# 더 유리하므로 값을 "1"로 사용하는 것이 좋다.
3. numa 아키텍처 메모리 할당 정책
# 1. 메모리가 노드 하나의 크기를 넘지 않고 프로세스도 싱글 스레드로 동작하는 경우
# - 이런 경우는 거의 없다. 해당 워크로드는 UMA 아키텍처를 사용하는 것이 가장 최적합하다.
# 2. 메모리가 노드 하나 크기를 넘지않고 프로세스가 멀티 스레드로 동작하는 경우
# - cpunodebind 모드를 통해서 여러 개의 코어에 프로세스를 바인딩시키고 해당 노드에서만 메모리를 할당
# 받아서 사용하는 것이 가장 좋다. "vm.zone_reclaim_mode = 1"로 적용하는 것이 효과적
# 3. 메모리가 노드 하나의 크기를 넘고 프로세스가 싱글 스레드로 동작하는 경우
# - cpunodebind 모드를 통해 리모트 액세스를 최소화 하는 것이 좋다. 이 경우 "vm.zone_reclaim_mode = 0"
# 으로 하는 것이 성능에 유리하다.
# 4. 메모리가 노드 하나의 크기를 넘고 프로세스가 멀티 스레드로 동작하는 경우
# - 이 경우가 가장 많다. 이 경우에는 interleave 모드가 최적의 성능을 낼 수 있다.
# "vm.zone_reclaim_mode = 0" 으로 지정하는 것이 성능 면에서 좋다.