对于物理机来说, CPU 有 socket 、 Core 、 thread 的概念,一个 linux 虚拟机上面同样有这些信息,这些信息是什么含义,和物理机之间有多少对应关系呢?如何分配 CPU 拓扑,会得到较好的性能?
一个服务器可以有多个 socket
一个 socket (插槽)可以插一个 chip 。
一个 chip 里面可以有 N 个 core (核)
一个核里面可以有 1 个 CPU 线程,如果开启超线程, CPU 线程 = 核 *2
上面这些信息是 x86 CPU 。如果是 Power 的 CPU ,超线程可以一个核超出来 2 个、 4 个、 8 个(根据机器型号)。同时,还有一个 drawer (抽屉)的概念。一个抽屉里面有 N 个 socket ,一个服务器可以有多个抽屉。
对于虚拟机来说,操作系统看到的 CPU 信息都是虚拟的,但操作系统认为他们是物理的。
查看虚拟机 CPU 的方法和物理机没什么区别,一般用 lscpu 或者 cat /proc/cpuinfo 来查看
拿一台虚拟的 linux 举例
这个是 linux 操作系统看到的 CPU 信息, linux 操作系统并不知道自己跑在一个虚拟机上,虽然看到的 CPU 都是虚拟的,但 linux 认为这些都是真的,因此在进程调度上,也会按照这个信息去调度。
CPU(s): 8 : 一共 8 个逻辑 CPU ,即 8 个 vCPU
Thread(s) per core: 1 :每个核有几个线程,分配虚拟机的时候,拓扑默认就是 1
Core(s) per socket: 1 :每个插槽(一个插槽可以插一个 cpu chip )里面有几个核,分配虚拟机的时候,拓扑默认就是 1
Socket(s): 8 :有几个插槽(一个插槽可以插一个 cpu chip )
这一段的信息是,该虚拟机一共有 8 个 chip ,每个 chip 里有 1 个核,每个核里有 1 个 thread 。这样就是 811=8 个 thread ,即 8 个逻辑 CPU ,即 8 个 vCPU 。
注:这里的 socket 、 core 都是虚的。
接下来,看 cpuinfo 里面的信息(和 lscpu 是一致的)
processor: 0 :虚拟 CPU ( vCPU )的 ID , OS 以为这是物理的,其实是虚拟的。这里的 processor 不是虚拟核,而是虚拟 CPU 线程。因为如果如果分配虚拟机的时候,虚拟核开启超线程( 2 ),那么虚拟 CPU 线程 = 虚拟核 *2
physical id: 0 :这个是虚拟 socket ( chip )的 ID 。在本例中,给虚拟机分配了 8 个 sockets ,那么 physical id 会有 8 个,分别是 0-7.
siblings: 1 :一个虚拟 socket 上有多少虚拟 CPU 线程。如果 =1 ,那么只有 1 个 thread ( processor )。说明这个 socket 上只有一个 core ,这个 core 里只有一个 thread ( processor )。
core id: 0 :这是虚拟 core 的 id 号,每个虚拟 core 可以有 1 个虚拟 thread ( processor ),如果分配虚拟机的时候,虚拟核开启超线程( 2 ),那么每个虚拟 core 可以有 2 个虚拟 thread ( processor )
cpu cores: 虚拟 core 的数量
收集全部 cpuinfo 的信息如下
processor | physical id | sibling | core id | cpu cores |
0 | 0 | 1 | 0 | 1 |
1 | 2 | 1 | 0 | 1 |
2 | 4 | 1 | 0 | 1 |
3 | 6 | 1 | 0 | 1 |
4 | 8 | 1 | 0 | 1 |
5 | 10 | 1 | 0 | 1 |
6 | 12 | 1 | 0 | 1 |
7 | 14 | 1 | 0 | 1 |
即分配多少逻辑 CPU ,这些逻辑 CPU 是如何通过 socket 、 core 、超线程组合出来的。
分配虚拟机时,需要指定多少 socket (插槽)、每个插槽有多少 core , core 有没有超线程。
同样是分配 8 个逻辑 CPU ,也可以采用其他的拓扑。
本例中,分配的方式我们再回顾一下
CPU(s): 8
Thread(s) per core: 1
Core(s) per socket: 1
Socket(s): 8
分配 8 个 vCPU :该虚拟机一共有 8 个 chip ,每个 chip 里有 1 个核,每个核里有 1 个 thread 。这样就是 811=8 个 thread ,即 8 个 vCPU 。
换成拓扑 B :
CPU(s): 8
Thread(s) per core: 2
Core(s) per socket: 4
Socket(s): 1
Cpuinfo 对应的信息如下
processor | physical id | sibling | core id | cpu cores |
0 | 0 | 8 | 0 | 4 |
1 | 0 | 8 | 1 | 4 |
2 | 0 | 8 | 2 | 4 |
3 | 0 | 8 | 3 | 4 |
4 | 0 | 8 | 0 | 4 |
5 | 0 | 8 | 1 | 4 |
6 | 0 | 8 | 2 | 4 |
7 | 0 | 8 | 3 | 4 |
换成拓扑 C :
CPU(s): 8
Thread(s) per core: 1
Core(s) per socket: 8
Socket(s): 1
拓扑的排列组合还可以有很多其他方式。
首先操作系统会看这个拓扑,在进程调度时为了保持亲和性,会优先把同一个进程调度到同一个 core 上,如果不能调度到同一个 core ,则尽量调度到同一个 socket 上。
虚拟化平台,也许也会倾向于把同一个虚拟 core 、虚拟 socket 调度到同一个物理 core 、物理 socket 上。至于具体到某个虚拟化平台( VMware 、 KVM 、 Hyper-V 、 Citrix )是怎么调度的,肯定是各有各的算法。
因此,如果想收获比较好的虚拟机性能表现,把虚拟机的 CPU 拓扑设置为和物理机一致,这样在亲和性保持上比较有利。如果不一致,就不利。
举一个不一致的例子。
物理机拓扑: 2 个 sockets 、每个 socket 有 4 个 cores ,每个 core 有一个 thread 。
虚拟机拓扑: 1 个 sockets 、每个 socket 有 8 个 cores ,每个 core 有一个 thread 。
在 OS 进程调度时,如果同一个进程不能调度到同一个虚拟 core (名叫 A )上,它会调度到同一个 socket 上其他 core , OS 一看拓扑,大家都在同一个 socket ,于是就随便调度到一个 core (名叫 F )。
而在物理机层面,这个 8 个虚拟 core 不可能调度到同一个 socket (假设叫 1 )上,因为一个 socket 只有 4 个 cores 。结果, core ( F )就被调度到 Socket (名叫 2 )上了。
于是上下文切换的代价就明显增高。
如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!
赞4
添加新评论1 条评论
2021-04-14 12:00