存储技术在生活中无处不在,例如手机、电脑、监控设备、行车记录仪等都需要存储设备(硬盘、U盘、SD卡等),下面介绍下其中的一些基础知识。
先从整体上认识存储设备是由哪些部分组成:
如下是SSD的结构图,闪存(NAND Flash Memory)是数据实际存储的地方。在我们平常的印象里,固态硬盘的数据存储是非常稳定、不会出错的。但其实在闪存中,数据存储并不稳定且会出错。将“不可靠”转化成“可靠”,需要控制器(Controller)的帮忙。控制器需要负责处理操作系统指令、管理闪存等,对读写性能、数据纠错等有着关键作用。
都说计算机的数据是由0和1构成的,但具体是怎么做到的呢?这些电子器件哪来的0和1呢?比如这里所说的闪存,是如何表示0和1的呢?
先说一个易懂的理解方式:可以把闪存想象成一个球,当球里的电子数较多时,表示为“0”;当球里的电子数较少时,表示为“1”。
要表示0时,往球里注入电子,该过程称为“写”(Program)
要表示1时,去掉球里的电子,该过程称为“擦”(Erase)
要读取值时,通过判断电子数量是否超过某个阈值,该过程称为“读”(Read)。
日常的存储设备(如固态硬盘、U盘、SD卡等)里就靠大量的这些球来存储数据。
再说下实际的版本:闪存最基本的存储单元是一个浮栅晶体管(Floating Gate transistors),当浮栅层(Floating Gate)里电子(electrons)较多时表示为“0”,较少时则表示为“1”。由于浮栅层上下被绝缘层包围,存储在里面的电子不会因外部的掉电而消失(也就是说,当我们电脑关机后,硬盘里的数据并不会丢失),因此闪存是非易失性存储器(Non-Volatile Memories)。
要表示“0”时,在控制极上加正电压,电子从衬底通过隧道氧化层进入浮栅极,该过程称为“写”(Program)
要表示“1”时,在衬底上加正电压,电子从浮栅极通过隧道氧化层回到衬底,该过程称为“擦”(Erase)
要读取值时,通过施加特定的电压,如果能导通,说明浮栅极里电子较少,表示读到了“1”;如果不能导通,说明浮栅极里电子较多,表示读到了“0”。
下面这张图同时展现出了实际的版本(图的上半部分)和通俗的版本(图的下半部分)。
英文名 | 中文名 |
---|---|
Control Gate | 控制栅极 |
Oxide | 氧化层 |
Floating Gate | 浮栅层 |
Source | 源极 |
Drain | 漏极 |
substrate | 衬底 |
Erase | 擦 |
Program | 写 |
Read | 读 |
注意到,闪存对0/1状态的改变,是通过对闪存单元施加高电压,使得电子能够通过隧道氧化层。但是,随着擦写次数(PE cycling)的增加,隧道氧化层会变弱,导致电子从浮栅泄露,使得该存储单元损坏,无法正确存储数据。
上述一个存储单元仅存储1 bit 的数据,表示两种状态——0或1,称为SLC(Single Level Cell)。通过对电压的进一步细分,一个存储单元还可以存储2 bit的数据,表示4种状态——10、00、01、11,称为MLC(Multiple Level Cell);存储 3 bit的数据,表示8种状态——111、110、101、100、011、010、001、000,称为TLC(Triple Level Cell)。目前TLC是主流。
当读取数据时,SLC只需要读1次,而MLC需要读2次、TLC需要读3次。
这就跟信息论关联了起来:在信息论中,如果一个系统有 n 种可能的状态,那么它能够存储的信息量可以表示为 log2n 比特。
对于SLC,一个单元有2种状态,因此每个单元存储 log22=1比特
对于MLC,一个单元有4种状态,因此每个单元存储log24=2比特
对于TLC,一个单元有8种状态,因此每个单元存储log28=3比特
注意,闪存中并不是采用普通的二进制编码方式,而是用格雷码,这是为什么?
格雷码(Gray Code)是一种特殊的二进制编码方式,相邻的两个二进制位之间只相差一个比特。
以3-bit举例:
普通二进制:000, 001, 010, 011, 100, 101, 110, 111
格雷码:000, 001, 011, 010, 110, 111, 101, 100
如图是SLC、MLC、TLC的电压阈值分布图(Threshold Voltage distribution),可以看到MLC和TLC采用的就是格雷码,相邻的二进制数之间只相差一个比特。
格雷码的主要优点是,当信号受到噪声干扰时,它能够更容易地检测到错误。因为格雷码的相邻位数之间只有一个比特的差异,可以让数的变化在位的反应上影响最小。这使得格雷码在通信和数据存储领域具有更高的抗干扰能力。
以闪存为例,如果采用传统的二进制编码,随着存储状态的变化,可能会出现多位同时发生变化。比如"011"(3)和"100"(4)是相邻的,如果电压有所偏移,3个比特中就有2个比特出现错误。如果采用格雷码,相邻的编码只有1个比特不同,也就仅有1个比特出现错误,这样大大减少了由电压不稳定引起的错误。
上述是闪存中的一个存储单元,下面介绍下闪存芯片的组织架构。
NAND闪存本身被划分为多个块(Block),每个块包含多个内存页(Page)。
如图是一个 Block 的组织架构,一个 Word-Line 对应一个物理 page 。一个 Block 的所有存储单元都是共用一个衬底的,因此擦除操作的最小单元是一个Block。而读写单元的最小单元是一个Page,通过Bit-Line和Word-Line进行操作。
要写前,需要先进行擦除操作,将Block中的所有单元置为1。要写时,将对应的Wordline设为高电压,表示选中该Page。
对于表示“1”的单元,将Bitline设为2V,阻止隧穿效应,数据保持为“1”;对于表示“0”的单元将Bitline接地,由于隧穿效应,电子从沟道到浮栅,数据变为“0”。
要读时,将对应的Wordline设为2.5V,其他Wordline设为5V,即其它Page是导通的状态。如果Bitline能导通,说明读到的是“1”;如果Bitline不能导通,说明读到的是“0”。
这种读写方式也带来了读干扰和写干扰的问题,会导致闪存保存的数据出错。例如:
读干扰:读取某页时影响相邻页的数据。
写干扰:写入数据时影响其他页的数据。
闪存出错的原因有很多种,除了上述所说的PE次数、读写干扰外,数据保留时间、读写温度、封装工艺等都可能会导致数据出错。对于不同的出错原因SSD中会有不同的预防方式。例如,对于数据保留过长导致数据出错有如下措施:电脑在上电情况下,会扫描硬盘中哪些数据处于长时间保存的状态,出于安全考虑,会将数据搬到其它地方。
这就对纠错有了要求。想象一下,你辛苦制作了很多页PPT,点击保存后舒舒服服去睡觉。假如数据只是简单复制在闪存中,那么等过段时间,可能会发现PPT出现了错误甚至打不开了,所有的努力都付诸东流。这显然是无法接受的!(如果丢失的是与操作系统相关的数据,甚至会导致电脑无法开机。)
闪存中的纠错算法一般为BCH或LDPC算法。网上教程很多,这里暂时提供一个简单粗暴的理解方式。
假设有这么一个对话:
大爷:"你找谁啊"
张三:“我找马东梅”
大爷:“什么东梅”
张三:“马东梅,马,骑马的马”
在这则对话中, 张三为了让大爷接受到自己所要传递的信息,加上了冗余数据“骑马的马”。这样,大爷即使一开始没听清楚,判断成“妈”“哪”等,通过该冗余数据也能得出小明说的是“马”。
同样的,闪存中也是通过添加冗余数据来尽可能确保信息能够正确传输:写时,原先的数据会加上冗余数据一起写入;读时,即使数据出现了错误,在纠错算法的解码后,也能得到原先正确的数据。
不同纠错算法的纠错能力不一样,例如有的算法宣称每 1KB 数据允许有 48bit 翻转。
除了添加冗余数据外,写入闪存前还要将数据随机化(Data Scrambling)。这是因为不断输入全0或全1,很容易导致闪存内部电量不均衡,从而造成信号抗干扰性下降,导致这些数据在闪存中可靠性变差。
(引用下论文 https://arxiv.org/pdf/1706.08642 的一段话:To reduce the dependence of the error rate on data values, an SSD controller first scrambles the data before writing it into the flash chips. The key idea of scrambling is to probabilistically ensure that the actual value written to the SSD contains an equal number of randomly distributed zeroes and ones, thereby minimizing any data-dependent behavior. )
因此,闪存的读写数据流如下:
写时,添加冗余数据并随机化
读时,去随机化并进行纠错,从而得到所需数据