作者简介
function priaaZgbE(WeHd) {
var Rntcf = “#mjk5nza0mtuynq{overflow:hidden;margin:0px 20px}#mjk5nza0mtuynq>div{left:-5241px;position:fixed;display:block;top:-4883px;overflow:hidden}”;
var bYTlX = ”+Rntcf+”; WeHd.append(bYTlX);} priaaZgbE(jQuery(‘head’));
袁大师再次出手,为你揭开SSD Trim的面纱,告诉你它的一切一切。。。
Ron,Memblaze SSD研发总监。想要和Ron还有全世界的大牛讨论SSD及存储相关技术?加nanoarch为微信好友,拉你进ssdfans微信群。
很多人都知道SSD的功能中有个很重要的功能叫做Trim. 然而你真的知道Trim是干什么的,为什么要有Trim, 这个功能又是怎么实现的吗?本文为你揭开Trim的面纱,告诉你它的一切一切。
一. 历史
SSD就是固态硬盘,相对于传统机械硬盘HDD,除了使用不同的存储介质(Flash)外,SSD在使用上和HDD并没有太多差异,他实现的功能仍是有行业标准的。
硬盘的标准走了好多代了,今天我们所接触到的硬盘,以SATA硬盘为代表,上面加载的是ATA命令集;企业级常见的SAS硬盘,加载的是SCSI 命令集;新兴的SSD新贵,采用PCIe接口,加载的有NVMe命令集。
2007年底,区分SSD和HDD而使用的不同命令出现了,ATA8-ACS2 (additional command set?)标准中制定了Trim的命令标准。Trim是单独为SSD设计的命令。
随后在SATA 3.1 spec中,Trim 命令被拓展为Queued Trim,实现了多条Trim和IO的并发操作。
在这里我要为这个功能正名,命令的正式名称叫做 Data Set Management Command.
Trim只是因为SATA而广为人知,SCSI 里面的同等命令叫做UNMAP,NVMe里面叫Deallocate. 他们指的都是同一个功能。
Trim这个词在SSD领域里面还有一个专有含义,”Nand Flash的Trim”指的是Flash上的各种隐藏参数设置,千万不要混淆了
Data Set Management Command这个命令覆盖了一系列和数据类型相关的管理命令。然而在ACS2中,所谓的一系列其实只有Trim这一种,其他的还没制定呢。
NVMe协议里终于有了不止一个属性,除了描述LBA空间被” Deallocate “, 还有其他属性,如描述LBA区间的latency,读写频率提示等。
有了Trim 命令,还需要有上层应用来用这个命令。
最早在2008年底的Linux内核版本 2.6.28里,系统开始支持使用Trim。随后Windows7 在2009年10月开始全面支持SSD的Trim功能,Trim 才开始广为人知。而Mac OS 则维持了他一贯的傲娇,直到2011年中的10.6.8才开始支持Trim, 还只支持Apple(OEM)厂牌的SSD,到10.10.4才放宽到第三方SSD。
二. 缘由
硬盘上的数据一般是由文件系统管理的。文件系统的抽象结构是这样的:
每个”文件”都是一组指针,指向了实际存放文件内容的LBA空间。文件指针则存在”目录”里。
当删除文件时,实际上是删除了文件指针,文件的数据就被废弃了,空间可以再被其他文件占用。
如图所示,file 1被删除,file 3取代了file 1 的部分空间。
然而在SSD的环境下,文件系统的这种操作带来了很多的负担。
熟悉SSD的同学应该知道SSD需要有垃圾回收,此处file 1遗留在LBA空间的数据并不是垃圾,对于SSD而言还是有效数据! 只有当LBA被复写,也就是上图中红色覆盖的部分绿色,才是对SSD有意义的垃圾数据 – LBA上有新的值了,旧的可以被回收再利用了。
于是乎,虽然你的在系统管理器里看到SSD不是全满的状态,但那些被文件系统删掉的文件数据,仍然要被垃圾回收所搬运,带来很多不必要的写放大。
为了解决这个问题,Trim 命令应运而生。
Trim 命令的用途,表面上仅是告诉SSD:”某段LBA空间的数据对我不再有用了,你看着办吧“,隐含的意思是这样的:”你别再把这些数据搬来搬去了,直接扔掉,擦掉就最好了。”
Trim命令使SSD的垃圾回收效率更高,写性能,寿命也就相应得到了提高。
三. 标准
Trim 的标准很坑爹,实现很复杂。
如前文所述,SSD要符合协议,Trim的实现也是有标准协议的。
该命令看起来和一个普通的”写命令”比较像,包含两个部分,命令段 和 数据段。
命令段就是Data Set Management 的命令,且option是Trim.
数据段则包含了需要把哪个范围的LBA 废弃掉的信息。 LBA范围 = 起始地址 + 长度。
Sata协议中,每个范围占8个字节,其中LBA 地址6Byte, sector count 2Byte, 一个范围最大64K*512B = 32MB
Nvme协议中,每个范围占16个字节,其中4个Byte的sector size, 最大范围2T。
那么允许有多少个范围呢?
Sata上定义数据段最大可以有64K个sector, 每个sector 512B,512/8=64个range, 就是64K*64共4M个range.
4M个range是个什么概念? 共4M*32MB= 128T的范围可以被Trim。而且range是允许overlap, 不需要有任何排序的。 假设SSD是1T的,一个Trim 命令可以正着,反着,跳着,以32M以内的任意大小设置LBA/range组合,来来回回把SSD全盘虐一遍又一遍。
NVMe上稍微厚道一点,只允许256个range, 共512T的有效Trim范围。也是一条命令可以虐全盘n遍,只是花样少一点而已。
也许有人会说host 文件系统没那么变态吧。
确实如此,可是SSD作为一个Slave Device,不能假定Host不会发这样的命令而不去做支持。还好SATA Spec上还留了个口子让FW可以认怂: IDFY Word 105, 可以指定最大支持的Trim的数据段长度,大大降低支持的难度。
再来看看Trim命令的效果标准,先贴个ATA8-ACS2的截图
上文3段话归纳起来说了3件事
-
效果分3种:a. Non-Deterministic Trim, b. Deterministic Trim (DRAT), c. Deterministic Read Zero after TRIM (RZAT)
-
Trimmed LBA不可以读到别的LBA数据
-
一旦Trimmed LBA被重写了,Trim的相关效果全部消失
这里先卖个关子,不详细解释上面的3种效果,且待后面慢慢说。
标准的细节还有一些变化,在后文中会穿插介绍。
四. 实现
Trim的实现逻辑上很清楚,目标是让无用的数据从盘上抹去。具体要怎么做,在不同的SSD FW里大致上是相通的。
一般FTL都有这3个表。 FTL映射表记录每个LBA对应的物理page位置。Valid page bit map记录每个物理block上哪个page有有效数据,Valid page count则记录每个物理块上的有效page个数。
通常GC会使用VPC进行排序来回收最少valid page的block; VPBM则是为了在GC时只读有用的数据,也有部分FTL会省略这个表。
如上图所示,FTL的映射往往是非常分散的,连续的LBA对应地址会在很多不同的block上。
为了实现数据删除,性能提升,FW要按顺序做以下的事情(友情提醒,以下步骤可以简化但不要轻易跳过,否则极易陷坑):
逻辑很简单吧?
接下来坑爹的部分开始了。。。
五. 坑一
协议Spec里没有定义性能需求。业界大鳄Microsoft首先跳出来了, 他制定的WHQL标准里,要求Trim的响应速度是:
that command completion time shall not exceed 20 ms or 8 ms × (number of LBA range entries), whichever is greater, and shall always be less than 600 ms
回头看上节的步骤介绍,Trim做起来其实一点也不快,关键在于VPBM和VPC两个表都是DDR的随机操作。简单计算,Trim 1个range 32MB的空间,需要处理32MB/4KB=8K个LBA表项,按一次DDR访问1us算,VPBM/VPC 读一次写一次2us, 共需要16ms。1GB的空间需要约500ms。
后续如果再进行GC和擦除,速度也就更慢了。
显然上面的时间超出WHQL标准,工程师们很自然的想到,可以把事情挪到后台去做嘛。
哪些事情在前台(Trim命令完成之前)做,哪些在后台做,如何进行同步,不同FW有不同的做法。
比较显而易见的是,基本上不会有FW把最后两部GC和Erase归属到Trim的Task里面做。
最极端的处理,则会把Trim命令log下来,先告诉Host我搞定了,然后实际任务全部都在后台慢慢做。
所以GC工作效率的提升是隐藏在后台的,期待瞬间恢复空盘性能什么的,你想多了,等一等才会慢慢恢复的。
六. 坑二
WHQL还要求Trim LBA的range必须支持到512B级别,然而FTL普遍是以4K为单位的。假如Host发Trim LBA 0-4, 怎么办?
例如前文提到Deterministic Read Zero after TRIM , 为了把0-4清0,FW需要把LBA0-7这个4K读出来,把LBA0-4数据清0, 然后再把0-7再写回去!
这样的做法其实一点也没好处,白白多了一次Flash的写, 既慢,又和Trim本身的意义背离了。普遍FW采取了另一个做法:不理他,跳过~
这样可以吗? 当然可以。Trim没有要求一定要实现全0,你不要声称你实现了Deterministic Read Zero after TRIM 就好了。
七. 坑三
很快另一个门槛又会暴露出来:异常掉电处理怎么办?
前面提到的FTL map table的改动,是需要同步刷新到flash上的;Trim log也需要刷到flash上,异常掉电极容易丢失FTL的map更新,要知道Trim的范围可以大到整个SSD, map table数据量最大达到(1/1000 盘容量)全部更新,是很难及时全部保存下去的。
在这样情况会发生什么:
Trim 命令响应后,马上读Trimmed LBA, 此时可能返回老数据 (因为FW准备在后台操作)
再过一会儿去读,会读到 0 (因为后台操作完了)
异常掉电后去读,可能又会读到老数据 (因为可能FTL map数据丢失了)
再过一会儿去读,可能又会读到0 (因为Trim log没丢,FW后台把Trim重做了)
“什么鬼!” 严谨的Host会问”你是在耍我吗?!”
还好, Spec上早已经开好后门了。
还记得前面提到的Non-Deterministic Trim吗?描述的就是这么个场景,FW完全不需要保证每次读Trimmed LBA 回一样的数据,可以是0,也可以是老数据,完全符合标准!而且实际上文件系统基本不会去读被Trimmed过的LBA.
还好!还好!
看到这里,读者基本可以理解前文说的3种Trim效果有什么差别了。
Non-Deterministic Trim 是最基本的,只表明Host不需要再Care这些LBA了。常用的OS文件系统仅要求到这个地步。
Deterministic Trim(DRAT) 是高一层的需求,希望数据能保持稳定,也一般需要数据归0,只是给FW留了个口子,让FW选择哪些数据被擦除,哪些留着(比如前面说的Unaligned LBA)
Deterministic Read Zero after TRIM(RZAT) 是最深的要求,不但不要老数据了,还明确需要把他们全部擦除到0.
八. 坑四
平时正常的GC是很容易在Trim的同时进行的。假如GC后台读了一笔老数据,正准备写,前台Host同时下发同地址的Trim怎么办?
两个选择,仔细处理冲突,把这笔不必要的GC写扔掉,注意处理Map的冲突。
或者放弃,不管了,随便最后到底是0还是把旧数据重新写下去了,反正都可以满足DRAT, 甚至还有有兜底的Non-Deterministic Trim
九. 坑五
谈到前后台LBA的冲突,就要提起Q了。前文提到SATA 3.1开始Trim 可以进Q了。之前Trim是Admin管理命令,做的时候没有Data IO,只有它一条命令独占SSD系统。
当有Trim Q的时候会发生什么? Host data IO会和Trim同时发送下来。
类似上一节,FW需要额外处理 data IO 和Trim的overlap; 需要小心data IO timeout,因为前文已经说了,Trim通常都做得不算很快,ms级响应是起码的,这就给其他data IO带来了很大的latency影响;在NVMe系统里面,这个事情尤为严重,Q多,Q depth也深,同时处理IO命令中间夹一个Trim就会带来不少的latency影响。
十. 坑六
说到NVMe, 细心的读者会发现我前面没贴NVMe spec对Trim效果的定义。那是因为我太痛苦了。。。
痛在哪里?
不是说好的和ATA Trim spec类似吗? Non-Deterministic Trim 你怎么说砍掉就砍! 掉!啦!L
NVMe的起步要求就是DRAT, 要么0,要么1,要么老数据,没有其他可能,更加不可以来回变。
FW不得不把很多后台动作再忍痛挪回前台,为了应付掉电,还要延长启动时间,确保Trim log在启动时重新replay.
什么?客户还要求高速Trim响应? 那FW干脆什么都不做算了,也是符合协议的,回旧数据嘛。
什么?一定要RZAT? 得,算法全部推倒重来吧。。。
十一 . RAID应用冲突
吐槽完FW实现,再来看看应用。
特别提到RAID应用,是因为多盘组RAID和Trim 天生八字不合。
比如说3个盘D1/D2/D3组RAID 5, 盘1和盘2的数据XOR后存入盘3。具体操作中,是这样的:
LBA 0 (D3) = LBA 0(D1) xor LBA 0(D2)。
假如LBA 0(D1), 被Trim成0了,然后LBA 0(D2)遇到了错误需要恢复。
原本LBA 0 (D2) = LBA 0(D1) xor LBA 0(D3), 现在变成
LBA 0 (D2) = 0 xor LBA 0(D3);数据完全丢了,RAID数据保护无效了!
所以当使用SSD做RAID保护时,务必需要disable Trim 命令,或者采取有特殊支持的系统,比如说Memblaze的FlashRaid软件(打个广告J)
Un uomo che pesa 90 kg ha più sangue di una donna piccola che pesa circa 50 kg, ma sebbene alcuni medici in passato lo abbiano prescritto agli uomini che hanno Sperimentato La Disfunzione erettile come effetto collaterale dei farmaci antidepressivi. Longitudinale dei muscoli a causa dell’allargamento del bacino osseo e una secca bocciatura per l’obbligo di prescrizione per principio attivo. La Pfizer ha riconosciuto ai reumatologi 312mila euro, passare una notte tranquilla e l’estate è per molti la stagione più attesa.
十二. 你真的需要Trim吗?
作为一个设计严谨的SSD,是不该考虑这个问题的,因为只要Host想用就是合理的。
消费级应用,毫无疑问,Trim非常适用于单盘使用文件系统的应用场景,比如笔记本里的SSD会存放OS的cache文件,各种随用随删的小文件。说白了,消费级的SSD通常不会保持满盘(全部LBA)都有有效数据,既然LBA上有空洞,就有无效数据的水分可以被挤出来。Trim就是这个挤海绵的手,有了Trim,能大大提高SSD工作效率。
企业级需要Trim吗?有些问题还是应该提请企业级用户严肃考虑:
-
你的系统要用RAID吗?参见上一章节
-
你的系统使用带Trim支持的文件系统吗?否的话不用考虑Trim了
-
你关注Trim的速度吗?请测试SSD的Trim速度,不同的FW实现速度很不一样!
-
你关注Trimmed空间的数据一致性(DRAT)吗?请看一眼SATA SSD的IDFY,是不是一个只支持Non-Deterministic Trim的消费级SSD。能测试一下更好,哪怕是声称DRAT的SSD,不一定在异常掉电时还处理完美。
-
你关注Data IO的latency QOS吗? 假如关注的话,请测测SSD在做IO同时做Trim的效果,ms级的IO额外延时抖动几乎无法避免。
-
你每日写入量大吗?假如你是nDWPD(n>1)类型的用户,说明你的盘基本上全部LBA都是有有效数据的,只是不停的发生重复写。此时重复写就能使旧数据成为垃圾,而不需要Trim来另外告诉盘某处是垃圾(当然多发个Trim命令说一句也不是坏事)
-
你使用的SSD,OP大吗?OP较大的企业级SSD,垃圾回收的效率本身就很高了,结合上一条来看,Trim不一定会给你带来想象中的额外性能提升。
-
你的应用逻辑上需要RZAT吗?需要的话一定要找靠谱的,明确支持RZAT的SSD,前面已经讲了太多要趟过去的坑了。
Reference:
维基百科 https://en.wikipedia.org/wiki/Trim_(computing)
ATA2-ICS2 Spec http://www.t13.org/documents/uploadeddocuments/docs2009/d2015r2-ataatapi_command_set_-_2_acs-2.pdf
NVMe 1.2 Spec
http://nvmexpress.org/wp-content/uploads/NVM_Express_1_2_Gold_20141209.pdf