【重要】NAND Flash基础知识简介

NAND Flash是一种非易失存储介质(掉电后数据不会丢失),常见的U盘、TF卡/SD卡,以及大部分SSD(固态硬盘)都是由它组成的。 本文主要介绍其组成及工作原理。

为了表述方便,后面所说的Flash仅指NAND Flash。

一、Flash基本组成单元:SLC/MLC/TLC

Flash的基本组成单元是浮栅晶体管,其状态可以用来指示二进制的0或1。写操作就是往晶体管中注入电子,使之充电;擦除操作则是把晶体管中的电子排出,使之放电。由于这是个模拟系统,晶体管并不存在绝对的空和满状态,其中的电子数目可以处于空和满之间的任一个状态。

由此可见,可以根据晶体管中电子的数目来指示二进制的0和1。比如在SLC(Single Level Cell)中,晶体管中电子数目小于50%的时候代表1,大于50%的时候代表0。

SLC是对电子数目做的一阶量化,所以一个晶体管可以代表两个状态:0和1。如果我们对晶体管中的电子数目做二阶量化,一个晶体管就可以代表四个状态:少于25%代表00,25% ~ 50%代表01,50% ~ 75%代表10、大于75%代表11。这就是MCL(Multi Level Cell)的做法。

当然我们还可以对晶体管中的电子数目做三阶量化,一个晶体管就可以代表八个状态:000、001、010、011、100、101、110、111。这是TLC(Three Level Cell)的做法。

也就是说,量化等级越高,一个晶体管可以表示的状态越多,存储密度就越大,同等数量的存储单元组成的存储介质,存储容量也越大。

晶体管电子数目量化示意图

晶体管电子数目量化示意图

如上图所示,可以把晶体管比作水桶,晶体管内的电子比作水:

  • 由于SLC只有两个状态,只需要保证电子数目多于一半或少于一半即可,所以注入/排放电子的过程比较简单,执行起来很快;对于MLC,有四个状态,对注入/排放电子的精度要求就比较高,执行起来就没那么快了;对于TLC,有八个状态,对注入/排放电子的精度要求更高,执行的就更慢了。另外,写入的数据也会影响效率,比如对于MLC,写入代表满状态的00和代表空状态的11,效率要高于01和10(清空一杯水和倒满一杯水肯定比倒1/4,、1/2杯水简单,当然这个影响在业务层看来可能比较小)。
  • 另一方面,如果水桶发生损坏,比如在上半部分产生了一个缺口(擦除操作会导致介质磨损,最终导致电子泄露),对于SLC可能没影响,可以正常使用,对于MLC和TLC可能由于无法区分多个状态,就无法使用了。NAND Flash的寿命在很大程度上受所用存储单元类型影响,单个晶体管中存放的状态越多,容错性越差,寿命越短。

不同组成单元对Flash性能和寿命的影响

从上面的原理可以看出,SLC、MLC、TLC的性能和寿命是递减的,存储密度是递增的。 下面是一组具体的数据:

性能和寿命

性能和寿命

从上图可以看出:

  • 随着每个单元代表的比特数增加,读、写、擦除耗时也在增加
  • 无论是SLC还是MCL、TLC,擦除耗时(ms数量级)都远高于读写耗时(us数量级)
  • SLC的擦写次数远大于MLC、TLC,也就是说寿命长。
  • SLC每个晶体管只能代表一个比特,从存储密度看,是最低的,TLC存储密度最高,MLC次之。

总的来看,SLC的性能、寿命、稳定性是优于MLC的,当然价格也更贵,MCL次之,TLC最次。

二、Flash的结构及特点

Flash的结构

Flash中存在下面几个基本概念:package、die、plane、block、page(page对应于普通硬盘HDD中的sector,即常说的扇区)。 下面是一个示意图,我们由大到小拆解下:

  • package是存储芯片,即拆解固态硬盘或者SD卡后看到的NAND Flash颗粒。
  • 每个package包含一个或多个die。die是可以独立执行命令并上报状态的最小单元。
  • 每个die包含一个或多个plane(通常是1个或2个)。不同的plane间可以并发操作,不过有一些限制。
  • 每个plane包含多block*,block是最小擦除单元
  • 每个block包含多个page, page是最小的读写单元

NAND Flash布局示意图

NAND Flash布局示意图

这里我们需要重点关注的是:

  • 读写的操作对象是page,通常是512字节或者2KB
  • 擦除的对象是block,通常包含32或64个page(16KB或64KB)
  • 每个block在写入前需要先擦除
  • block擦除前,需要保证本block上所有page中都不包含有效数据(如果有些page包含有效数据,需要先搬移到其他地方)

flash的最小操作单元

flash的最小操作单元

Program/Erase Cycles

