KVM虚拟机CPU的软件调优首先需要对NUMA技术有一定了解,调优的主要手段就是虚拟机对物理机CPU逻辑内核的手工绑定。 内存方面的调优手段主要是KSM,即相同内存页合并、内存气球技术以及大页内存的使用。

NUMA架构理解

NUMA技术与应用

多CPU共同工作技术的架构:SMP,MPP,NUMA

1.1 SMP技术: 多个cpu通过一个总线访问存储器,因此SMP系统有时也被称为一致性内存访问(UMA)结构体系。一致性指无论在什么时候,处理器只能为内存的每个数据保持或共享唯一一个数值。(多个cpu通过总线访问共同的内存)。缺点是扩展性有限,存储器接口达到饱和的时候,增加处理器不能获得更高的性能,因此SMP方式支持的CPU个数有限啊

1.2 MPP模式: 一种分布式存储器模式,能够将更多的处理器纳入一个系统的存储器,一个分布式存储器模式具有多个节点,每个节点都有自己的存储器,可以配置为SMP模式。单个节点相互连接起来形成一个总系统。MPP可以近似理解成一个SMP的横向扩展集群。MPP一般依靠软件实现。

1.3 NUMA技术: 每个处理器都有自己的存储器,每个处理器也可以访问别的处理器的存储器。 多核NUMA CPU架构: NUMA node1: NUMA node2: Core1 Core2 Core1 Core2 CPU0 CPU1 Core3 Core4 Core3 Core4

查看cpu详情

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                32                   //共有32个逻辑CPU(threads)
On-line CPU(s) list:   0-31
Thread(s) per core:    2                    //每个core有2个threads
Core(s) per socket:    8                    //每个socket有8个cores
Socket(s):             2                    //共有2个sockets
NUMA node(s):          2                    //共有2个NUMA nodes
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 63
Stepping:              2
CPU MHz:               2600.014
BogoMIPS:              5199.25
Virtualization:        VT-x
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              20480K
NUMA node0 CPU(s):     0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30
NUMA node1 CPU(s):     1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31

# 2(node/socket)*8(8cores/socket)*2(2threads/core)
2 Sockets 2 CPUs ,1Socket 1 numa node,1 numa node 8 cores,1 core 2 threads

KVM虚拟机NUMA调优

宿主机的NUMA信息查看和配置:

因为NUMA架构每个处理器都可以访问自己和别的处理器的存储器,访问自己的存储器要比访问别的存储器快很多,相差10~100倍,所以NUMA调优的目标就是让处理器尽量访问自己的存储器。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# sh getcpuinfo.sh
===== CPU Topology Table =====

+--------------+---------+-----------+
| Processor ID | Core ID | Socket ID |
+--------------+---------+-----------+
| 0            | 0       | 0         |
+--------------+---------+-----------+
| 1            | 0       | 1         |
+--------------+---------+-----------+
| 2            | 1       | 0         |
+--------------+---------+-----------+
| 3            | 1       | 1         |
+--------------+---------+-----------+
| 4            | 2       | 0         |
+--------------+---------+-----------+
| 5            | 2       | 1         |
+--------------+---------+-----------+
| 6            | 3       | 0         |
+--------------+---------+-----------+
| 7            | 3       | 1         |
+--------------+---------+-----------+
| 8            | 4       | 0         |
+--------------+---------+-----------+
| 9            | 4       | 1         |
+--------------+---------+-----------+
| 10           | 5       | 0         |
+--------------+---------+-----------+
| 11           | 5       | 1         |
+--------------+---------+-----------+
| 12           | 6       | 0         |
+--------------+---------+-----------+
| 13           | 6       | 1         |
+--------------+---------+-----------+
| 14           | 7       | 0         |
+--------------+---------+-----------+
| 15           | 7       | 1         |
+--------------+---------+-----------+
| 16           | 0       | 0         |
+--------------+---------+-----------+
| 17           | 0       | 1         |
+--------------+---------+-----------+
| 18           | 1       | 0         |
+--------------+---------+-----------+
| 19           | 1       | 1         |
+--------------+---------+-----------+
| 20           | 2       | 0         |
+--------------+---------+-----------+
| 21           | 2       | 1         |
+--------------+---------+-----------+
| 22           | 3       | 0         |
+--------------+---------+-----------+
| 23           | 3       | 1         |
+--------------+---------+-----------+
| 24           | 4       | 0         |
+--------------+---------+-----------+
| 25           | 4       | 1         |
+--------------+---------+-----------+
| 26           | 5       | 0         |
+--------------+---------+-----------+
| 27           | 5       | 1         |
+--------------+---------+-----------+
| 28           | 6       | 0         |
+--------------+---------+-----------+
| 29           | 6       | 1         |
+--------------+---------+-----------+
| 30           | 7       | 0         |
+--------------+---------+-----------+
| 31           | 7       | 1         |
+--------------+---------+-----------+

