大家好,我是五月。
目前绝大数存储设备都是以闪存为存储介质的,内部许多固件算法方案都是在为闪存服务的。
无论是什么算法,都是遵循着Flash的特性为前提的。
那闪存究竟有哪些潜规则的特性呢?
闪存块(Block)是不能覆盖写的,它不允许开发者在一个地方上重复写入,必须先擦除一遍才行。
一般来说,当有一笔数据写入的数据,都是安排写到新的地址空间上,当你实在不清楚一个地址究竟有没有有效数据的时候,稳妥的做法一般都是先擦除一遍再写入。
闪存允许最小的写入单位就是page,最少写入的数据量都得是1个page。
FTL算法中有一个基本操作,会把主机Host传下来的数据凑成1page,再写入Flash中,不足1page的,就放在Dbuf中,等待下一次数据来凑成1page,再写入Flash中。
闪存允许擦除的基本单位是1个Block,只要发生了擦除操作,那么这一整个Block的数据都会被清除掉,所以我们一般不会轻易做整块擦除。
解决办法:当有一笔新数据下来的时候,会把数据放在新的物理地址上,这样做一来是为了不轻易做擦除操作,避免失误擦除掉了有效数据,二来也避免在同一个物理地址上做重复的擦写,过快消耗闪存块寿命。
我们写的时候,如果简单把数据写进去,会遇到很多错误,有时候是写失败,有时候是读出来数据不对。
这是由于闪存存储电子的工作模式导致的,其对数据写入的样式特别敏感,如果不断地写入全0或者全1,容易导致内部电荷量不足,造成信号抗干扰性下降。
直观的现象就是你会发现某些数据bit位发生了翻转。
解决办法:写入数据前需要先将数据做随机化处理,也就是打乱数据,使得0和1的分布均匀。
但是打乱也不是随便打乱的,它会以某种方式进行随机化处理写入flash,读取数据的时候,会先进行一次反随机化处理,得到真实数据。
闪存还有个奇怪的特性,就是数据你必须得写满一整个块,这个块的数据才会稳定下来。
但是很多时候,我们没有那么多数据正正好好去写满一整个Block。
解决办法:为了保证写入数据稳定,我们写入一笔数据后,会额外写入几页数据,目的就是让写入的那笔数据保持稳定,而额外写入的几页数据,称之为附加逻辑页数据。
每一次写和擦,都会对闪存块造成磨损,磨损久了,闪存块也就坏掉了。其寿命是用PE(擦写次数)来衡量的。
在使用中,我们尽量避免集中在同一片区域上重复擦写,不然这片区域的块很快就磨损没了。
解决办法:FTL中需要做一个磨损平衡的处理,让所有的Block都来均摊数据的写入。
将数据分担到其他的Block上,让每一个Block都磨损的平均些,既可以保证闪存有最大数据写入量,还能延长闪存的寿命。
除了有擦写次数限制,闪存块还有读次数的限制,读取的次数多了,数据便会出错,这种现象称之为读干扰现象。
解决办法:FTL算法需要做一个读干扰处理,当某个Block的读次数达到一定的阈值时,就把数据从该Block上搬移到新的Block上。
闪存能存储数据的原理就是电荷的存储,但是电荷是流动不定的,时间一旦久了,电荷就会流失,反映出来的现象就是数据的丢失。
这个时间不好说,长则十多年,短则几年,几个月,甚至更短。
如果是在高温的环境下,电荷流失的速度会更快。
解决办法:FTL算法需要做一个扫描处理,去发现是否有数据保持丢失的问题,如果发现了,立马将数据搬移到新的位置,未雨绸缪。
闪存出现坏块这是无法避免的,有的是出厂的时候就有的坏块,有的是闪存在使用中产生的坏块。
坏块的症状就是擦除失败,或者写失败,或者读失败(ECC纠错纠不过来)。
解决办法:FTL算法需要做一个坏块管理的处理,对坏块打上坏块标记,在使用的时候就不要用这些坏块了,挑好的Block用。
对于MLC,一个worlLine存在Upper page和Lower page;
对于TLC,一个worlLine存在Upper page、Extra page和Lower page;
在写入时,如果发生意外,比如异常掉电这些,Lower page上成功写入的数据会被破坏掉。
解决办法:一个办法是在电路上加上电容,一旦发生异常掉电,让电容开始放电,在这段时间将数据保存起来,并且开启正常掉电流程。
还有一个办法是在FTL算法中需要做一个掉电恢复的处理,通过重建映射表将丢失的数据恢复回来。
一般无论有没有电容,FTL中都会带有一个异常掉电处理模块。
闪存存在这么多的毛病,但是依旧抵挡不住各大存储领域的企业入局去研究其毛病,毕竟,一切方案,都是以特性未前提的,先明白了特性,才能有解决方案。
好了,这次先写到这儿,祝各位生活愉快。