虚拟化技术发展简史
作者:张子良
版权所有,转载请注明出处
一 概述
虚拟化技术按照其发展历史,可以分为四个阶段:硬件仿真虚拟化、完全虚拟化、半虚拟化和操作系统虚拟化。当前阶段的虚拟化技术以半虚拟化技术为主流,操作系统虚拟化是发展方向,目前主要应用在高端应用领域。下面将从每一种虚拟化技术的原理、优点、缺点和代表产品四个方面进行介绍。
二 硬件仿真
2.1 工作原理
硬件虚拟化分为硬件指令虚拟化和硬件资源虚拟化,硬件指令虚拟化目的是将客户机发出的指令翻译成所在主机平台的指令,从而实现对客户机指令的模拟执行。硬件资源虚拟化目的是虚拟出硬件资源,通常主机平台与客户机平台所用的指令集是一样的,只是为了提高效率,将虚拟资源映射到物理资源,并在虚拟机计算中使用本地硬件。硬件虚拟化工作原理如下图所示:
2.2 优点
硬件仿真虚拟化由于采用了硬件仿真技术,硬件仿真的实现在宿主操作系统上实现,所以安装在仿真硬件上的操作系统,不需要做任何修改即可直接安装。例如我们可以在Windows上运行Symbian或Windows Mobile程序,只要有相应的硬件虚拟机即可。
2.3 缺点
硬件仿真虚拟化是最为复杂的虚拟化技术,需要在宿主操作系统上,创建一个硬件VM来仿真所想要的硬件。由于每条指令都必须在底层硬件上进行仿真,所以硬件仿真虚拟化技术的主要问题就是速度慢。
2.4 代表产品
三 完全虚拟化
3.1 工作原理
完全虚拟化(full virtualization)模型使用一个虚拟机,它在客户操作系统和原始硬件之间进行协调。"协调"在这里是一个关键,因为 VMM 在客户操作系统和裸硬件之间提供协调。特定受保护的指令必须被捕获下来并在 hypervisor 中进行处理,因为这些底层硬件并不由操作系统所拥有,而是由操作系统通过 hypervisor 共享。工作原理如下图所示:
完全虚拟化分为传统完全虚拟化和硬件辅助的虚拟化。传统的完全虚拟化,虚拟机运行在操作系统之上,虚拟机管理程序本身运行在cpu的Ring 0,虚拟的Guest OS则运行在Ring 1(为了避免Guest OS破坏Host OS,Guest OS必须运行 在低于Ring 0的权限)。但是这样一来Guest的兼容性会受到影响,并且原来Guest OS要在Ring 0上执行的指令都必须经过hypervisor翻译才能运行,速度会有所下降。硬件辅助的完全虚拟化需要CPU硬件支持,有INTEL的VT和AMD的 AMD-V两种技术,只有支持这两种技术的CPU才可以使用。硬件辅助的虚拟化把虚拟机管理程序本身放到比Ring 0还低的模式运行(比如Ring -1),而把Guest OS放到Ring 0,这样兼容性得到了提高,不过因为第一代硬件虚拟技术(VT和AMD-V)实现上还不够成熟,所以效率上并不比传统的完全虚拟化更高。
3.2 优点
完全虚拟化的速度要比硬件仿真的速度要快,但是其性能低于裸硬件,因为中间经过了 hypervisor 的协调过程。完全虚拟化的最大优点是操作系统无需任何修改就可以直接运行。此外完全虚拟化还可使实现同时支持多个操作系统。
3.3 缺点
操作系统必须要支持底层硬件(例如 PowerPC)。
3.4 代表产品
传统的完全虚拟化的产品主要有Vmware Workstation / Server, Virtual PC / Server,Parallel Workstation等。硬件辅助的虚拟化受到很多产品的支持,目前传统的完全虚拟化产品也都开始对硬件辅助的虚拟化进行支持,比如Vmware Workstation / Server和VirtualBox都开始支持VT和AMD-V,并且在它们上面想要运行64位的Guest OS还必须使用硬件辅助的虚拟化。
四 半虚拟化
4.1 工作原理
半虚拟化(paravirtualization),可以提供极高的性能,与完全虚拟化有一些类似。这种方法使用了一个 hypervisor 来实现对底层硬件的共享访问,将与虚拟化有关的代码集成到了操作系统本身中。与硬件辅助的完全虚拟化有一点相似是hypervisor运行在Ring -1,而Guest OS运行在Ring 0上。半虚拟化工作原理如下图所示:
4.2 优点
半虚拟化比完全虚拟化效率更高,速度更快,提供了与未经虚拟化的系统相接近的性能。
4.3 缺点
虚拟化有一个缺点是必须修改客户操作系统,因为半虚拟化为了提高效率,必须要让Guest OS本身意识到自己运行在虚拟机上,所以在Guest OS的内核中需要有方法来与hypervisor进行协调,这个缺点很大的影响了半虚拟化技术的普及,因为Linux等系统可以修改,而其它不能修改的系统就不能用了。
4.4 代表产品
半虚拟化的代表产品是Xen【zen】,Vmware ESX Server,Microsoft Hyper-V R1。Xen通过给Linux内核打补丁,使Host OS本身也运行在虚拟机上(叫做Domain 0),其它的虚拟机叫做Domain U(Domain U需要为Xen进行修改)。Hyper-V和Xen比较相似,Hyper-V目前集成在Windows 2008中,没启用Hyper-V时,只是一个普通的Windows 2008,一旦启用了Hyper-V,那么Hyper-V一开始就运行,而Windows 2008则在之上成为第一个虚拟机(叫做Parent partition,与Xen的Domain 0相似),在Hyper-V上运行的其它虚拟机应该也需要修改,不过Windows 2008已经修改过了所以可以在Hyper-V上运行。Vmware ESC Server本身集成在一个以Linux为基础的系统上,其架构和Xen及Hyper-V也是比较相似的。
五 操作系统虚拟化
5.1 工作原理
操作系统级的虚拟化在操作系统本身之上实现服务器的虚拟化,特点是一个单一的节点运行着唯一的操作系统实例。通过在这个系统上加装虚拟化平台,可以将系统划分成多个独立隔离的容器,每个容器是一个虚拟的操作系统,被称为虚拟环境,也成为虚拟专用服务器。操作系统级的虚拟化原理如下图所示:
5.2 优点
操作系统级虚拟化技术直接和物理设备进行交换,极大的提高了系统性能。
5.3 缺点
操作系统级的虚拟化要求对操作系统的内核进行一些修改,但是其优点是可以获得原始性能。
5.4 代表产品
操作系统级虚拟以WMware ESX/ESXI和微软公司的Hyper-v Server 2008 R2服务器操作系统的典型应用,也是目前虚拟化技术领域的领跑者。
以上部分是曾经写过的一个专题的第一章,特此分享,如果喜欢请点一下推荐,发表一下评论,多谢!
模板绑定使用数据render模板,然后把渲染的结果填充到Dom树中。模板通过重复或嵌套块(通常为您的视图模型数据的函数)用一种简单,方便的方式来建立复杂的UI结构 。
有两种方式使用模板:
foreach
, if
, with
,或其它控制流绑定(control flow bindings)组成 。 这些控制流绑定捕捉包含你指定的所有HTML标记,把它作为模板来呈现任意数据项目,此特性由Knockout内置,无需任何扩展库。主要参数
简化语法: 如果你使用一个字符串值, KO 将把它使用一个模板ID来呈现. 它提供的数据模板将是你的当前模型对象.
复杂控制, 通过以下方式的Javascript 对象来绑定:
name
—包含你想呈现的模板ID - 参见 Note 5 .data
— 你想呈现的data对象. 如省略此参数, KO 将查找 foreach
参数, or will fall back on using your current model object.if
— 如有此参数, 则在if表达式为true时渲染模板.例如:先判断观察对象为空,再决定是否绑定模板foreach
— 通过“foreach” 循环进行绑定- 参见 Note 2 .as
— 使用 foreach
时,用于定义别名 - 参见Note 3 .afterRender
, afterAdd
, or beforeRemove
— 渲染元素的回调函数 -参见 Note 4一般说来,如果使用控制流绑定 (foreach
, with
, if
, etc.)时,无需给模板命名: 你的Dom元素中已经隐式的给它命名了. 但你也可以显式的给模板命名,并引用它
<h2>Participants</h2> Here are the participants: <div data-bind="template: { name: 'person-template', data: buyer }"></div> <div data-bind="template: { name: 'person-template', data: seller }"></div> <script type="text/html" id="person-template"> <h3 data-bind="text: name"></h3> <p>Credits: <span data-bind="text: credits"></span></p> </script> <script type="text/javascript"> function MyViewModel() { this.buyer = { name: 'Franklin', credits: 250 }; this.seller = { name: 'Mario', credits: 5800 }; } ko.applyBindings(new MyViewModel()); </script>
上例中,person-template
被使用了两次:buyer
一次,
seller一次
. 注意:模板被包裹在<script type="text/html">标记中
,type
属性是必须的,用于区别正常的javascript代码, 不会被Knockout 当作标记来绑定.
命名模板并不常用,但有的时候能派上用场.
以下方式在命名模板中使用foreach:
<h2>Participants</h2> Here are the participants: <div data-bind="template: { name: 'person-template', foreach: people }"></div> <script type="text/html" id="person-template"> <h3 data-bind="text: name"></h3> <p>Credits: <span data-bind="text: credits"></span></p> </script> function MyViewModel() { this.people = [ { name: 'Franklin', credits: 250 }, { name: 'Mario', credits: 5800 } ] } ko.applyBindings(new MyViewModel());
其实,下面的代码使用foreach是最直接的,无需命名模板:
<div data-bind="foreach: people"> <h3 data-bind="text: name"></h3> <p>Credits: <span data-bind="text: credits"></span></p> </div>
使用as
将有助于更好的使用foreach. 例如:
<ul data-bind="template: { name: 'employeeTemplate', foreach: employees, as: 'employee' }"></ul>
注意: 'employee'
通过 as与foreach中的项相关联了
.现在你可以在foreach
循环中通过employee
来访问foreach项,达到更好控制渲染的目的
此功能主要用于foreach
嵌套, 以下示例展示了上层循环season
如何控制下层循环month的
:
<ul data-bind="template: { name: 'seasonTemplate', foreach: seasons, as: 'season' }"></ul> <script type="text/html" id="seasonTemplate"> <li> <strong data-bind="text: name"></strong> <ul data-bind="template: { name: 'monthTemplate', foreach: months, as: 'month' }"></ul> </li> </script> <script type="text/html" id="monthTemplate"> <li> <span data-bind="text: month"></span> is in <span data-bind="text: season.name"></span> </li> </script> <script> var viewModel = { seasons: ko.observableArray([ { name: 'Spring', months: [ 'March', 'April', 'May' ] }, { name: 'Summer', months: [ 'June', 'July', 'August' ] }, { name: 'Autumn', months: [ 'September', 'October', 'November' ] }, { name: 'Winter', months: [ 'December', 'January', 'February' ] } ]) }; ko.applyBindings(viewModel); </script>
注意: 别忘记给值加上引号 (e.g., as: 'season'
, 别写为 as: season
),
有时需要定制生成模板的逻辑。例如,当你使用 jQuery UI组件时, 可能需要将模板转化为对应的各种控件.
一般说来, 使用 custom binding,来处理以上需求较好,但有可能你也需要访问原始的模板生成dom元素,此时,你可以使用afterRender
.
渲染模板之后.KO将调用afterRender .如果使用了 foreach
, Knockout 将在每个项加到observable数组后回调 afterRender.
例如:
<div data-bind='template: { name: "personTemplate", data: myData, afterRender: myPostProcessingLogic }'> </div> ..... viewModel.myPostProcessingLogic = function(elements) { // "elements" is an array of DOM nodes just rendered by the template // You can add custom post-processing logic here }
如果在foreach
只想处理增加和删除, 可使用afterAdd
、 beforeRemove
来代替,参见文档foreach
binding.
如果有多个模板, 可使用回调函数来决定使用哪一个,当然函数们得有自己的name。如果使用的是foreach
模板, KO在每次foreach项的时候都会执行函数,其参数为整个item对象。.Otherwise, the function will be given the data
option’s value or fall back to providing your whole current model object.
例如:
<ul data-bind='template: { name: displayMode, foreach: employees }'> </ul> <script> var viewModel = { employees: ko.observableArray([ { name: "Kari", active: ko.observable(true) }, { name: "Brynn", active: ko.observable(false) }, { name: "Nora", active: ko.observable(false) } ]), displayMode: function(employee) { // Initially "Kari" uses the "active" template, while the others use "inactive" return employee.active() ? "active" : "inactive"; } }; // ... then later ... viewModel.employees()[1].active(true); // Now "Brynn" is also rendered using the "active" template. </script>
如果在函数中使用 observable 值, 那么它的值更新后对应的绑定也会更新. 这样数据就可以选择合适的模板来呈现。
如果在函数中使用了第二个参数,那它将作为 binding context对象来处理.当动态选择模板时,你可以访问$parent
或其它的 binding context 变量 。例如:
displayMode: function(employee, bindingContext) {
// Now return a template name string based on properties of employee or bindingContext
}