# 管理系统资源

使用libvirt命令来管理虚拟机的系统资源，如vCPU、虚拟内存资源等。

在开始前：

-   确保主机上运行了libvirtd守护进程。
-   用virsh list --all命令确认虚拟机已经被定义。

<!-- TOC -->
    -   [管理系统资源](#管理系统资源)
        -   [管理虚拟CPU](#管理虚拟CPU)
            -   [CPU份额](#CPU份额)
            -   [绑定QEMU进程至物理CPU](#绑定QEMU进程至物理CPU)
            -   [调整虚拟CPU绑定关系](#调整虚拟CPU绑定关系)
        -   [管理虚拟内存](#管理虚拟内存)
            -   [NUMA简介](#NUMA简介)
            -   [配置Host NUMA](#配置Host-NUMA)
            -   [配置Guest NUMA](#配置Guest-NUMA)
<!-- /TOC -->




## 管理虚拟CPU

### CPU份额

#### 概述

虚拟化环境下，同一主机上的多个虚拟机竞争使用物理CPU。为了防止某些虚拟机占用过多的物理CPU资源，影响相同主机上其他虚拟机的性能，需要平衡虚拟机vCPU的调度，避免物理CPU的过度竞争。

CPU份额表示一个虚拟机竞争物理CPU计算资源的能力大小总和。用户通过调整cpu\_shares值能够设置虚拟机抢占物理CPU资源的能力。cpu\_shares值无单位，是一个相对值。虚拟机获得的CPU计算资源，是与其他虚拟机的CPU份额，按相对比例，瓜分物理CPU除预留外可用计算资源。通过调整CPU份额来保证虚拟机CPU计算资源服务质量。

#### 操作步骤

通过修改分配给虚拟机的运行时间的cpu\_shares值，来平衡vCPU之间的调度。

-   查看虚拟机的当前CPU份额：

    ```
    $ virsh schedinfo <VMInstance>
    Scheduler      : posix
    cpu_shares     : 1024
    vcpu_period    : 100000
    vcpu_quota     : -1
    emulator_period: 100000
    emulator_quota : -1
    global_period  : 100000
    global_quota   : -1
    iothread_period: 100000
    iothread_quota : -1
    ```


-   在线修改：修改处于running状态的虚拟机的当前CPU份额，使用带**--live**参数的virsh schedinfo命令：

    ```
    $ virsh schedinfo <VMInstance> --live cpu_shares=<number>
    ```

    比如将正在运行的虚拟机openEulerVM的CPU份额从1024改为2048：

    ```
    $ virsh schedinfo openEulerVM --live cpu_shares=2048
    Scheduler      : posix
    cpu_shares     : 2048
    vcpu_period    : 100000
    vcpu_quota     : -1
    emulator_period: 100000
    emulator_quota : -1
    global_period  : 100000
    global_quota   : -1
    iothread_period: 100000
    iothread_quota : -1
    ```

    对cpu\_shares值的修改立即生效，虚拟机_openEulerVM_能得到的运行时间将是原来的2倍。但是这一修改将在虚拟机关机并重新启动后失效。

-   持久化修改：在libvirt内部配置中修改虚拟机的CPU份额，使用带**--config**参数的virsh schedinfo命令：

    ```
    $ virsh schedinfo <VMInstance> --config cpu_shares=<number>
    ```

    比如将虚拟机openEulerVM的CPU份额从1024改为2048：

    ```
    $ virsh schedinfo openEulerVM --config cpu_shares=2048
    Scheduler      : posix
    cpu_shares     : 2048
    vcpu_period    : 0
    vcpu_quota     : 0
    emulator_period: 0
    emulator_quota : 0
    global_period  : 0
    global_quota   : 0
    iothread_period: 0
    iothread_quota : 0
    ```

    对cpu\_shares值的修改不会立即生效，在虚拟机openEulerVM下一次启动后才生效，并持久生效。虚拟机openEulerVM能得到的运行时间将是原来的2倍。


### 绑定QEMU进程至物理CPU

#### 概述

QEMU主进程绑定特性是将QEMU主进程绑定到特定的物理CPU范围内，从而保证了运行不同业务的虚拟机不会干扰到邻位虚拟机。例如在一个典型的云计算场景中，一台物理机上会运行多台虚拟机，而每台虚拟机的业务不同，造成了不同程度的资源占用，为了避免存储IO密集的虚拟机对邻位虚拟机的干扰，需要将不同虚拟机处理IO的存储进程完全隔离，由于QEMU主进程是处理前后端的主要服务进程，故需要实现隔离。

#### 操作步骤

通过virsh emulatorpin命令可以绑定QEMU主进程到物理CPU。

-   查看QEMU进程当前绑定的物理CPU范围：

    ```
    $ virsh emulatorpin openEulerVM
    emulator: CPU Affinity
    ----------------------------------
           *: 0-63
    ```

    这说明虚拟机_openEulerVM_对应的QEMU主进程可以在主机的所有物理CPU上调度。

-   在线绑定：修改处于running状态的虚拟机对应的QEMU进程的绑定关系，使用带**--live**参数的vcpu emulatorpin命令：

    ```
    $ virsh emulatorpin openEulerVM --live 2-3
    
    $ virsh emulatorpin openEulerVM
    emulator: CPU Affinity
    ----------------------------------
           *: 2-3
    ```

    以上命令把虚拟机_open__Euler__VM_对应的QEMU进程绑定到物理CPU2、3上，即限制了QEMU进程只在这两个物理CPU上调度。这一绑定关系的调整立即生效，但在虚拟机关机并重新启动后失效。

-   持久化绑定：在libvirt内部配置中修改虚拟机对应的QEMU进程的绑定关系，使用带**--config**参数的virsh emulatorpin命令：

    ```
    $ virsh emulatorpin openEulerVM --config 0-3,^1
    
    $ virsh emulatorpin openEulerVM --config
    emulator: CPU Affinity
    ----------------------------------
           *: 0,2-3
    ```

    以上命令把虚拟机_open__Euler__VM_对应的QEMU进程绑定到物理CPU0、2、3上，即限制了QEMU进程只在这三个物理CPU上调度。**这一绑定关系的调整不会立即生效，在虚拟机下一次启动后才生效，并持久生效**。


### 调整虚拟CPU绑定关系

#### 概述

把虚拟机的vCPU绑定在物理CPU上，即vCPU只在绑定的物理CPU上调度，在特定场景下达到提升虚拟机性能的目的。比如在NUMA系统中，把vCPU绑定在同一个NUMA节点上，可以避免vCPU跨节点访问内存，避免影响虚拟机运行性能。如果未绑定，默认vCPU可在任何物理CPU上调度。具体的绑定策略由用户来决定。

#### 操作步骤

通过virsh vcpupin命令可以调整vCPU和物理CPU的绑定关系。

-   查看虚拟机的当前vCPU绑定信息：

    ```
     $ virsh vcpupin openEulerVM
     VCPU   CPU Affinity
    ----------------------
     0      0-63
     1      0-63
     2      0-63
     3      0-63
    ```

    这说明虚拟机_openEulerVM_的所有vCPU可以在主机的所有物理CPU上调度。

-   在线调整：修改处于running状态的虚拟机的当前vCPU绑定关系，使用带**--live**参数的vcpu vcpupin命令：

    ```
     $ virsh vcpupin openEulerVM  --live 0 2-3
    
     $ virsh vcpupin openEulerVM
     VCPU   CPU Affinity
    ----------------------
     0      2-3
     1      0-63
     2      0-63
     3      0-63
    ```

    以上命令把虚拟机_open__Euler__VM_的vCPU0绑定到PCPU2、3上，即限制了vCPU0只在这两个物理CPU上调度。这一绑定关系的调整立即生效，但在虚拟机关机并重新启动后失效。

-   持久化调整：在libvirt内部配置中修改虚拟机的vCPU绑定关系，使用带**--config**参数的virsh vcpupin命令：

    ```
     $ virsh vcpupin openEulerVM --config 0 0-3,^1
    
     $ virsh vcpupin openEulerVM --config
     VCPU   CPU Affinity
    ----------------------
     0      0,2-3
     1      0-63
     2      0-63
     3      0-63
    ```

    以上命令把虚拟机_open__Euler__VM_的vCPU0绑定到物理CPU0、2、3上，即限制了vCPU0只在这三个物理CPU上调度。**这一绑定关系的调整不会立即生效，在虚拟机下一次启动后才生效，并持久生效**。


## 管理虚拟内存

### NUMA简介

传统的多核运算使用SMP（Symmetric Multi-Processor）模式：将多个处理器与一个集中的存储器和I/O总线相连。所有处理器只能访问同一个物理存储器，因此SMP系统也被称为一致存储器访问（UMA）系统。一致性指无论在什么时候，处理器只能为内存的每个数据保持或共享唯一一个数值。很显然，SMP的缺点是可伸缩性有限，因为在存储器和I/O接口达到饱和的时候，增加处理器并不能获得更高的性能。

NUMA（Non Uniform Memory Access Architecture） 模式是一种分布式存储器访问方式，处理器可以同时访问不同的存储器地址，大幅度提高并行性。 NUMA模式下，处理器被划分成多个“节点”（NODE）， 每个节点分配一块本地存储器空间。所有节点中的处理器都可以访问全部的物理存储器，但是访问本节点内的存储器所需要的时间，比访问某些远程节点内的存储器所花的时间要少得多。

### 配置Host-NUMA

为提升虚拟机性能，在虚拟机启动前，用户可以通过虚拟机XML配置文件为虚拟机指定主机的NUMA节点，使虚拟机内存分配在指定的NUMA节点上。本特性一般与vCPU绑定一起使用，从而避免vCPU远端访问内存。

#### 操作步骤

-   查看host的NUMA拓扑结构：

    ```
     $ numactl -H
    available: 4 nodes (0-3)
    node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    node 0 size: 31571 MB
    node 0 free: 17095 MB
    node 1 cpus: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
    node 1 size: 32190 MB
    node 1 free: 28057 MB
    node 2 cpus: 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
    node 2 size: 32190 MB
    node 2 free: 10562 MB
    node 3 cpus: 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
    node 3 size: 32188 MB
    node 3 free: 272 MB
    node distances:
    node   0   1   2   3
      0:  10  15  20  20
      1:  15  10  20  20
      2:  20  20  10  15
      3:  20  20  15  10
    ```

-   在虚拟机XML配置文件中添加numatune字段，创建并启动虚拟机。例如使用主机上的NUMA node 0给虚拟机分配内存，配置参数如下：

    ```
      <numatune>
        <memory mode="strict" nodeset="0"/>
      </numatune>
    ```

    假设虚拟机的vCPU也绑定在NODE0的物理CPU上，就可以避免由于vCPU访问远端内存带来的性能下降。

    >![](public_sys-resources/icon-note.gif) **说明：**   
    >-   分配给虚拟机的内存不要超过该NUMA节点剩余的可用内存，否则可能导致虚拟机启动失败。  
    >-   建议虚拟机内存和vCPU都绑定在同一NUMA节点，避免vCPU访问远端内存造成性能下降。例如将上例中vCPU也绑定在NUMA node 0上。  


### 配置Guest-NUMA

虚拟机中运行的很多业务软件都针对NUMA架构进行了性能优化，尤其是对于大规格虚拟机，这种优化的作用更明显。openEuler提供了Guest NUMA特性，在虚拟机内部呈现出NUMA拓扑结构。用户可以通过识别这个结构，对业务软件的性能进行优化，从而保证业务更好的运行。

配置Guest NUMA时可以指定vNode的内存在HOST上的分配位置，实现内存的分块绑定，同时配合vCPU绑定，使vNode上的vCPU和内存在同一个物理NUMA node上。

#### 操作步骤

在虚拟机的XML配置文件中，配置了Guest NUMA后，就可以在虚拟机内部查看NUMA拓扑结构。<numa\>项是Guest NUMA的必配项。

```
  <cputune>
    <vcpupin vcpu='0' cpuset='0-3'/>
    <vcpupin vcpu='1' cpuset='0-3'/>
    <vcpupin vcpu='2' cpuset='16-19'/>
    <vcpupin vcpu='3' cpuset='16-19'/>
  </cputune>
  <numatune>
    <memnode cellid="0" mode="strict" nodeset="0"/>
    <memnode cellid="1" mode="strict" nodeset="1"/>
  </numatune>
  [...]
  <cpu>
    <numa>
      <cell id='0' cpus='0-1' memory='2097152'/>
      <cell id='1' cpus='2-3' memory='2097152'/>
    </numa>
  </cpu>
```

>![](public_sys-resources/icon-note.gif) **说明：**   
>-   <numa\>项提供虚拟机内部呈现NUMA拓扑功能，“cell id”表示vNode编号，“cpus”表示vCPU编号，“memory”表示对应vNode上的内存大小。  
>-   如果希望通过Guest NUMA提供更好的性能，则需要配置<numatune\>和<cputune\>，使vCPU和对应的内存分布在同一个物理NUMA NODE上：  
>    -   <numatune\>中的“cellid”和<numa\>中的“cell id”是对应的；“mode”可以配置为“strict”（严格从指定node上申请内存，内存不够则失败）、“preferred”（优先从某一node上申请内存，如果不够则从其他node上申请）、“interleave”（从指定的node上交叉申请内存）；“nodeset”表示指定物理NUMA NODE。  
>    -   <cputune\>中需要将同一cell id中的vCPU绑定到与memnode相同的物理NUMA NODE上。  

