Fork me on GitHub

深入浅出计算机组成原理——原理篇:存储与I/O系统(46-51)

全文内容主要来自对课程《深入浅出计算机组成原理》的学习笔记。

46 | SSD硬盘(上)

SSD 的读写原理

没有寻道,随机读写快。
缺点:耐用性(重复擦写)差。

SLC、MLC、TLC 和 QLC

一个电容,有无电压代表0、1,即1bit信息。这种方式为 SLC(Single-Level Cell) 颗粒。与 CPU Cache 类似,存储有限。

如果一个单元存储超过1bit呢?

于是发明了 MLC(Multi-Level Cell)、TLC(Triple-Level Cell)以及 QLC(Quad-Level Cell),分别可以存储2、3、4bit。

因为有一个电压计可以通过不同的电压值表示不同的bit。比如,15个不同的电压位,加0电压总共16个值则可以表示4bit。但对电压精度要求很高,会导致充放电慢。

P/E 擦写问题

SSD 由多个裸片(Die)叠在一起组成,每个如下所示。

  • 一个裸片会分成多个平面(Plane),容量约GB级;
  • 一个平面会分很多(Block),容量约MB级;
  • 一个块分多个(Page),容量约4KB。

SSD 写入叫 Program,不是复写来完成,需要先擦除(Erase)。单位是一个页(Page),擦除是按照块(Block)来进行。硬盘寿命是每个块的可擦除的次数,物理材料原因。

SLC 一般在10万次,MLC约1万次,TLC和QLC约几千次。

SSD 读写的生命周期

下图是SSD硬盘读写的流程:

  • 绿色:有效数据;
  • 红色:已删除数据;
  • 白色:无数据。

因为写入最小单位是页,擦除最小单位是块,数据一多容易出现红色空洞占的地方也会越来越多,因为绿色页的存在,整块不能擦除,白色页就越来越少。

所以需要磁盘碎片整理,如下图所示,即把有效的零散的绿色数据集中搬移到新空间,然后擦除原来的块,就可以空出容量了。

厂商为了“磁盘碎片整理”,往往有一些预留空间(Over Provisioning),一般在7%-15%。


47 | SSD硬盘(下)

作为系统盘的时候,大多部分只读不写。擦除会反复发生在其他用来存放数据的地方,容易变成坏块,即容量变小了。

磨损均衡、TRIM 和写入放大效应

FTL 和磨损均衡

为了减少坏块,我们尽量平摊擦除到每个块上,即磨损均衡(Wear-Leveling)。实现方式就是FTL 这个闪存转换层

与内存管理类似,在 FTL 里面,存放了逻辑块地址(Logical Block Address,简称 LBA)到物理块地址(Physical Block Address,简称 PBA)的映射。系统都是访问前者,实际操作是后者。

FTL 能够记录物理块被擦写的次数。如果某块被擦写的次数多了,可以将它挪到一个擦写次数少的物理块上。

TRIM 指令的支持

操作系统的逻辑层和 SSD 的逻辑层里的块状态,是不匹配的。

因操作系统删除数据的时候,是把对应的 inode 里面的元信息清理掉,物理层面仅标记成可写入,没有实际擦除。所以日常的文件删除,都只是一个操作系统层面的逻辑删除,有被恢复的可能。

为了磨损均衡,很多时候在都在搬运很多已经删除了的数据。解法是 TRIM 命令,在文件被删除的时候,让操作系统去通知 SSD 硬盘,对应的逻辑块已经标记成已删除了。

写入放大

SSD 硬盘容易越用越慢。

空间被占用多了之后,空白不足,需要经常进行整理,于是变慢。

写入放大 = 实际的闪存写入的数据量 / 系统通过 FTL 写入的数据量,该值越大(说明为了完成操作多了很多整理),性能越差。

AeroSpike

SSD 虽然有劣势,但可以充分利用其优势,比如 AeroSpike

AeroSpike 这个专门针对 SSD 硬盘特性设计的 Key-Value 数据库(键值对数据库)

利用SSD物理特性:

  • 不通过操作系统,直接操作 SSD 中的块和页;
  • 写入的时候尽可能写较大的数据块,一般128KB;
  • 读取的时候可以读512 字节(Bytes)这样的小数据。

AeroSpike 需要响应时间短,所以写入放大严重,优化:

  • 持续地进行磁盘碎片整理。(块碎片>50%)
  • 建议只用到容量最大额的50%。(降低写放大)

48 | DMA: Kafka 快速原因

CPU 的主频 2GHz 意味每秒20亿次操作,诸如大文件复制等操作,CPU 大部分时间都空闲等待。DMA 技术,直接内存访问(Direct Memory Access)来减少 CPU 等待的时间。