Socket 0: 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
Socket 1: 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31

===== CPU Info Summary =====

Logical processors: 32
Physical socket: 2
Siblings in one socket:  16
Cores in one socket:  8
Cores in total: 16
Hyper-Threading: on

===== END =====

查看numa架构模式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# cat /sys/bus/pci/devices/0000\:07\:00.0/numa_node
0

使用numactl --hardware查看当前CPU硬件的情况:

由以下信息可以看到,当前CPU有两颗,每颗CPU8核,每颗CPU有64G内存可以使用
# numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
node 0 size: 65490 MB
node 0 free: 501 MB
node 1 cpus: 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31
node 1 size: 65536 MB
node 1 free: 185 MB
node distances:
node   0   1
  0:  10  20
  1:  20  10

查看每个node的内存情况

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
使用numastat命令可以查看每个节点的内存情况:
# numastat
                           node0           node1
numa_hit             11541910709      7342897046		#使用本节点内存次数
numa_miss               10973455        14712396		#计划使用本节点而被调度到其他节点次数
numa_foreign            14712396        10973455		#计划使用其他节点内存而被使用本地内存次数
interleave_hit             32651           32580		#交叉分配使用的内存中使用本节点的内存次数
local_node           11540101051      7342503537		#在本节点运行的程序使用本节点内存的次数
other_node              12783113        15105905		#在其他节点运行的程序使用本节点内存次数



使用numastat -c 查看相关进程的NUMA内存使用情况:
# numastat -c qemu-kvm

Per-node process memory usage (in MBs)
PID              Node 0 Node 1  Total
---------------  ------ ------ ------
27822 (qemu-kvm)   5786   2449   8236
27947 (qemu-kvm)   5503   2729   8232
28108 (qemu-kvm)   4154   4116   8269
28295 (qemu-kvm)   5845   2410   8255
32840 (qemu-kvm)   5652   2749   8401
32994 (qemu-kvm)   6229   2095   8324
33235 (qemu-kvm)   3086   5287   8373
33453 (qemu-kvm)   3577   4817   8394
33620 (qemu-kvm)   5112   3326   8438
33893 (qemu-kvm)   5529   2863   8391
34141 (qemu-kvm)   4745   3689   8434
34318 (qemu-kvm)   2414   5989   8404
---------------  ------ ------ ------
Total             57632  42519 100151

Liunx系统默认是自动NUMA平衡策略,如果需要关闭Linux系统的自动平衡,可以使用如下命令:
echo 0 > /proc/sys/kernel/numa_balancing

虚拟机NUMA信息查看与配置

查看虚拟机VCPU和物理CPU的对应关系:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# virsh vcpuinfo xxbandy.github.io
VCPU:           0
CPU:            12
State:          running
CPU time:       466238.9s
CPU Affinity:   yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy

VCPU:           1
CPU:            5
State:          running
CPU time:       387815.5s
CPU Affinity:   yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy

VCPU:           2
CPU:            4
State:          running
CPU time:       397013.3s
CPU Affinity:   yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy

VCPU:           3
CPU:            31
State:          running
CPU time:       389255.3s
CPU Affinity:   yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
最后一行CPU亲和性:

透明大页技术与应用

X86默认的内存页大小是4KB,也可以使用2MB或者1GB的巨型页,系统的巨型页可以传输过虚拟机,kvm虚拟机可以通过分配巨型页提高性能。 使用巨型页可以提高内存的分配效率,提升系统性能。

使用透明大页的好处: 可以使用swap,内存页默认2MB,需要使用swap的时候,内存被分割为4KB。 对用户透明,不需要用户做特殊配置。 不需要root权限 不需要依赖某种库文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
透明大页内存配置:
# cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never
修改配置:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
参数说明:
	never:关闭,不使用透明内存
	alway:尽量使用透明内存,扫描内存,有512个4KB页面可以整合,就整合成一个2MB的页面。
	madvise:避免改变内存占用

使用情况监控:
$ cat /sys/kernel/mm/transparent_hugepage/khugepaged/pages_to_scan 默认(4096=16MB)一个扫描周期被扫描的内存页数
4096
$ cat /sys/kernel/mm/transparent_hugepage/khugepaged/scan_sleep_millisecs 默认(10000=10s)多长时间扫描一次
10000
$ cat /sys/kernel/mm/transparent_hugepage/khugepaged/alloc_sleep_millisecs 默认(60000=60s)多长时间整理一次碎片
60000
也可以查看meminfo信息;查看当前的巨型页值:
$ grep Huge /proc/meminfo
AnonHugePages:  102537216 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB

查看当前巨型页使用情况
$ cat /proc/sys/vm/nr_hugepages
0
巨型页默认大小是2MB,可以修改使用的巨型页数量:
echo 25000 > /proc/sys/vm/nr_hugepages
或者:
sysctl vm.nr_hugepages = N