# 九：如何在线添加/移除虚拟机的vCPU

KVM支持vCPU热插拔么？Linux KVM虚拟机能够感知到新添加的vCPU么？答案当然是"YES"。

类似[KVM 内存管理](https://github.com/huataihuang/cloud-atlas-draft/tree/6f3204fffc11cf006abd394631e2598d98b415c3/virtual/kvm/startup/how_to_add_remove_memory_to_guest_on_fly/README.md)，你可以使用`virsh`命令给正在运行的VM添加或删除vCPU。不过，这个工作是需要预先配置KVM虚拟机的最大vCPU参数才能使用。所以当部署一个新的虚拟机，你应该首先考虑这个参数。给KVM虚拟机设置最大vCPU数量并不会对资源有所小号，因为虚拟机只会使用分配的vCPU。

## 理解VM的vCPU配置

* 列出KVM主机配置的VM

```
[root@UA-HA ~]# virsh list  --all
 Id    Name                           State
----------------------------------------------------
  -     UAKVM2                         shut off

[root@UA-HA ~]#
```

* 检查当前VM配置

```
[root@UA-HA ~]# virsh dumpxml UAKVM2 | grep vcpu
  <vcpu placement='static' current='1'>2</vcpu>
```

以上显示这个VM当前使用1个vCPU，并且可以通过`virsh vsetcpus`命令增加vCPU。但死你不能在VM运行时增加超过2个vCPU。

* 现在我们启动VM

```
[root@UA-HA ~]# virsh start UAKVM2
Domain UAKVM2 started

[root@UA-HA ~]#
```

* 登陆到KVM虚拟机并检查分配的vCPU数量：

```
[root@UA-KVM1 ~]# lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                1
On-line CPU(s) list:   0
Thread(s) per core:    1
Core(s) per socket:    1
Socket(s):             1
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 44
Model name:            Westmere E56xx/L56xx/X56xx (Nehalem-C)
Stepping:              1
CPU MHz:               2594.058
BogoMIPS:              5188.11
Hypervisor vendor:     KVM
Virtualization type:   full
L1d cache:             32K
L1i cache:             32K
L2 cache:              4096K
NUMA node0 CPU(s):     0
[root@UA-KVM1 ~]#
```

## 向运行的KVM虚拟机增加vCPU

* 切换到KVM主机并使用`virsh`命令增加vCPU，从1增加到2

```
[root@UA-HA ~]# virsh setvcpus UAKVM2 2

[root@UA-HA ~]# virsh dominfo UAKVM2
Id:             38
Name:           UAKVM2
UUID:           6013be3b-08f9-4827-83fb-390bd5a86de6
OS Type:        hvm
State:          running
CPU(s):         2
CPU time:       51.5s
Max memory:     1048576 KiB
Used memory:    1048576 KiB
Persistent:     yes
Autostart:      disable
Managed save:   no
Security model: selinux
Security DOI:   0
Security label: system_u:system_r:svirt_t:s0:c709,c868 (permissive)
[root@UA-HA ~]#
```

* 返回到KVM guest虚拟机，检查新添加的vCPU。此时VM从`UP code(uniprocessor)`切换到`SMP code (symmetric multiprocessor`)