理解 DMA,一个协处理器

主板上一块芯片,在内存和 I/O 设备的数据传输时,不通过 CPU 控制,直接通过 DMA 控制器(DMA Controller,简称 DMAC),也是协处理器。

DMAC 使用价值:

  • 传输的数据极大、速度快,减少 CPU 依赖;
  • 传输的数据极小、速度慢,等数据到齐再发送,减少 CPU 忙等待。

DMAC 也是一个特殊的 I/O 设备,链接总线进行传输。总线上设备分主设备从设备
只有主设备可以主动发起数据传输,如 CPU。I/O 设备只能发送控制信号,告知 CPU 有数据要传,再由 CPU 拉数。
DMAC 既是一个主设备(对于IO设备),又是一个从设备(对于CPU)。

DMAC 进行数据传输的过程(硬盘加载数据为例):

  1. CPU 向 DMAC 发起请求,即修改其配置寄存器;
  2. 提供给 DMAC 的信息:
    • 源地址的初始值(硬盘IO地址)以及传输时候的地址增减方式(是否大往小地址传);
    • 目标地址初始值(目的地地址)和传输时候的地址增减方式;
    • 要传输的数据长度。
  3. 设置后,DMAC 变为空闲(Idle);
  4. 硬盘向 DMAC 发起数据传输请求;
  5. DMAC 响应;
  6. DMAC 向硬盘接口发起总线读请求并读取;
  7. DMAC 向内存发起总线写请求并写入;
  8. 反复上述6、7,直到指定长度数据传输完成,回到第 3 步空闲。

因显示器、网卡、硬盘对于数据传输的需求都不一样,所以各个设备里面都有自己的 DMAC 芯片了。

Kafka 的实现原理

Kafka 项目是通过利用 DMA 的方式实现了非常大的性能提升,是目前实时数据传输管道的标准解决方案。

Kafka 两种常见海量数据传输:

  • 从网络中接收数据并落盘;
  • 从本地磁盘读取并通过网络发送出去。

从本地磁盘读取并通过网络发送出去,这个过程数据一共发生四次传输,2次 DMA 传输,2次 CPU 控制传输。

整个过程:

  1. 从硬盘读到系统内核缓冲区,DMA 搬运;
  2. 内核缓冲区复制到内存,CPU 搬运;
  3. 从内存写到操作系统的 Socket 缓冲区,CPU 搬运;
  4. 从 Socket 缓冲区写到网卡缓冲区,DMA 搬运。

在 Kafka 中,则只有上述的 1、4 步骤。数据绕过内存,直接通过 Channel,写入到对应的网络设备里。并且,对于 Socket 的操作,也不是写入到 Socket 的 Buffer 里面,而是直接根据描述符(Descriptor)写入到网卡的缓冲区里面。

没有在内存层面去“复制(Copy)”数据,所以也称上述方法是零拷贝(Zero-Copy)。

传输同样数据的时间,可以缩减为原来的 1/3


49 | 数据完整性(上)

单比特翻转

作者举例遇到的硬件错误,由于定制的硬件没有使用 ECC 内存,内存中出现了单比特翻转(Single-Bit Flip)。

一个 ASCII 码二进制表示是 0010 0100,可能是 0011 0100 在第4位发生单比特反转变来的。随机,不可复现,而 ECC 内存的全称是 Error-Correcting Code memory,中文名字叫作纠错内存

奇偶校验和校验位

奇偶校验,即内存里面的 N 位比特当成是一组,1 的个数是奇数还是偶数,并记录在校验码位

如,101010111,前8位数数据位,最后一位就是校验码位

该算法速度快,并且能判断内存数据是否出错。缺陷:

  1. 只能解决遇到奇数个的错误;
  2. 只能发现错误,不能纠正错误。

ECC 内存所使用的解决方案,既可以发现,也可以纠错。2个版本:

  • 纠错码(Error Correcting Code),发现并纠正;
  • 纠删码(Erasure Code),不能纠正时,直接删除。

50 | 数据完整性(下)

纠错码,需要既能判断是否有错,还要找出错误位置。

海明码

海明码(Hamming Code)是最知名的纠错码,上世纪四十年代发明,沿用至今。

最基础的是 7-4 海明码,即 7bit 数据位,4bit 校验位。因为,4bit 可以表示 16 个数,假设全部正确状态占用一个数,那么剩余 15 个数可以用来纠正 15 中单比特反转错误。

这里需要注意,如果纠错位少一位,变成3bit,就只能表达7个校验位,而校验位本身也会出现错误,所以7-4实际上有11种单比特反转错误。