Flash还有一个重要特性:Flash不支持更新操作,严格说应该是不支持原址更新。 如果我们已经往某个page中写入了数据,想修改这个page中的内容,只能通过下面的方法:

  1. 先把本page所属block的数据全部读出来,比如先读到内存DRAM
  2. 然后修改对应page的内容
  3. 接下来擦除整个block
  4. 最后把修改后的block数据回写到Flash

Flash芯片上block的擦写次数是有限的,最大擦写次数称为PE Cycles(Program erase cycles, 往Flash写入的过程又称为编程过程,即program)。如果采用上面的方法进行原址更新,Flash很容易就会被用坏的。一个折中的方法是:将新数据写到一个新的page中,并将原来的page标记为无效,如下图所示:

说明:新的page和老的page可以位于同一个block,也可以位于不同的block,甚至位于不同的die。

flash数据更新示意图

flash数据更新示意图

这样做会带来另外的问题:

  1. 数据所在page变了,后续如何访问新的数据(谁来维护这个映射关系)
  2. 无效的page什么时候回收(上面的做法只是延迟了擦除block的时间,但是空闲page迟早有用完的时候)
  3. 如何选择新的page,保证整个flash的擦写均衡(避免有的block擦除次数多,有的block擦除次数少)

接下来登场的FTL会解决上面的问题。需要注意的是,擦除的耗时远大于读写耗时,相关逻辑处理不好的话会影响性能。所以目前有很多FTL的优化算法。

关于Flash的原址更新补充如下说明:假设一个空白page是全1,比如1111 1111,对它的写操作只能把其中的某些位由1变为0(第一次写可以把1111 1111改成1111 0000,第二次可以继续把1111 0000改成0011 0000,从这个角度看,page可以执行多次写操作),而无法再把0变为1(如果某个写操作涉及把0变为1,那就无能为力了,只有整个block擦除后再写入了)。

三、The Flash Translation Layer

逻辑地址映射

在NAND Flash出现前,逻辑地址映射(Logical Block Mapping, 简称LBA)就存在了,它是为了对上层的文件系统屏蔽Physical Block Address(PBA)的细节,让寻址更简单、灵活。

下面是逻辑地址和物理地址映射示意图:

逻辑地址和物理地址映射示意图

逻辑地址和物理地址映射示意图

上图所示属于page-to-page的映射,这种映射的缺点是FTL中维护大量的映射关系,好处是管理方便(某个page更新时,不用关心新数据是否和原数据位于同一个block,如下图所示)。

page-to-page映射时的数据更新

page-to-page映射时的数据更新

实际一般使用block-to-block的映射(这种情况下,逻辑page和物理page的映射是固定的,比如逻辑的page1对应物理的page1,逻辑的page2对应物理的page2),如下图所示:

LBA和PBA的映射

LBA和PBA的映射

block-to-block的映射,好处是维护的映射关系较少,节省了存储空间,缺点是在数据更新的时候比较麻烦,如下图所示:

  1. 步骤1展示的是初始状态,FTL的映射指向Original block
  2. 步骤2想要更新前两个page的数据:先将新数据写入新的的block(注意:page在block中的相对位置保持不变),原来block中对应的page被标记为无效
  3. 步骤3把原来block中下面的两个page搬移到新的block中(注意:page在block中的相对位置保持不变)
  4. 步骤4更新FTL映射关系,指向新的block,然后擦除原来的block(具体什么时候擦除,由Flash内部的垃圾回收机制决定)

部分page更新

部分page更新

block-to-block方式的映射,在数据更新的时候产生了额外的数据拷贝,需要付出的代价较高。为了解决这个问题,FAST、BAST等算法应运而生。

可以看到,无论是page-to-page的映射还是block-to-block的映射,虽然Flash内部的映射关系发生了变化,但是该变化对文件系统是透明的,因为FTL的映射表对外并未发生变化。

磨损均衡

每个block的最大擦写次数(P/E Cycles)基本上是一样的,磨损均衡(Wear Levelling)的作用是保证所有block被擦写的次数基本相同。这就要求磨损均衡算法要把擦写操作均摊在所有的block上。

如果所有block上的数据都经常更新,磨损均衡算法执行起来问题不大。如果有些block上存在冷数据(写入之后就很少更改的数据),我们必须根据一定的策略强制搬移这些数据并擦写对应的block,否则这些block就永远不会被擦除。当然这种操作会增加系统负载,同时也加大了整个系统的磨损(产生了不必要的擦写)。

实际上,磨损均衡算法越激进,系统的磨损越严重;但是如果磨损均衡算法太消极,会导致两极分化,部分block被擦除次数较多,部分block被擦除次数较少。

垃圾回收