```
[root@UA-KVM1 ~]# tail -f /var/log/messages
Dec 16 12:48:28 UA-KVM1 kernel: CPU1 has been hot-added
Dec 16 12:48:28 UA-KVM1 kernel: SMP alternatives: switching to SMP code
Dec 16 12:48:57 UA-KVM1 kernel: smpboot: Booting Node 0 Processor 1 APIC 0x1
Dec 16 12:48:57 UA-KVM1 kernel: kvm-clock: cpu 1, msr 0:3ff87041, secondary cpu clock
Dec 16 12:48:57 UA-KVM1 kernel: TSC synchronization [CPU#0 -> CPU#1]:
Dec 16 12:48:57 UA-KVM1 kernel: Measured 906183720569 cycles TSC warp between CPUs, turning off TSC clock.
Dec 16 12:48:57 UA-KVM1 kernel: tsc: Marking TSC unstable due to check_tsc_sync_source failed
Dec 16 12:48:57 UA-KVM1 kernel: KVM setup async PF for cpu 1
Dec 16 12:48:57 UA-KVM1 kernel: kvm-stealtime: cpu 1, msr 3fd0d240
Dec 16 12:48:57 UA-KVM1 kernel: microcode: CPU1 sig=0x206c1, pf=0x1, revision=0x1
Dec 16 12:48:57 UA-KVM1 kernel: Will online and init hotplugged CPU: 1
[root@UA-KVM1 ~]# lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                2
On-line CPU(s) list:   0,1
Thread(s) per core:    1
Core(s) per socket:    1
Socket(s):             2
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 44
Model name:            Westmere E56xx/L56xx/X56xx (Nehalem-C)
Stepping:              1
CPU MHz:               2594.058
BogoMIPS:              5188.11
Hypervisor vendor:     KVM
Virtualization type:   full
L1d cache:             32K
L1i cache:             32K
L2 cache:              4096K
NUMA node0 CPU(s):     0,1
[root@UA-KVM1 ~]#
```

* 如果想配置永久生效，保存VM配置

```
[root@UA-HA ~]# virsh setvcpus UAKVM2 2 --config

[root@UA-HA ~]#
```

现在我们已经成功给KVM虚拟机添加了vCPU并使配置永久生效。

## 从运行的KVM虚拟机去除vCPU

没有直接从KVM guest虚拟机直接移除vCPU的方法。但是可以通过禁止CPU核心方式将CPU核心的性能返还给KVM主机。

* 登陆到KVM host主机
* 假设当前KVM guest虚拟机UAKVM2有2个活动的vCPU
* 注意不要使用以下命令来移除vCPU，你会收到错误消息`error: internal error: cannot change vcpu count of this domain`

```
[root@UA-HA ~]# virsh setvcpus UAKVM2 1
error: internal error: cannot change vcpu count of this domain

[root@UA-HA ~]#
```

* 使用以下命令来缩减UAKVM2的vCPU数量（vCPU从2缩减到1）

```
[root@UA-HA ~]# virsh setvcpus --live --guest UAKVM2 1
[root@UA-HA ~]#
```

* 保存VM配置

```
[root@UA-HA ~]# virsh setvcpus --config UAKVM2 1

[root@UA-HA ~]#
```

* 登陆到KVM guest虚拟机`UAKVM2`验证

```
[root@UA-KVM1 ~]# tail -f /var/log/messages
Dec 16 13:01:01 UA-KVM1 systemd: Starting Session 2 of user root.
Dec 16 13:19:08 UA-KVM1 kernel: Unregister pv shared memory for cpu 1
Dec 16 13:19:08 UA-KVM1 kernel: smpboot: CPU 1 is now offline
[root@UA-KVM1 ~]# lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                2
On-line CPU(s) list:   0
Off-line CPU(s) list:  1
Thread(s) per core:    1
Core(s) per socket:    1
Socket(s):             1
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 44
Model name:            Westmere E56xx/L56xx/X56xx (Nehalem-C)
Stepping:              1
CPU MHz:               2594.058
BogoMIPS:              5188.11
Hypervisor vendor:     KVM
Virtualization type:   full
L1d cache:             32K
L1i cache:             32K
L2 cache:              4096K
NUMA node0 CPU(s):     0
[root@UA-KVM1 ~]#
```

注意：

在KVM物理主机中过，你依然会看到两个vCPU呗分配给虚拟机`UAKVM2`，只有重启VM才会生效。

```
[root@UA-HA ~]# virsh dominfo UAKVM2
Id:             38
Name:           UAKVM2
UUID:           6013be3b-08f9-4827-83fb-390bd5a86de6
OS Type:        hvm
State:          running
CPU(s):         2
CPU time:       90.4s
Max memory:     1048576 KiB
Used memory:    1048576 KiB
Persistent:     yes
Autostart:      disable
Managed save:   no
Security model: selinux
Security DOI:   0
Security label: system_u:system_r:svirt_t:s0:c709,c868 (permissive)

[root@UA-HA ~]#
```

