Openstack+KVM实践企业私有云中win7虚拟机只能看到2个CPU的解决方案

来源:互联网 发布:数组和矩阵的区别 编辑:程序博客网 时间:2024/05/29 18:36
现象
有时候会发现一个很奇怪的现象,无论配置几个CPU,但是在win7的系统里面,只能看到2个CPU:
配置了4CPU,在处理器里看也是4个,但是只能使用2个:
 
原因
1、Windows 7最多只支持两个CPU socket,每个socket内可以有多个core。
2、kvm缺省每个CPU模拟一个socket,必须修改虚拟机CPU的topology,才能使用超过一个CPU。
3、关于windows64位机具体原因请参考微软官方详情:http://windows.microsoft.com/zh-cn/windows7/taking-the-mystery-out-of-64-bit-windows

解决办法
修改为一个socket多个core。
xml配置文件为:
文件位置(默认缺省路径是/etc/libvirt/qemu/您的虚拟机名字.xml)
<topology sockets='1' cores='4' threads='1'/>
问题解决!

附录:KVM基于内核的虚拟机概念理解与客户机浅析

作为一个KVM的学习者,如果你想要自己完善一个KVM样品级的解决方案,仅仅学会图形化界面使用和简单的配置(详情见上一篇文章)是远远不够的。在上文中感谢@laowolf提出的问题,让我有动力完成接下来的深入的“科普”。可能在本文编写的时候,笔者还没有精力对@laowolf提到的几个难点问题来探究,但是仍然需要纂写文本旨在知识的传播与经验记录,那么同时,也想试着抛出一些热点问题旨在抛砖引玉。

严格来说KVM是属于云计算-虚拟化的范畴。但是我们今天不来讨论所谓云计算的问题,我们着重来介绍KVM的比较深入的知识。 面向读者:KVM虚拟化爱好者,初级运维人员,计算机网络爱好者,KVM用户。 

1.KVM的基于内核的概念理解

在谈及内核的时候,大多数学习者、爱好者都会觉得这是一个晦涩难懂的概念,那么我今天就以我的理解简单向大家介绍一下KVM基于内核的含义(如有不当大家尽可在评论区指出!):

要理解基于内核的含义,显然我们需要一些背景知识作为支撑。

1.1 背景知识:

操作系统内核设计的两大阵营:微内核与单内核。单内核是较为简单的设计,指整个系统的内核功能(具体内核的功能大家可以参考《Linux/Unix系统编程手册》,这里不是本文重点,笔者就不在赘述了)集合在一个大的内核空间来实现,在这样的内核空间中,内核之间通信可以简单的通过调用函数来实现。但是这样做有一个比较大的缺点:一旦修改内核文件就要意味着重新编译源代码;微内核则相反,内核功能被分割为好几个独立的过程。每个过程叫做一个服务器。一般来讲服务器运行在自己的独立的地址空间,通信通过进程间的通信机制来完成。(有点类似网站的服务器分布式管理)那么进程通信就意味着空间的切换,开销相对比较大。

Linux的内核设计不妨说就是采用了单内核+微内核的设计。一方面,Linux内核被设计为单内核,尽管如此在另一方面,Linux内核同时借鉴了微内核的精华:采用了模块化设计以及动态装载内核模块的模式。除了核心的内核功能(如进程切换,内存管理)以外,大部分内和功能设计为模块化,这些内核模块以单独的binary文件形式存在,内核运行过程中动态的加载并且链接进入内核空间。不使用的模块还可以卸载。这样的设计保证了内核性能,也改进了内核的灵活性。 

如果大家理解了上文内容,我们要了解的KVM就是内核模块之一。需要时可以组装进内核,不需要时也可以卸载。因此KVM作为内核模块的虚拟机,其性能,速度等大家都可想而知了,相对于其他的同类型虚拟机要高一些。

1.2 关于虚拟机的类型:

类型一:通俗地来讲是没有通常意义上的“宿主机”的虚拟机,起再电脑刚刚启动的时候就加载了虚拟化模块,这样也就意味着只有一个必要的内核来虚拟化虚拟机部署,这样的虚拟化技术典型的就是Xen。

类型二:有宿主机的虚拟化技术:KVM,还有著名的VMware workstation,virtual Box。在宿主机启动以后加载虚拟化模块。举个例子,要使用KVM,就必须先把宿主机启动了,还要保证kvm内核模块的加载。

显然KVM输入类型二虚拟机。

1.3 关于更多QEMU与KVM的关系:

简单来说QEMU实际上也是一个早已经存在的虚拟化的解决方案,但是与KVM不同的是,QEMU是一个完全基于软件的虚拟化方案,也就意味着QEMU可以完全靠软件虚拟一个客户机运行的环境,那么我们不禁要问,这样的效率不是非常不可靠的吗?笔者要告诉你的是:没错!QEMU的效率的确不高。那么QEMU是怎样和KVM扯上关系的呢?事实上我们可以打个比方:珊瑚虫和小丑鱼。小丑鱼单独生活存活几率不高,珊瑚虫需要小丑鱼来帮助起保持生态圈稳态。那么KVM就像是珊瑚虫,QEMU像是小丑鱼。QEMU可以依赖KVM提供的内核接口来极大提高自己的效率。

 

那么同样的,理论上只要是基于KVM提供的内核接口的软件虚拟化技术都可以完成虚拟化。但是实际上,QEMU-KVM的互利共生关系还是非常牢固且高效的。

1.4 在这个系列文章中反复要出现的重要概念:

Hypervisor:运行在真实物理系统之上,管理硬件平台,并且为每一个虚拟客户机提供相应的虚拟硬件平台。

Intel虚拟化技术:一系列硬件技术的集合,虚拟机监控机软件通过选择利用各项技术从而提高虚拟化软件的性能以及实现各种功能,在本文讨论的技术都是基于x86架构的,需要intel虚拟化技术的支持,对此我们需要做的只是从bios开启虚拟化模块(baidu:bios开启虚拟化即可解决)。

 

那么作为一名虚拟化技术爱好者,在略微理解了KVM的概念的基础上,显然我们需要更深入的去实践KVM服务器的搭建与管理。

2.Guest与Host的分析

在我开始之前,我们仍需要补充一些说明:

?
1
2
3
1.本文仅适用于centos与rhel系统。
2.硬件平台intel VT-x即可。
3.KVM版本3.5以上,QEMU是qemu-kvm 1.1版本以上。

关于搭建的话我实在上一篇文章中有写到过,图形化搭建,并成功访问。参见笔者上一篇文章《初学者也能学会的云桌面虚拟化》。

显然作为一名中度使用者来说。我们是需要了解如果要正常管理一台KVM Host我们需要注意的元素:

2.1 Host的信息获取

首先我们当然要明确Host的概念,Host就是宿主机,在本文里就是搭载KVM核心的的CentOS,Guest就是客户机,在本文中指的是XP_FOR_TEST这台winXP的测试用的机器。

这里我准备了一个完整的记录KVM Host的capability XML。为了使读者更容易读取有用的信息,我将在XML之间穿插介绍,希望能帮助到需要了解KVM的Capabilities信息。

这里为了系列文章的连续性,我使用了在我的上一篇文章中的XP虚拟机来罗列其XML,宁外作为下一篇文章的剧透,将使用Libvirt API来列出所需要的元素。

Libvirt是一套用来管理虚拟化的方案,包含virsh(命令行)和libvirt API两套接口

下面我贴出使用API来获取信息的代码:

#include "stdlib.h"
#include “stdio.h”
ibvirt.h"      //libvirt库 int main(int arg
#include "libvirt/lc,char *argv[]){         virConnectPtr conn ;
Open(NULL); // 建立连接,
         char *caps;          conn = virConnect参数为NULL表示建立本地连接         if( conn == NULL )         {
to qemu : /// system \n ;");                   return 1;         }          caps
                   fprintf(stderr,"Failed to connection  = virConnectGetCapabilities(conn); //获取本机host的capabilities         fprintf(stdout,"Capabilities is : \n%s \n",caps);         free(caps);
          virConnectClose(conn); //关闭与节点连接         return 0;
}

以上是一个简单的调用libvirtAPI的一个c语言文件(此外libvirt支持各种语言的绑定),我们将在以后的文章中详细讲解libvirt的使用。

对于上面的.c文件,我们需要使用如下命令来编译

?
1
gcc getCapability.c –o getCapability –lvirt

执行

?
1
./getCapability

执行得到如下输出:(如下输出描述了kvm host的Capabilities(姑且我们称之为特性))

?
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
<capabilities>
  
  <!—host标签指的是宿主机(CentOS)的各种资料-->
  <host>
    <uuid>564dbe4b-a9ec-c603-bede-f184528e387a</uuid>
<cpu>
  <!—架构-->
      <arch>x86_64</arch>
      <model>SandyBridge</model>
      <vendor>Intel</vendor>
      <topology sockets='2'cores='3'threads='1'/>
      <!—以下是特性标签-->
      <feature name='invtsc'/>
      <feature name='invpcid'/>
      <feature name='erms'/>
      <feature name='bmi2'/>
      <feature name='smep'/>
      <feature name='avx2'/>
      <feature name='bmi1'/>
      <feature name='fsgsbase'/>
      <feature name='abm'/>
      <feature name='pdpe1gb'/>
      <feature name='hypervisor'/>
      <feature name='rdrand'/>
      <feature name='f16c'/>
      <feature name='osxsave'/>
      <feature name='movbe'/>
      <feature name='pcid'/>
      <feature name='fma'/>
      <feature name='vmx'/>(这是支持虚拟化的重要标签)
      <feature name='ht'/>
      <feature name='ss'/>
      <feature name='ds'/>
      <feature name='vme'/>
    </cpu>
    <power_management>
      <suspend_disk/>
    </power_management>
    <migration_features>
      <live/>
      <uri_transports>
        <uri_transport>tcp</uri_transport>
      </uri_transports>
    </migration_features>
    <topology>
      <cells num='1'>
        <cellid='0'>
          <cpus num='6'>
            <cpuid='0'socket_id='0'core_id='0'siblings='0'/>
            <cpuid='1'socket_id='0'core_id='1'siblings='1'/>
            <cpuid='2'socket_id='0'core_id='2'siblings='2'/>
            <cpuid='3'socket_id='1'core_id='0'siblings='3'/>
            <cpuid='4'socket_id='1'core_id='1'siblings='4'/>
            <cpuid='5'socket_id='1'core_id='2'siblings='5'/>
          </cpus>
        </cell>
      </cells>
    </topology>
    <secmodel>
      <model>selinux</model>
      <doi>0</doi>
    </secmodel>
    <secmodel>
      <model>dac</model>
      <doi>0</doi>
    </secmodel>
  </host>
  
  <guest>
    <!—操作系统类型,这里的guest是指可以支持32位的系统被安装-->
    <os_type>hvm</os_type>
    <arch name='i686'>
      <wordsize>32</wordsize>
      <emulator>/usr/libexec/qemu-kvm</emulator>
      <machine>rhel6.6.0</machine>
      <machine canonical='rhel6.6.0'>pc</machine>
      <machine>rhel6.5.0</machine>
      <machine>rhel6.4.0</machine>
      <machine>rhel6.3.0</machine>
      <machine>rhel6.2.0</machine>
      <machine>rhel6.1.0</machine>
      <machine>rhel6.0.0</machine>
      <machine>rhel5.5.0</machine>
      <machine>rhel5.4.4</machine>
      <machine>rhel5.4.0</machine>
      <!—domain指的是Guest ,从以下的两条标签我们看到了QEMU-KVM架构-->
      <domaintype='qemu'>
      </domain>
      <domaintype='kvm'>
        <emulator>/usr/libexec/qemu-kvm</emulator>
      </domain>
    </arch>
    <features>
      <cpuselection/>
      <deviceboot/>
      <acpi default='on'toggle='yes'/>
      <apic default='on'toggle='no'/>
      <pae/>
      <nonpae/>
    </features>
  </guest>
  
  <guest>
    <!—同样的这里指的是有能力安装64位的guest-->
    <os_type>hvm</os_type>
    <arch name='x86_64'>
      <wordsize>64</wordsize>
      <emulator>/usr/libexec/qemu-kvm</emulator>
      <machine>rhel6.6.0</machine>
      <machine canonical='rhel6.6.0'>pc</machine>
      <machine>rhel6.5.0</machine>
      <machine>rhel6.4.0</machine>
      <machine>rhel6.3.0</machine>
      <machine>rhel6.2.0</machine>
      <machine>rhel6.1.0</machine>
      <machine>rhel6.0.0</machine>
      <machine>rhel5.5.0</machine>
      <machine>rhel5.4.4</machine>
      <machine>rhel5.4.0</machine>
      <!—域采用的是QEMU-KVM架构-->
      <domaintype='qemu'>
      </domain>
      <domaintype='kvm'>
        <emulator>/usr/libexec/qemu-kvm</emulator>
      </domain>
    </arch>
    <features>
      <cpuselection/>
      <deviceboot/>
      <acpi default='on'toggle='yes'/>
      <apic default='on'toggle='no'/>
    </features>
  </guest>
  
</capabilities>

这里有必要着重再提醒一下的是Host必须开启VMX(虚拟化功能模块),CPU必须(如果是intel)必须支持vt-d或者vt-x虚拟化技术。这是KVM的硬件支持。(如果有VMware使用经验的人,肯定知道在64位虚拟化的时候是需要开启Host本身的CPU虚拟化支持的,在Bios里面手动操作,这里具体的步骤就不提了。百度与google说得还是相对详细的)。

2.2 那么我们建立起Host的概念以后,显然创造经济效益的(或者说真正为人们服务的就是Guest机):

关于如何简历Guest机我在上一篇文章说得也是比较详细了(图形化界面建立Guest),其实作为一个KVM普通用户来讲的话,学会图形化界面已经足够,作为一个学习者来说的,我们只有懂得Guest的完整的创建过程,才能懂得图形化界面真正的方便之处。

在此,现在主流的创建guest机的方式是:图形化管理工具,virsh命令行,libvirtAPI,kvm-qemu命令行。关于配置这一块我们暂时不提。本文是着重在科普原理以及架构,以方便大家更好地理解并使用KVM技术,所以我们直接开始介绍一台Guest的元素要素,这里笔者想了很多办法想更加直观地来介绍Guest,最终选定的方案是通过介绍libvirt Domain 的XML配置文件来介绍客户机的配置,存储,硬盘等。

路径:/etc/libvirt/qemu/XP_FOR_TEST.xml (XP_FOR_TEST要看你自己给Guest取的名字喔)
 

?
1
2
3
4
5
6
<!--
WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
OVERWRITTEN AND LOST. Changes to thisxml configuration should be made using:
  virsh edit XP_FOR_TEST
or other application using the libvirt API.
-->
 

以上一段主要是讲不要修改这个xml配置文件,因为这是由系统维护的。由系统自动生成的。当然如果自己对KVM足够熟悉的大可不必理会。这里还给出了两个可以改动此xml的方法:virsh命令行和libvirt API。

 

?
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
<domain type='kvm'>
  <name>XP_FOR_TEST</name>
  <uuid>5119e3ad-efa7-e426-49eb-9ddf9060fde4</uuid> 独一无二的uuid
  <memory unit='KiB'>1048576</memory> 内存最大值
  <currentMemory unit='KiB'>1048576</currentMemory> 最近内存使用
  <vcpu placement='static'>2</vcpu>  虚拟CPU数据
  <os>   这里指的是客户机系统类型以及启动顺序
    <type arch='x86_64'machine='rhel6.6.0'>hvm</type>
    <boot dev='hd'/>   第一顺序是硬盘harddisk
  </os>
  <features>
    <acpi/>
    <apic/>
    <pae/>
  </features>
  <clock offset='localtime'> 时钟设置
    <timer name='rtc'tickpolicy='catchup'/>
  </clock>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>restart</on_crash>
  
  
  <devices>
    <emulator>/usr/libexec/qemu-kvm</emulator> 不妨把这个理解为底层的平台
    <disk type='file'device='disk'>    硬盘资料
      <driver name='qemu'type='raw'cache='none'/>
      <source file='/var/lib/libvirt/images/XP_FOR_TEST.img'/> 硬盘位置 才用.img镜像
      <target dev='hda'bus='ide'/>
      <address type='drive'controller='0'bus='0'target='0'unit='0'/>
    </disk>
    <disk type='file'device='cdrom'>  通俗讲这里存的是安装时候的系统镜像文件iso
      <driver name='qemu'type='raw'/>
      <source file='/root/Desktop/xp.iso'/>   路径。
      <target dev='hdc'bus='ide'/>
      <readonly/>
      <address type='drive'controller='0'bus='1'target='0'unit='0'/>
</disk>
  
  
  
    <controller type='usb'index='0'model='ich9-ehci1'>
      <address type='pci'domain='0x0000'bus='0x00'slot='0x05'function='0x7'/>
    </controller>
    <controller type='usb'index='0'model='ich9-uhci1'>
      <master startport='0'/>
      <address type='pci'domain='0x0000'bus='0x00'slot='0x05'function='0x0'multifunction='on'/>
    </controller>
    <controller type='usb'index='0'model='ich9-uhci2'>
      <master startport='2'/>
      <address type='pci'domain='0x0000'bus='0x00'slot='0x05'function='0x1'/>
    </controller>
    <controller type='usb'index='0'model='ich9-uhci3'>
      <master startport='4'/>
      <address type='pci'domain='0x0000'bus='0x00'slot='0x05'function='0x2'/>
    </controller>
    <controller type='ide'index='0'>
      <address type='pci'domain='0x0000'bus='0x00'slot='0x01'function='0x1'/>
    </controller>
    <controller type='virtio-serial'index='0'>
      <address type='pci'domain='0x0000'bus='0x00'slot='0x06'function='0x0'/>
    </controller>

以上是USB的一些信息。有pci控制接口, ide控制,virtio虚拟io接口。可能大家还不是太了解这些概念,大可不必紧张。如果有机会我还是会出文章来依次解释这些问题。

?
1
2
3
4
5
<interfacetype='network'>
      <mac address='52:54:00:73:65:64'/>
      <source network='default'/>
      <address type='pci'domain='0x0000'bus='0x00'slot='0x03'function='0x0'/>
</interface>

网卡接口,列出了mac地址,联网方式。

?
1
2
3
4
5
6
    <serial type='pty'>
      <target port='0'/>
</serial>
    <console type='pty'>
      <target type='serial'port='0'/>
</console>

串口和控制台配置。 

?
1
2
3
4
    <channel type='spicevmc'>
      <target type='virtio'name='com.redhat.spice.0'/>
      <address type='virtio-serial'controller='0'bus='0'port='1'/>
</channel>

这里是通信通道的设置channel是频道的概念,在这里,可以采用spice,可以才用vnc,当然我这里用的是spice,大家如果熟悉的话是可以直接写。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    <input type='tablet'bus='usb'/>
    <input type='mouse'bus='ps2'/>  鼠标配置
    <graphics type='spice'autoport='yes'listen='0.0.0.0'passwd='123456'>  图形化spice
      <listen type='address'address='0.0.0.0'/>
    </graphics>  监听0.0.0.0表示监听所有,  passwd表密码
    <sound model='ich6'>   声音接口
      <address type='pci'domain='0x0000'bus='0x00'slot='0x04'function='0x0'/>
    </sound>
    <video> 图像显示接口
      <model type='qxl'ram='65536'vram='65536'heads='1'/>
      <address type='pci'domain='0x0000'bus='0x00'slot='0x02'function='0x0'/>
    </video>
    <hostdev mode='subsystem'type='usb'managed='yes'>
      <source>
        <vendor id='0x0951'/>
        <product id='0x1665'/>
      </source>
    </hostdev>
    <memballoon model='virtio'>  虚拟化io模块
      <address type='pci'domain='0x0000'bus='0x00'slot='0x07'function='0x0'/>
    </memballoon>
  </devices>
</domain>

这样我把上面重要的部分和需要大家了解的Guest配置信息(模块都标注出来了),查看xml只是一种方法,

同样的我们还可以用别的方法来查看此类信息。

我再在这里提供一个方法,直接通过命令行来查看此类信息。

?
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
[root@localhost qemu]# ps -ef | grep qemu | grep XP
qemu      79598      1 99 12:20 ?        07:58:27
/usr/libexec/qemu-kvm -name XP_FOR_TEST -S -M rhel6.6.0 -enable-kvm \
-m 1024 \
-realtime mlock=off \
-smp 2,sockets=2,cores=1,threads=1 \
-uuid 5119e3ad-efa7-e426-49eb-9ddf9060fde4 \
-nodefconfig \
-nodefaults\  
-chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/XP_FOR_TEST.monitor,server,nowait  \
-mon chardev=charmonitor,id=monitor,mode=control \
-rtc base=localtime,driftfix=slew \
-no-shutdown –device ich9-usb-ehci1,id=usb,bus=pci.0,addr=0x5.0x7 \
-device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,addr=0x5 \ -device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,addr=0x5.0x1 \
-device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pci.0,addr=0x5.0x2 \
-device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x6 \
-drive file=/var/lib/libvirt/images/XP_FOR_TEST.img,if=none,id=drive-ide0-0-0,format=raw,cache=none \
-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 \
-drive file=/root/Desktop/xp.iso,if=none,media=cdrom,id=drive-ide0-1-0,readonly=on,format=raw \
-device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0 \
-netdev tap,fd=23,id=hostnet0 \
-device rtl8139,netdev=hostnet0,id=net0,mac=52:54:00:73:65:64,bus=pci.0,addr=0x3 \
-chardev pty,id=charserial0 \
-device isa-serial,chardev=charserial0,id=serial0 \
-chardev spicevmc,id=charchannel0,name=vdagent \
-device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=com.redhat.spice.0 \
-device usb-tablet,id=input0 \
-spice port=5900,addr=0.0.0.0,seamless-migration=on \
-vga qxl -global qxl-vga.ram_size=67108864 \
-global qxl-vga.vram_size=67108864 \
-device intel-hda,id=sound0,bus=pci.0,addr=0x4 \
-device hda-duplex,id=sound0-codec0,bus=sound0.0,cad=0 \
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x7 \
-msg timestamp=on

没错,这一坨基本就是所有的配置信息了。大家如果要看的话,只能耐心一点我先替大家整理成分行命令的形式了,如果看原生的命令行的话,是一坨,着实难受。

在实际的使用中,可以通过virsh命令行,甚至通过图形化工具来完成热拔插问题。那么本文讲到这里,题目所讲的知识就完成了。如果发现笔者文章出现了问题,请在评论区中指出,我会努力更正。如果对笔者的文笔风格有一些建议的话,也欢迎指出。

随着谈及问题的深入和介绍的全面化,可能本文读起来会略显枯燥。旨在帮助那些希望了解和深度使用KVM的爱好者,甚至开发者。


参考文献:http://www.2cto.com/Article/201510/447974.html
0 0
原创粉丝点击