接下来我们需要处理page的回收问题(Garbage Collection)。Flash的擦除单元是block,这决定了垃圾回收的最小单元也是block。block回收过程中,需要确保待擦除block上无有效数据;如果有的话,需要搬移到其他的block(和磨损均衡一样,这也会增加额外的负担,实际应用中需要找到一个平衡点)。

为什么需要垃圾回收

我们假设一个简单的存储介质只包含5个block,每个block包含10个page。在初始化状态,所有的page都是空的,存储介质的可用空间是100%。

初始化状态

初始化状态

接下来写入一些数据(注意:写入的最小单元是page)。从下图可以看出,有些page已经被占用了,并且由于磨损均衡算法的作用,他们被分散在不同的block上:

写入数据

写入数据

我们再继续写入一些数据,现在50%的空间被占用了,并且数据分散在各个block上(尽管在物理层面数据是分散在各个block的,FTL对外展现的可能是连续的):

继续写入数据

继续写入数据

如果这时更新数据,FTL会选择一个空的page写入新数据,然后把老的page标记为stale状态(黄色标记块),如下图所示:

更新数据

更新数据

这时最左边的block包含2个stale状态的page和4个used状态的page,为了回收stale状态的page,必须先把4个used状态的page拷贝到其他的block,然后再把最左边的block整个擦除掉。如果此时不执行该操作,继续写入新数据(或者更新现有数据),会耗尽所有free状态的page,尽管此时还存在stale状态的page,但是已经无法回收了(有效数据没法腾挪了),这时候整个存储介质会进入只读状态。

所以,Flash的FTL层需要执行垃圾回收策略,释放stale状态的page。

写放大因子

从上面的介绍我们了解到,磨损均衡和垃圾回收在一定程度上都会触发后台数据搬运。这些操作是在Flash内部进行的,外部通过任何方法都监控不到,外部唯一能感受到的就是性能受到影响,比如某次写很耗时。

这种现象叫做写放大(Write Amplification),可以通过下面的公式衡量。该值越大说明效率越低,会对存储介质的性能和寿命造成不良影响:

写放大因子定义

写放大因子定义

公式的分子是实际写入到Flash的数据量,分母是有效数据量。比如一次写入5KB数据,但是由于磨损均衡或者垃圾回收导致后台产生了数据搬运,实际写入数据量是10KB,那么,写放大因子就是2。

预留空间

一般情况下,存储介质的实际存储空间都大于标称空间(一般多7%左右,具体依赖生产商),多出来的存储空间被称为预留空间(Over-Provisioning),这部分空间用户是无法使用的。它可以被用来进行数据腾挪,保证垃圾回收、擦写均衡的正常进行,如果有坏块产生,还可以作为替补block顶上去(在一定程度上,让用户感知不到坏块的存在)。

预留空间

预留空间

四、参考资料

  1. https://pdfs.semanticscholar.org/faf8/22b0712731a32a10988e4ee3b3602bec5dd9.pdf
  2. https://flashdba.com/storage-for-dbas/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/115653.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【原创】H3C路由器OSPF测试

网络拓扑图 路由器配置: 路由器1上接了4跟线,分别为这四个接口配置IP地址。 # interface GigabitEthernet0/0/0port link-mode routecombo enable copperip address 2.1.1.2 255.255.255.0 # interface GigabitEthernet0/0/1port link-mode routecombo…

【UI 设计】触摸界面设计

触摸界面设计是一种以触摸操作为主的用户界面设计。以下是一些触摸界面设计的要点: 界面布局:设计简洁、直观的界面布局,使用户可以快速找到所需的功能和信息。避免过于拥挤的布局,保持按钮和菜单的大小适中,以便用户能…

Android DataBinding 基础入门(学习记录)

目录 一、DataBinding简介二、findViewById 和 DataBinding 原理及优缺点1. findViewById的优缺点2. DataBinding的优缺点 三、Android mvvm 之 databinding 原理1. 简介和三个主要的实体DataViewViewDataBinding 2.三个功能2.1. rebind 行为2.2 observe data 行为2.3 observe …

MacOS 为指定应用添加指定权限(浏览器无法使用摄像头、麦克风终极解决方案)