* 关闭`UAKVM2` KVM虚拟机并验证

```
[root@UA-HA ~]# virsh destroy UAKVM2
Domain UAKVM2 destroyed

[root@UA-HA ~]# virsh dominfo UAKVM2
Id:             -
Name:           UAKVM2
UUID:           6013be3b-08f9-4827-83fb-390bd5a86de6
OS Type:        hvm
State:          shut off
CPU(s):         1
Max memory:     1048576 KiB
Used memory:    0 KiB
Persistent:     yes
Autostart:      disable
Managed save:   no
Security model: selinux
Security DOI:   0

[root@UA-HA ~]#
```

此时可以看到`vCPU`被修改成1个。

如果尝试添加比预分配更多的vCPU会看到如下错误信息`error: invalid argument: requested vcpus is greater than max allowable vcpus for the domain`

```
[root@UA-HA ~]# virsh setvcpus UAKVM2 3
error: invalid argument: requested vcpus is greater than max allowable vcpus for the domain: 3 > 2
[root@UA-HA ~]#
```

请重新参考前述的"理解VM vCPU配置"段落。使用`virsh`命令不能超过vCPU最大配置数量。这个最大vCPU数量不能在虚拟机运行时修改。

## 如何修改每个虚拟机的最大vCPU数量？（只能使用offline模式）

* 作为root用户登陆到KVM host主机
* 优雅地停止虚拟机

```
[root@UA-HA ~]# virsh list
 Id    Name                           State
----------------------------------------------------
 39    UAKVM2                         running

[root@UA-HA ~]# virsh shutdown UAKVM2
Domain UAKVM2 is being shutdown

[root@UA-HA ~]#
```

* 编辑VM配置类似如下，这里将最大vCPU数量从2修改成4:

```
<vcpu placement='static' currtne='1'>2</vcpu>
```

修改成

```
<vcpu placement='static' currtne='1'>4</vcpu>
```

vCPU XML 格式：

```
<vcpu placement='static' current='N'>M</vcpu>
```

这里N时当前激活的CPU数量，而M是CPU的最大数量

* 启动KVM虚拟机`UAKVM2`

```
[root@UA-HA ~]# virsh start UAKVM2
Domain UAKVM2 started

[root@UA-HA ~]#
```

* 验证UAKVM2虚拟机的vCPU信息

```
[root@UA-HA ~]# virsh vcpuinfo UAKVM2
VCPU:           0
CPU:            1
State:          running
CPU time:       24.0s
CPU Affinity:   yy

[root@UA-HA ~]#
```

如上所述，此时UAKVM2只分配了1个vCPU。由于我们配置了vCPU最大数量是4，所以我们可以动态将虚拟机的vCPU增加到4个。

* 增加vCPU数量到4

```
[root@UA-HA ~]# virsh setvcpus UAKVM2 4

[root@UA-HA ~]# virsh vcpuinfo UAKVM2
VCPU:           0
CPU:            0
State:          running
CPU time:       27.6s
CPU Affinity:   yy

VCPU:           1
CPU:            0
State:          running
CPU time:       0.4s
CPU Affinity:   yy

VCPU:           2
CPU:            0
State:          running
CPU time:       0.1s
CPU Affinity:   yy

VCPU:           3
CPU:            0
State:          running
CPU time:       0.1s
CPU Affinity:   yy

[root@UA-HA ~]#
[root@UA-HA ~]# virsh setvcpus UAKVM2 4 --config

[root@UA-HA ~]#
```

* 登陆到KVM虚拟机`UAKVM2`中并列出vCPU

```
[root@UA-KVM1 ~]# lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                4
On-line CPU(s) list:   0-3
Thread(s) per core:    1
Core(s) per socket:    1
Socket(s):             4
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 44
Model name:            Westmere E56xx/L56xx/X56xx (Nehalem-C)
Stepping:              1
CPU MHz:               2594.058
BogoMIPS:              5188.11
Hypervisor vendor:     KVM
Virtualization type:   full
L1d cache:             32K
L1i cache:             32K
L2 cache:              4096K
NUMA node0 CPU(s):     0-3
[root@UA-KVM1 ~]#
```

