mirror of
https://github.com/zhwei820/learn.lianglianglee.com.git
synced 2025-09-26 21:26:41 +08:00
378 lines
36 KiB
HTML
378 lines
36 KiB
HTML
<!DOCTYPE html>
|
||
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
<head>
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
|
||
<link rel="icon" href="/static/favicon.png">
|
||
<title>34 理解虚拟机:你在云上拿到的计算机是什么样的?.md.html</title>
|
||
<!-- Spectre.css framework -->
|
||
<link rel="stylesheet" href="/static/index.css">
|
||
<!-- theme css & js -->
|
||
<meta name="generator" content="Hexo 4.2.0">
|
||
</head>
|
||
<body>
|
||
<div class="book-container">
|
||
<div class="book-sidebar">
|
||
<div class="book-brand">
|
||
<a href="/">
|
||
<img src="/static/favicon.png">
|
||
<span>技术文章摘抄</span>
|
||
</a>
|
||
</div>
|
||
<div class="book-menu uncollapsible">
|
||
<ul class="uncollapsible">
|
||
<li><a href="/" class="current-tab">首页</a></li>
|
||
</ul>
|
||
<ul class="uncollapsible">
|
||
<li><a href="../">上一级</a></li>
|
||
</ul>
|
||
<ul class="uncollapsible">
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/00 开篇词 为什么你需要学习计算机组成原理?.md.html">00 开篇词 为什么你需要学习计算机组成原理?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/01 冯·诺依曼体系结构:计算机组成的金字塔.md.html">01 冯·诺依曼体系结构:计算机组成的金字塔</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/02 给你一张知识地图,计算机组成原理应该这么学.md.html">02 给你一张知识地图,计算机组成原理应该这么学</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/03 通过你的CPU主频,我们来谈谈“性能”究竟是什么?.md.html">03 通过你的CPU主频,我们来谈谈“性能”究竟是什么?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/04 穿越功耗墙,我们该从哪些方面提升“性能”?.md.html">04 穿越功耗墙,我们该从哪些方面提升“性能”?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/05 计算机指令:让我们试试用纸带编程.md.html">05 计算机指令:让我们试试用纸带编程</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/06 指令跳转:原来if...else就是goto.md.html">06 指令跳转:原来if...else就是goto</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/07 函数调用:为什么会发生stack overflow?.md.html">07 函数调用:为什么会发生stack overflow?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/08 ELF和静态链接:为什么程序无法同时在Linux和Windows下运行?.md.html">08 ELF和静态链接:为什么程序无法同时在Linux和Windows下运行?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/09 程序装载:“640K内存”真的不够用么?.md.html">09 程序装载:“640K内存”真的不够用么?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/10 动态链接:程序内部的“共享单车”.md.html">10 动态链接:程序内部的“共享单车”</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/11 二进制编码:“手持两把锟斤拷,口中疾呼烫烫烫”?.md.html">11 二进制编码:“手持两把锟斤拷,口中疾呼烫烫烫”?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/12 理解电路:从电报机到门电路,我们如何做到“千里传信”?.md.html">12 理解电路:从电报机到门电路,我们如何做到“千里传信”?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/13 加法器:如何像搭乐高一样搭电路(上)?.md.html">13 加法器:如何像搭乐高一样搭电路(上)?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/14 乘法器:如何像搭乐高一样搭电路(下)?.md.html">14 乘法器:如何像搭乐高一样搭电路(下)?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/15 浮点数和定点数(上):怎么用有限的Bit表示尽可能多的信息?.md.html">15 浮点数和定点数(上):怎么用有限的Bit表示尽可能多的信息?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/16 浮点数和定点数(下):深入理解浮点数到底有什么用?.md.html">16 浮点数和定点数(下):深入理解浮点数到底有什么用?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/17 建立数据通路(上):指令加运算=CPU.md.html">17 建立数据通路(上):指令加运算=CPU</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/18 建立数据通路(中):指令加运算=CPU.md.html">18 建立数据通路(中):指令加运算=CPU</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/19 建立数据通路(下):指令加运算=CPU.md.html">19 建立数据通路(下):指令加运算=CPU</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/20 面向流水线的指令设计(上):一心多用的现代CPU.md.html">20 面向流水线的指令设计(上):一心多用的现代CPU</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/21 面向流水线的指令设计(下):奔腾4是怎么失败的?.md.html">21 面向流水线的指令设计(下):奔腾4是怎么失败的?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/22 冒险和预测(一):hazard是“危”也是“机”.md.html">22 冒险和预测(一):hazard是“危”也是“机”</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/23 冒险和预测(二):流水线里的接力赛.md.html">23 冒险和预测(二):流水线里的接力赛</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/24 冒险和预测(三):CPU里的“线程池”.md.html">24 冒险和预测(三):CPU里的“线程池”</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/25 冒险和预测(四):今天下雨了,明天还会下雨么?.md.html">25 冒险和预测(四):今天下雨了,明天还会下雨么?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/26 Superscalar和VLIW:如何让CPU的吞吐率超过1?.md.html">26 Superscalar和VLIW:如何让CPU的吞吐率超过1?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/27 SIMD:如何加速矩阵乘法?.md.html">27 SIMD:如何加速矩阵乘法?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/28 异常和中断:程序出错了怎么办?.md.html">28 异常和中断:程序出错了怎么办?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/29 CISC和RISC:为什么手机芯片都是ARM?.md.html">29 CISC和RISC:为什么手机芯片都是ARM?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/30 GPU(上):为什么玩游戏需要使用GPU?.md.html">30 GPU(上):为什么玩游戏需要使用GPU?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/31 GPU(下):为什么深度学习需要使用GPU?.md.html">31 GPU(下):为什么深度学习需要使用GPU?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/32 FPGA、ASIC和TPU(上):计算机体系结构的黄金时代.md.html">32 FPGA、ASIC和TPU(上):计算机体系结构的黄金时代</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/33 解读TPU:设计和拆解一块ASIC芯片.md.html">33 解读TPU:设计和拆解一块ASIC芯片</a>
|
||
</li>
|
||
<li>
|
||
<a class="current-tab" href="/专栏/深入浅出计算机组成原理/34 理解虚拟机:你在云上拿到的计算机是什么样的?.md.html">34 理解虚拟机:你在云上拿到的计算机是什么样的?</a>
|
||
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/35 存储器层次结构全景:数据存储的大金字塔长什么样?.md.html">35 存储器层次结构全景:数据存储的大金字塔长什么样?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/36 局部性原理:数据库性能跟不上,加个缓存就好了?.md.html">36 局部性原理:数据库性能跟不上,加个缓存就好了?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/37 理解CPU Cache(上):“4毫秒”究竟值多少钱?.md.html">37 理解CPU Cache(上):“4毫秒”究竟值多少钱?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/38 高速缓存(下):你确定你的数据更新了么?.md.html">38 高速缓存(下):你确定你的数据更新了么?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/39 MESI协议:如何让多核CPU的高速缓存保持一致?.md.html">39 MESI协议:如何让多核CPU的高速缓存保持一致?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/40 理解内存(上):虚拟内存和内存保护是什么?.md.html">40 理解内存(上):虚拟内存和内存保护是什么?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/41 理解内存(下):解析TLB和内存保护.md.html">41 理解内存(下):解析TLB和内存保护</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/42 总线:计算机内部的高速公路.md.html">42 总线:计算机内部的高速公路</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/43 输入输出设备:我们并不是只能用灯泡显示“0”和“1”.md.html">43 输入输出设备:我们并不是只能用灯泡显示“0”和“1”</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/44 理解IO_WAIT:IO性能到底是怎么回事儿?.md.html">44 理解IO_WAIT:IO性能到底是怎么回事儿?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/45 机械硬盘:Google早期用过的“黑科技”.md.html">45 机械硬盘:Google早期用过的“黑科技”</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/46 SSD硬盘(上):如何完成性能优化的KPI?.md.html">46 SSD硬盘(上):如何完成性能优化的KPI?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/47 SSD硬盘(下):如何完成性能优化的KPI?.md.html">47 SSD硬盘(下):如何完成性能优化的KPI?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/48 DMA:为什么Kafka这么快?.md.html">48 DMA:为什么Kafka这么快?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/49 数据完整性(上):硬件坏了怎么办?.md.html">49 数据完整性(上):硬件坏了怎么办?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/50 数据完整性(下):如何还原犯罪现场?.md.html">50 数据完整性(下):如何还原犯罪现场?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/51 分布式计算:如果所有人的大脑都联网会怎样?.md.html">51 分布式计算:如果所有人的大脑都联网会怎样?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/52 设计大型DMP系统(上):MongoDB并不是什么灵丹妙药.md.html">52 设计大型DMP系统(上):MongoDB并不是什么灵丹妙药</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/53 设计大型DMP系统(下):SSD拯救了所有的DBA.md.html">53 设计大型DMP系统(下):SSD拯救了所有的DBA</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/54 理解Disruptor(上):带你体会CPU高速缓存的风驰电掣.md.html">54 理解Disruptor(上):带你体会CPU高速缓存的风驰电掣</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/55 理解Disruptor(下):不需要换挡和踩刹车的CPU,有多快?.md.html">55 理解Disruptor(下):不需要换挡和踩刹车的CPU,有多快?</a>
|
||
</li>
|
||
<li>
|
||
<a href="/专栏/深入浅出计算机组成原理/结束语 知也无涯,愿你也享受发现的乐趣.md.html">结束语 知也无涯,愿你也享受发现的乐趣</a>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
|
||
<div class="sidebar-toggle-inner"></div>
|
||
</div>
|
||
<script>
|
||
function add_inner() {
|
||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||
inner.classList.add('show')
|
||
}
|
||
function remove_inner() {
|
||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||
inner.classList.remove('show')
|
||
}
|
||
function sidebar_toggle() {
|
||
let sidebar_toggle = document.querySelector('.sidebar-toggle')
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
let content = document.querySelector('.off-canvas-content')
|
||
if (sidebar_toggle.classList.contains('extend')) { // show
|
||
sidebar_toggle.classList.remove('extend')
|
||
sidebar.classList.remove('hide')
|
||
content.classList.remove('extend')
|
||
} else { // hide
|
||
sidebar_toggle.classList.add('extend')
|
||
sidebar.classList.add('hide')
|
||
content.classList.add('extend')
|
||
}
|
||
}
|
||
function open_sidebar() {
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
let overlay = document.querySelector('.off-canvas-overlay')
|
||
sidebar.classList.add('show')
|
||
overlay.classList.add('show')
|
||
}
|
||
function hide_canvas() {
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
let overlay = document.querySelector('.off-canvas-overlay')
|
||
sidebar.classList.remove('show')
|
||
overlay.classList.remove('show')
|
||
}
|
||
</script>
|
||
<div class="off-canvas-content">
|
||
<div class="columns">
|
||
<div class="column col-12 col-lg-12">
|
||
<div class="book-navbar">
|
||
<!-- For Responsive Layout -->
|
||
<header class="navbar">
|
||
<section class="navbar-section">
|
||
<a onclick="open_sidebar()">
|
||
<i class="icon icon-menu"></i>
|
||
</a>
|
||
</section>
|
||
</header>
|
||
</div>
|
||
<div class="book-content" style="max-width: 960px; margin: 0 auto;
|
||
overflow-x: auto;
|
||
overflow-y: hidden;">
|
||
<div class="book-post">
|
||
<p id="tip" align="center"></p>
|
||
<div><h1>34 理解虚拟机:你在云上拿到的计算机是什么样的?</h1>
|
||
<p>上世纪 60 年代,计算机还是异常昂贵的设备,实际的计算机使用需求要面临两个挑战。第一,计算机特别昂贵,我们要尽可能地让计算机忙起来,一直不断地去处理一些计算任务。第二,很多工程师想要用上计算机,但是没有能力自己花钱买一台,所以呢,我们要让很多人可以共用一台计算机。</p>
|
||
<h2>缘起分时系统</h2>
|
||
<p>为了应对这两个问题,<a href="https://en.wikipedia.org/wiki/Time-sharing">分时系统</a>的计算机就应运而生了。</p>
|
||
<p>无论是个人用户,还是一个小公司或者小机构,你都不需要花大价钱自己去买一台电脑。你只需要买一个输入输出的终端,就好像一套鼠标、键盘、显示器这样的设备,然后通过电话线,连到放在大公司机房里面的计算机就好了。这台计算机,会自动给程序或任务分配计算时间。你只需要为你花费的“计算时间”和使用的电话线路付费就可以了。比方说,比尔·盖茨中学时候用的学校的计算机,就是 GE 的分时系统。</p>
|
||
<p><img src="assets/d107e645e1f849ebcafab0e4d4b73a9d.png" alt="img" /></p>
|
||
<p><a href="https://commons.wikimedia.org/wiki/File:Unix_Timesharing_UW-Madison_1978.jpeg">图片来源</a></p>
|
||
<p>图片里面的“计算机”其实只是一个终端而已,并没有计算能力,要通过电话线连接到实际的计算机上,才能完成运算</p>
|
||
<h2>从“黑色星期五”到公有云</h2>
|
||
<p>现代公有云上的系统级虚拟机能够快速发展,其实和分时系统的设计思路是一脉相承的,这其实就是来自于电商巨头亚马逊大量富余的计算能力。</p>
|
||
<p>和国内有“双十一”一样,美国会有感恩节的“<a href="https://en.wikipedia.org/wiki/Black_Friday_(shopping)">黑色星期五</a>(Black Friday)”和“<a href="https://en.wikipedia.org/wiki/Cyber_Monday">网络星期一</a>(Cyber Monday)”,这样一年一度的大型电商促销活动。几天的活动期间,会有大量的用户进入亚马逊这样的网站,看商品、下订单、买东西。这个时候,整个亚马逊需要的服务器计算资源可能是平时的数十倍。</p>
|
||
<p>于是,亚马逊会按照“黑色星期五”和“网络星期一”的用户访问量,来准备服务器资源。这个就带来了一个问题,那就是在一年的 365 天里,有 360 天这些服务器资源是大量空闲的。要知道,这个空闲的服务器数量不是一台两台,也不是几十几百台。根据媒体的估算,亚马逊的云服务器 AWS 在 2014 年就已经超过了 150 万台,到了 2019 年的今天,估计已经有超过千万台的服务器。</p>
|
||
<p>平时有这么多闲着的服务器实在是太浪费了,所以,亚马逊就想把这些服务器给租出去。出租物理服务器当然是可行的,但是却不太容易自动化,也不太容易面向中小客户。</p>
|
||
<p>直接出租物理服务器,意味着亚马逊只能进行服务器的“整租”,这样大部分中小客户就不愿意了。为了节约数据中心的空间,亚马逊实际用的物理服务器,大部分多半是强劲的高端 8 核乃至 12 核的服务器。想要租用这些服务器的中小公司,起步往往只需要 1 个 CPU 核心乃至更少资源的服务器。一次性要他们去租一整台服务器,就好像刚毕业想要租个单间,结果你非要整租个别墅给他。</p>
|
||
<p>这个“整租”的问题,还发生在“时间”层面。物理服务器里面装好的系统和应用,不租了而要再给其他人使用,就必须清空里面已经装好的程序和数据,得做一次“重装”。如果我们只是暂时不用这个服务器了,过一段时间又要租这个服务器,数据中心服务商就不得不先重装整个系统,然后租给别人。等别人不用了,再重装系统租给你,特别地麻烦。</p>
|
||
<p>其实,对于想要租用服务器的用户来说,最好的体验不是租房子,而是住酒店。我住一天,我就付一天的钱。这次是全家出门,一次多定几间酒店房间就好啦。</p>
|
||
<p>而这样的需求,用虚拟机技术来实现,再好不过了。虚拟机技术,使得我们可以在一台物理服务器上,同时运行多个虚拟服务器,并且可以动态去分配,每个虚拟服务器占用的资源。对于不运行的虚拟服务器,我们也可以把这个虚拟服务器“关闭”。这个“关闭”了的服务器,就和一个被关掉的物理服务器一样,它不会再占用实际的服务器资源。但是,当我们重新打开这个虚拟服务器的时候,里面的数据和应用都在,不需要再重新安装一次。</p>
|
||
<h2>虚拟机的技术变迁</h2>
|
||
<p>那虚拟机技术到底是怎么一回事呢?下面我带你具体来看一看,它的技术变迁过程,好让你能更加了解虚拟机,从而更好地使用它。</p>
|
||
<p><strong>虚拟机</strong>(Virtual Machine)技术,其实就是指在现有硬件的操作系统上,能够<strong>模拟</strong>一个计算机系统的技术。而模拟一个计算机系统,最简单的办法,其实不能算是虚拟机技术,而是一个模拟器(Emulator)。</p>
|
||
<h3>解释型虚拟机</h3>
|
||
<p>要模拟一个计算机系统,最简单的办法,就是兼容这个计算机系统的指令集。我们可以开发一个应用程序,跑在我们的操作系统上。这个应用程序呢,可以识别我们想要模拟的、计算机系统的程序格式和指令,然后一条条去解释执行。</p>
|
||
<p>在这个过程中,我们把原先的操作系统叫作<strong>宿主机</strong>(Host),把能够有能力去模拟指令执行的软件,叫作<strong>模拟器</strong>(Emulator),而实际运行在模拟器上被“虚拟”出来的系统呢,我们叫<strong>客户机</strong>(Guest VM)。</p>
|
||
<p>这个方式,其实和运行 Java 程序的 Java 虚拟机很像。只不过,Java 虚拟机运行的是 Java 自己定义发明的中间代码,而不是一个特定的计算机系统的指令。</p>
|
||
<p>这种解释执行另一个系统的方式,有没有真实的应用案例呢?当然是有的,如果你是一个 Android 开发人员,你在开发机上跑的 Android 模拟器,其实就是这种方式。如果你喜欢玩一些老游戏,可以注意研究一下,很多能在 Windows 下运行的游戏机模拟器,用的也是类似的方式。</p>
|
||
<p>**这种解释执行方式的最大的优势就是,模拟的系统可以跨硬件。**比如,Android 手机用的 CPU 是 ARM 的,而我们的开发机用的是 Intel X86 的,两边的 CPU 指令集都不一样,但是一样可以正常运行。如果你想玩的街机游戏,里面的硬件早就已经停产了,那你自然只能选择 MAME 这样的模拟器。</p>
|
||
<p><img src="assets/912a6b83c639ae06b61a56327488916b.png" alt="img" /></p>
|
||
<p><a href="https://commons.wikimedia.org/wiki/File:NewMAME.png">图片来源</a></p>
|
||
<p>MAME 模拟器的界面</p>
|
||
<p>不过这个方式也有两个明显的缺陷。第一个是,我们做不到精确的“模拟”。很多的老旧的硬件的程序运行,要依赖特定的电路乃至电路特有的时钟频率,想要通过软件达到 100% 模拟是很难做到的。第二个缺陷就更麻烦了,那就是这种解释执行的方式,性能实在太差了。因为我们并不是直接把指令交给 CPU 去执行的,而是要经过各种解释和翻译工作。</p>
|
||
<p>所以,虽然模拟器这样的形式有它的实际用途。甚至为了解决性能问题,也有类似于 Java 当中的 JIT 这样的“编译优化”的办法,把本来解释执行的指令,编译成 Host 可以直接运行的指令。但是,这个性能还是不能让人满意。毕竟,我们本来是想要把空余的计算资源租用出去的。如果我们空出来的计算能力算是个大平层,结果经过模拟器之后能够租出去的计算能力就变成了一个格子间,那我们就划不来了。</p>
|
||
<h3>Type-1 和 Type-2:虚拟机的性能提升</h3>
|
||
<p>所以,我们希望我们的虚拟化技术,能够克服上面的模拟器方式的两个缺陷。同时,我们可以放弃掉模拟器方式能做到的跨硬件平台的这个能力。因为毕竟对于我们想要做的云服务里的“服务器租赁”业务来说,中小客户想要租的也是一个 x86 的服务器。而另外一方面,他们希望这个租用的服务器用起来,和直接买一台或者租一台物理服务器没有区别。作为出租方的我们,也希望服务器不要因为用了虚拟化技术,而在中间损耗掉太多的性能。</p>
|
||
<p>所以,首先我们需要一个“全虚拟化”的技术,也就是说,我们可以在现有的物理服务器的硬件和操作系统上,去跑一个完整的、不需要做任何修改的客户机操作系统(Guest OS)。那么,我们怎么在一个操作系统上,再去跑多个完整的操作系统呢?答案就是,我们自己做软件开发中很常用的一个解决方案,就是加入一个中间层。在虚拟机技术里面,这个中间层就叫作<strong>虚拟机监视器</strong>,英文叫 VMM(Virtual Machine Manager)或者 Hypervisor。</p>
|
||
<p><img src="assets/e09b64e035a3b1bd664b0584a7b52fbf.jpeg" alt="img" /></p>
|
||
<p>如果说我们宿主机的 OS 是房东的话,这个虚拟机监视器呢,就好像一个二房东。我们运行的虚拟机,都不是直接和房东打交道,而是要和这个二房东打交道。我们跑在上面的虚拟机呢,会把整个的硬件特征都映射到虚拟机环境里,这包括整个完整的 CPU 指令集、I/O 操作、中断等等。</p>
|
||
<p>既然要通过虚拟机监视器这个二房东,我们实际的指令是怎么落到硬件上去实际执行的呢?这里有两种办法,也就是 Type-1 和 Type-2 这两种类型的虚拟机。</p>
|
||
<p>我们先来看 Type-2 类型的虚拟机。在 Type-2 虚拟机里,我们上面说的虚拟机监视器好像一个运行在操作系统上的软件。你的客户机的操作系统呢,把最终到硬件的所有指令,都发送给虚拟机监视器。而虚拟机监视器,又会把这些指令再交给宿主机的操作系统去执行。</p>
|
||
<p>那这时候你就会问了,这和上面的模拟器看起来没有那么大分别啊?看起来,我们只是把在模拟器里的指令翻译工作,挪到了虚拟机监视器里。没错,Type-2 型的虚拟机,更多是用在我们日常的个人电脑里,而不是用在数据中心里。</p>
|
||
<p>在数据中心里面用的虚拟机,我们通常叫作 Type-1 型的虚拟机。这个时候,客户机的指令交给虚拟机监视器之后呢,不再需要通过宿主机的操作系统,才能调用硬件,而是可以直接由虚拟机监视器去调用硬件。</p>
|
||
<p>另外,在数据中心里面,我们并不需要在 Intel x86 上面去跑一个 ARM 的程序,而是直接在 x86 上虚拟一个 x86 硬件的计算机和操作系统。所以,我们的指令不需要做什么翻译工作,可以直接往下传递执行就好了,所以指令的执行效率也会很高。</p>
|
||
<p>所以,在 Type-1 型的虚拟机里,我们的虚拟机监视器其实并不是一个操作系统之上的应用层程序,而是一个嵌入在操作系统内核里面的一部分。无论是 KVM、XEN 还是微软自家的 Hyper-V,其实都是系统级的程序。</p>
|
||
<p><img src="assets/9c30f8d93270a9563154aa732b9c9f8e.jpeg" alt="img" /></p>
|
||
<p>因为虚拟机监视器需要直接和硬件打交道,所以它也需要包含能够直接操作硬件的驱动程序。所以 Type-1 的虚拟机监视器更大一些,同时兼容性也不能像 Type-2 型那么好。不过,因为它一般都是部署在我们的数据中心里面,硬件完全是统一可控的,这倒不是一个问题了。</p>
|
||
<h3>Docker:新时代的最佳选择?</h3>
|
||
<p>虽然,Type-1 型的虚拟机看起来已经没有什么硬件损耗。但是,这里面还是有一个浪费的资源。在我们实际的物理机上,我们可能同时运行了多个的虚拟机,而这每一个虚拟机,都运行了一个属于自己的单独的操作系统。</p>
|
||
<p>多运行一个操作系统,意味着我们要多消耗一些资源在 CPU、内存乃至磁盘空间上。那我们能不能不要多运行的这个操作系统呢?</p>
|
||
<p>其实是可以的。因为我们想要的未必是一个完整的、独立的、全虚拟化的虚拟机。我们很多时候想要租用的不是“独立服务器”,而是独立的计算资源。在服务器领域,我们开发的程序都是跑在 Linux 上的。其实我们并不需要一个独立的操作系统,只要一个能够进行资源和环境隔离的“独立空间”就好了。那么,能够满足这个需求的解决方案,就是过去几年特别火热的 Docker 技术。使用 Docker 来搭建微服务,可以说是过去两年大型互联网公司的必经之路了。</p>
|
||
<p><img src="assets/6cbf5f5f4275bc053fabcd3480304a35.jpeg" alt="img" /></p>
|
||
<p>在实践的服务器端的开发中,虽然我们的应用环境需要各种各样不同的依赖,可能是不同的 PHP 或者 Python 的版本,可能是操作系统里面不同的系统库,但是通常来说,我们其实都是跑在 Linux 内核上的。通过 Docker,我们不再需要在操作系统上再跑一个操作系统,而只需要通过容器编排工具,比如 Kubernetes 或者 Docker Swarm,能够进行各个应用之间的环境和资源隔离就好了。</p>
|
||
<p>这种隔离资源的方式呢,也有人称之为“操作系统级虚拟机”,好和上面的全虚拟化虚拟机对应起来。不过严格来说,Docker 并不能算是一种虚拟机技术,而只能算是一种资源隔离的技术而已。</p>
|
||
<h2>总结延伸</h2>
|
||
<p>这一讲,我从最古老的分时系统讲起,介绍了虚拟机的相关技术。我们现在的云服务平台上,你能够租到的服务器其实都是虚拟机,而不是物理机。而正是虚拟机技术的出现,使得整个云服务生态得以出现。</p>
|
||
<p>虚拟机是模拟一个计算机系统的技术,而其中最简单的办法叫模拟器。我们日常在 PC 上进行 Android 开发,其实就是在使用这样的模拟器技术。不过模拟器技术在性能上实在不行,所以我们才有了虚拟化这样的技术。</p>
|
||
<p>在宿主机的操作系统上,运行一个虚拟机监视器,然后再在虚拟机监视器上运行客户机的操作系统,这就是现代的虚拟化技术。这里的虚拟化技术可以分成 Type-1 和 Type-2 这两种类型。</p>
|
||
<p>Type-1 类型的虚拟化机,实际的指令不需要再通过宿主机的操作系统,而可以直接通过虚拟机监视器访问硬件,所以性能比 Type-2 要好。而 Type-2 类型的虚拟机,所有的指令需要经历客户机操作系统、虚拟机监视器、宿主机操作系统,所以性能上要慢上不少。不过因为经历了宿主机操作系统的一次“翻译”过程,它的硬件兼容性往往会更好一些。</p>
|
||
<p>今天,即使是 Type-1 型的虚拟机技术,我们也会觉得有一些性能浪费。我们常常在同一个物理机上,跑上 8 个、10 个的虚拟机。而且这些虚拟机的操作系统,其实都是同一个 Linux Kernel 的版本。于是,轻量级的 Docker 技术就进入了我们的视野。Docker 也被很多人称之为“操作系统级”的虚拟机技术。不过 Docker 并没有再单独运行一个客户机的操作系统,而是直接运行在宿主机操作系统的内核之上。所以,Docker 也是现在流行的微服务架构底层的基础设施。</p>
|
||
<h2>推荐阅读</h2>
|
||
<p>又到了阅读英文文章的时间了。想要更多了解虚拟机、Docker 这些相关技术的概念和知识,特别是进一步理解 Docker 的细节,你可以去读一读 FreeCodeCamp 里的<a href="https://www.freecodecamp.org/news/a-beginner-friendly-introduction-to-containers-vms-and-docker-79a9e3e119b/">A Beginner-Friendly Introduction to Containers, VMs and Docker</a>这篇文章。</p>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div style="float: left">
|
||
<a href="/专栏/深入浅出计算机组成原理/33 解读TPU:设计和拆解一块ASIC芯片.md.html">上一页</a>
|
||
</div>
|
||
<div style="float: right">
|
||
<a href="/专栏/深入浅出计算机组成原理/35 存储器层次结构全景:数据存储的大金字塔长什么样?.md.html">下一页</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||
</div>
|
||
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70997ad19e313cfa","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
|
||
</body>
|
||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
|
||
<script>
|
||
window.dataLayer = window.dataLayer || [];
|
||
function gtag() {
|
||
dataLayer.push(arguments);
|
||
}
|
||
gtag('js', new Date());
|
||
gtag('config', 'G-NPSEEVD756');
|
||
var path = window.location.pathname
|
||
var cookie = getCookie("lastPath");
|
||
console.log(path)
|
||
if (path.replace("/", "") === "") {
|
||
if (cookie.replace("/", "") !== "") {
|
||
console.log(cookie)
|
||
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
|
||
}
|
||
} else {
|
||
setCookie("lastPath", path)
|
||
}
|
||
function setCookie(cname, cvalue) {
|
||
var d = new Date();
|
||
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
|
||
var expires = "expires=" + d.toGMTString();
|
||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||
}
|
||
function getCookie(cname) {
|
||
var name = cname + "=";
|
||
var ca = document.cookie.split(';');
|
||
for (var i = 0; i < ca.length; i++) {
|
||
var c = ca[i].trim();
|
||
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
|
||
}
|
||
return "";
|
||
}
|
||
</script>
|
||
</html>
|