起因:需要浏览器在线做一些测评,但我的 Chrome 没有摄像头/麦克风权限,并且在设置中是没有手动添加按钮的。 我尝试了重装软件,更新系统(上面的 13.5 就是这么来的,我本来都半年懒得更新系统了&#xff09…

开始MySQL之路——MySQL存储引擎概念

一、存储引擎概念 MySQL数据库和大多数的数据库不同, MySQL数据库中有一个存储引擎的概念, 针对不同的存储需求可以选择最优的存储引擎。 ​ 存储引擎就是存储数据,建立索引,更新查询数据等等技术的实现方式 。存储引擎是基于表的,而不是基…

error: ‘std::_hypot‘ has not been declared using std::hypot;

Cmake 使用qt的编译器 编译opencv时 执行mingw32-make时出现了错误 本质原因就是 _hypot 没有声明。所以找到对应的文件声明一下 就行了。 E:\*****\Qt5.14.1\Tools\mingw730_64\lib\gcc\x86_64-w64-mingw32\7.3.0\include\c 下面的math.h 文件。 可以看到这个文件有一个…

二、C#—第一个c#程序(2)

🌻🌻 目录 一、编写第一个C#程序1.1 使用Visual Studio创建c#程序的步骤1.2 编写第一个程序“Hello Word”1.3 c#程序的基本结构1.3.1 c#中的命名空间1.3.2 c#中的类1.3.3 c#中的程序启动器——Main方法1.3.4 c#中的标识符1.3.5 c#中的关键字1.3.6 c#中的…

Yjs + Quill 实现文档多人协同编辑器开发(基础+实战)

前言 多人协同开发确实是比较难的知识点,在技术实现上有一定挑战,但随着各种技术库的发展,目前已经有了比较成熟的解决方案。今介绍 Yjs 基于CRDT算法,用于构建自动同步的协作应用程序,与Quill富文本编辑器&#xff0c…

海康机器人工业相机 Win10+Qt+Cmake 开发环境搭建

文章目录 一. Qt搭建海康机器人工业相机开发环境 一. Qt搭建海康机器人工业相机开发环境 参考这个链接安装好MVS客户端 Qt新建一个c项目 cmakeList中添加海康机器人的库,如下: cmake_minimum_required(VERSION 3.5)project(HIKRobotCameraTest LANG…

OPENCV实现暴力特征匹配

# -*- coding:utf-8 -*- """ 作者:794919561 日期:2023/9/1 """ import cv2 import numpy as np# 读

iPhone 14四款机型电池容量详细参数揭秘

苹果推出的iPhone 14系列与2021系列的设计和外形尺寸相同(仅缩小了几分之一毫米),所以这并不奇怪,但电池容量也大致相同。 虽然可能不足以对电池寿命产生可衡量的影响,但也存在微小的差异。不同的是,现在有…

GreenPlum的gpfdist使用与原理流程分析

一、简介 GreenPlum 的数据导入功能作为对数据源的一种扩充,数据导入的方式有: 1、insert 该方式通过 sql 语句,把数据一条一条插入至表中。这种方式,不仅读取数据慢(一条一条读取),且数据需要…

【局部活动轮廓】使用水平集方法实现局部活动轮廓方法研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

uni-app:允许字符间能自动换行(英文字符、数字等)

<template><view class"container"><!-- 这里是你的文本内容 -->{{ multilineText }}</view> </template><style> .container {word-break: break-all; } </style>例如&#xff1a; <template><view class"…

三、定长内存池

三、定长内存池 我们知道申请内存使用的是malloc&#xff0c;malloc其实就是一个通用的大众货&#xff0c;什么场景下都可以使用&#xff0c;而什么场景下都可以用就意味着什么场景下都不会有很高的性能&#xff0c;下面我们就先来设计一个定长内存池作为一个开胃菜&#xff0…

华为云服务

【计算】 【存储】 对象存储服务 OBS 对象存储服务&#xff08;Object Storage Service&#xff0c;OBS&#xff09;是一个基于对象的海量存储服务&#xff0c;为客户提供海量、安全、高可靠、低成本的数据存储能力。 OBS系统和单个桶都没有总数据容量和对象/文件数量的限制…

【爬虫】实验项目二:模拟登录和数据持久化

目录 一、实验目的 二、实验预习提示 三、实验内容 实验要求 基本要求&#xff1a; 改进要求A&#xff1a; 改进要求B&#xff1a; 四、实验过程 基本要求&#xff1a; 源码如下&#xff1a; 改进要求A: 源码如下&#xff1a; 改进要求B&#xff1a; 源码如下&…

【日积月累】后端刷题日志

刷题日志 说说对Java的理解JAVA中抽象类和接口之间的区别Java中的泛型 和equals()的区别八种基本数据类型与他们的包装类在一个静态方法内调用一个非静态成员为什么是非法的静态方法与实例方法有何不同重载与重写深拷贝浅拷贝面向过程与面向对象成员变量与局部变量Spring框架Sp…

Linux环境变量

文章目录 &#x1f950;1. 认识环境变量&#x1f956;1.1 PATH&#x1f956;1.2 HOME&#x1f956;1.3 查看环境变量 &#x1f96f;2. 什么是环境变量&#x1f356;3. 命令行参数&#x1f354;4. 本地变量 && 内建命令 &#x1f950;1. 认识环境变量 如果学过JAVA、My…

MySQL binlog的几种日志录入格式以及区别

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌&#xff0c;CSDN博客专家&#xff0c;阿里云社区专家博主&#xff0c;2023年6月CSDN上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师…