以上我们已经在离线情况下成功增加了最大vCPU数量，并在VM运行时增加了分配到vCPU。

## 系列教程编译

本系列教程根据 [UnixArena Linux KVM](http://www.unixarena.com/category/redhat-linux/linux-kvm) 系列教程编译，共分以下文章：

* [一：基于内核的虚拟机（KVM）概览](https://github.com/huataihuang/cloud-atlas-draft/tree/6f3204fffc11cf006abd394631e2598d98b415c3/virtual/kvm/startup/kernel_based_virtual_machine_kvm_overview/README.md)
* [二：Redhat企业Linux安装KVM](https://github.com/huataihuang/cloud-atlas-draft/tree/6f3204fffc11cf006abd394631e2598d98b415c3/virtual/kvm/startup/redhat_enterprise_linux_kvm_installation/README.md)
* [三：RHEL 7.2 配置KVM主机](https://github.com/huataihuang/cloud-atlas-draft/tree/6f3204fffc11cf006abd394631e2598d98b415c3/virtual/kvm/startup/rhel_7_2_configuring_kvm_hosts/README.md)
* [四：使用命令行启动第一个KVM实例](https://github.com/huataihuang/cloud-atlas-draft/tree/6f3204fffc11cf006abd394631e2598d98b415c3/virtual/kvm/startup/launch_the_first_kvm_instance_using_cli/README.md)
* [五：使用Virt-Manger(VMM)部署KVM实例](https://github.com/huataihuang/cloud-atlas-draft/tree/6f3204fffc11cf006abd394631e2598d98b415c3/virtual/kvm/startup/deploy_kvm_instance_using_virt_manger_vmm_gui/README.md)
* [六：如何克隆一个KVM虚拟机并重置该虚拟机](https://github.com/huataihuang/cloud-atlas-draft/tree/6f3204fffc11cf006abd394631e2598d98b415c3/virtual/kvm/startup/how_to_clone_a_kvm_virtual_machines_and_reset_the_vm/README.md)
* [七：如何在线添加/更改虚拟磁盘](https://github.com/huataihuang/cloud-atlas-draft/tree/6f3204fffc11cf006abd394631e2598d98b415c3/virtual/kvm/startup/how_to_add_resize_virtual_disk_on_fly/README.md)
* [八：如何在线添加/移除虚拟机的内存](https://github.com/huataihuang/cloud-atlas-draft/tree/6f3204fffc11cf006abd394631e2598d98b415c3/virtual/kvm/startup/how_to_add_remove_memory_to_guest_on_fly/README.md)
* [九：如何在线添加/移除虚拟机的vCPU](https://github.com/huataihuang/cloud-atlas-draft/tree/6f3204fffc11cf006abd394631e2598d98b415c3/virtual/kvm/startup/how_to_add_remove_vcpu_to_guest_on_fly/README.md)
* [十：更改libvirt虚拟机镜像存储路径](https://github.com/huataihuang/cloud-atlas-draft/tree/6f3204fffc11cf006abd394631e2598d98b415c3/virtual/kvm/startup/change_libvirt_vm_image_store_path/README.md)
* [十一：实现Linux KVM在线迁移](https://github.com/huataihuang/cloud-atlas-draft/tree/6f3204fffc11cf006abd394631e2598d98b415c3/virtual/kvm/startup/perform_live_migration_on_linux_kvm/README.md)
* [十二：RHEL7 Pacemaker - 配置高可用KVM虚拟机](https://github.com/huataihuang/cloud-atlas-draft/tree/6f3204fffc11cf006abd394631e2598d98b415c3/virtual/kvm/startup/rhel_7_pacemaker_configuring_ha_kvm_guest/README.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://huataihuang.gitbook.io/cloud-atlas-draft/virtual/kvm/startup/how_to_add_remove_vcpu_to_guest_on_fly.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