数据位有 K 位,校验位有 N 位,需要满足 K + N + 1 <= 2^N

一个简单的理解:数据位+纠错位总共有 K+N 位,那么就有 K+N 种单比特错误位置,外加1个全部正确状态,故 N 位的校验位需要能够表达至少 K + N + 1 个数值,于是有了上述关系。

海明码的纠错原理

校验位数的原理清楚了,那么怎么构建校验位不同数值对应的错误位映射关系呢?

这里直接以7-4海明码为例:

  1. 在 11 位中将 $2^k$ 位作为校验位,即 1、2、4、8 位,记为 p1-p4;
  2. 剩下的 7 位作为数据位,记为 d1-d7,来存储有效信息;
  3. 我们需要将数据位分组到每个校验位上,分组方式是根据二进制各个位置的1值

如下图,如:

  • 针对位置1的校验位p1,分到该组的数据位就是二进制下第0位为1的所有,包括1(自身)、3、5、7、9、11;
  • 针对位置4的校验位p3,分到该组的数据位就是二进制下第2位为1的所有,包括4(自身)、5、6、7;
  1. 分好组了,校验位的值可以根据组内位置奇偶校验法得到。

任何一个数据码出错了,就至少会有对应的两个或者三个校验码对不上,这样我们就能反过来找到是哪一个数据码出错了。

实际上找出错位方式很简单,即校验位按照 p4-p1 排列二进制的数值。

首先校验位需要按照 p4-p1 的方式来排列成二进制;比如 11 位中,第 3 位bit(即d1)反转了,那么对应上述表格,p1、p2校验位会为 1,即 0011,刚好是第 3 位。再比如第 7 位,那么就是 0111,刚好是7。

这里很像一道 coding 问题:1000 瓶药水只有 1 瓶有毒,有 10 个试验用的小白鼠,如何定位有毒的那瓶?

解法:

  1. 10 个小白鼠作为 10 个 bit 位,可以表示 0 到 $2^{10}-1$,能够涵盖 1000;
  2. 1000 瓶药水按照顺序编码,编码对应 bit 位为 1 的药水要给对应位置的小白鼠喝;
  3. 死亡的小白鼠,将对应 bit 位置为 1,那么 10 个 bit 位对应的值就是第几瓶药水有毒。

海明距离

对于两个二进制表示的数据,他们之间有差异的位数,我们称之为海明距离。


51 | 分布式计算

数据中心里一台计算机一般不够,面临3个问题:

  1. 垂直扩展和水平扩展的选择问题;
  2. 如何保持高可用性(High Availability);
  3. 一致性问题(Consistency)。

从硬件升级到水平扩展

假设采买了一台云服务器:1 个 CPU 核心、3.75G 内存以及一块 10G 的 SSD 系统盘。

当请求增长,性能不足时需要增加资源:

  • 垂直扩展(Scale Up):换成 2 个 CPU 核心、7.5G 内存;
  • 水平扩展(Scale Out):买 2 台 1 个 CPU 核心、3.75G 内存。

垂直扩展总有上限,因为物理机的原因。水平扩展,则需要软件层面改造,进入分布式,需要负载均衡

分布式,即通过消息传递(Message Passing)而不是共享内存(Shared Memory)的方式,让多台不同的计算机协作起来共同完成任务

理解高可用性和单点故障

系统的可用性(Avaiability):系统可以正常服务的时间占比。

如可用性是99.99%,则表示服务计划外的宕机时间<=4.32分钟/月。

水平扩展具有天然的优势,因为负载均衡能够通过健康检测(Health Check)发现坏掉的服务器,自动把其上的流量切换到其他正常服务器上,即故障转移(Failover)。

单点故障问题(Single Point of Failure,SPOF):任何一台服务器出错了,整个系统就没法用了。

解决单点故障问题就是移除单点,通过水平扩展,使得单台服务器挂了不影响其他正常使用。

但是,单点可能存在多处,比如虽然服务器水平扩展了,但物理机在一个机房,交换机容易成为单点。这时候就需要异地多活的系统设计和部署。即,服务器分地区采购后部署服务,很多公司都会采用。

故障转移(Failover)机制的生效,需要服务进行健康监测(Health Check),即每隔很短时间检查一次各服务器是否正常运行,如果有,则将流量转移到其他正常机器。


-------------本文结束感谢您的阅读-------------

本文标题:深入浅出计算机组成原理——原理篇:存储与I/O系统(46-51)

文章作者:

原始链接:https://www.xiemingzhao.com/posts/computerOrgArc46to51.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。