讀、寫、擦除是SSD對NAND的三大基本操作,但是針對NAND自身的特性和多樣化的I/O模型,SSD怎么讀、寫、擦除是門高級藝術(shù),也由此衍生了很多技術(shù)。
比如垃圾回收(GC),一個(gè)優(yōu)質(zhì)的GC明白在什么時(shí)候,挑選哪些Block,將上面的數(shù)據(jù)搬到哪去。
GC的基本原理
(如上圖)左側(cè)兩個(gè)Block中的有效數(shù)據(jù)被搬移/整合到一個(gè)新的Block,然后這兩個(gè)Block將被擦除,形成兩個(gè)可以寫入數(shù)據(jù)的新Block。
關(guān)于GC的研究,可以看Memblaze金一同學(xué)的這個(gè)文章。
有個(gè)問題,GC怎么才能知道垃圾是垃圾呢?討論這個(gè)問題需要先回到數(shù)據(jù)存儲的過程,開始是這樣的。
當(dāng)有數(shù)據(jù)刪除之后,SSD并不能及時(shí)的知道誰是臟數(shù)據(jù)。形成了這樣的局面
只有操作系統(tǒng)往標(biāo)注DEL的位置上寫數(shù)據(jù)時(shí),盤才知道這是垃圾。
不然這些數(shù)據(jù)將一直被GC認(rèn)為是有效數(shù)據(jù)搬移。為了更高效的執(zhí)行GC,讓操作系統(tǒng)和文件系統(tǒng)高效的和SSD主控交流刪除文件的信息。
就出現(xiàn)了TRIM。
A trim command (known as TRIM in the ATA command set, and UNMAP in the SCSI command set) allows an operating system to inform a solid-state drive (SSD) which blocks of data are no longer considered in use and can be wiped internally.——Wikipediahttps://en.wikipedia.org/wiki/Trim_(computing)
維基百科給的這段介紹,在NVMe SSD上解釋就是,TRIM讓操作系統(tǒng)通過Trim命令(NVMe協(xié)議中有定義)告訴SSD哪些地址上的數(shù)據(jù)可以擦除,從而提升垃圾回收的效率。
Memblaze就是這么干的,
我們總結(jié)了TRIM的三大價(jià)值:
降低寫放大
提升寫性能
提高設(shè)備壽命
對于NVMe來說,Trim是讓GC長了一對翅膀。說著簡單,但是要通過Trim達(dá)到降低寫放大的目標(biāo)而不影響設(shè)備性能,其中NAND無效塊的擦寫時(shí)機(jī)、Tirm和其他一系列SSD核心算法的配合非常有講究。
TRIM實(shí)現(xiàn)難在哪這里就不詳細(xì)討論了,有興趣的可以看Ron寫的文章《SSD Trim 詳解》
NVMe Spec對TRIM命令有詳細(xì)的規(guī)定,所以使NVMe Cli就可以對TRIM功能進(jìn)行驗(yàn)證
接下來就結(jié)合NVMe Spec的規(guī)定,發(fā)出我們的一條TRIM命令,然后做個(gè)驗(yàn)證。
1
準(zhǔn)備設(shè)備和環(huán)境
使用Memblaze官網(wǎng)Pblaze5 910/916系列產(chǎn)品中的4T U.2NVMe進(jìn)行驗(yàn)證測試。
nvme list的信息如下 firmware version:001008R0
寫入數(shù)據(jù):從NVMe 10GiB的位置往后寫10G的數(shù)據(jù),數(shù)據(jù)pattern是0x12345678
[root@localhost~]#fio--thread--direct=1--allow_file_creat=0--ioengine=libaio--rw=write--bs=128k--iodepth=128--numjobs=1--name=nvme0n1--filename=/dev/nvme0n1--offset=10g--size=10g--verify=pattern--do_verify=0--verify_pattern=0x12345678nvme0n1:(g=0):rw=write,bs=(R)128KiB-128KiB,(W)128KiB-128KiB,(T)128KiB-128KiB,ioengine=libaio,iodepth=128fio-3.12Starting1threadJobs:1(f=1):[W(1)][-.-%][w=3165MiB/s][w=25.3kIOPS][eta00m:00s]nvme0n1:(groupid=0,jobs=1):err=0:pid=4787:MonMar415:59:352019write:IOPS=25.2k,BW=3156MiB/s(3309MB/s)(10.0GiB/3245msec)slat(nsec):min=3204,max=81924,avg=9364.20,stdev=2437.54clat(usec):min=1177,max=17333,avg=5058.82,stdev=387.21lat(usec):min=1187,max=17347,avg=5068.25,stdev=387.16clatpercentiles(usec):|1.00th=[4555],5.00th=[5014],10.00th=[5014],20.00th=[5014],|30.00th=[5014],40.00th=[5014],50.00th=[5080],60.00th=[5080],|70.00th=[5080],80.00th=[5080],90.00th=[5080],95.00th=[5080],|99.00th=[5145],99.50th=[6063],99.90th=[11207],99.95th=[13042],|99.99th=[16909]bw(MiB/s):min=3145,max=3166,per=100.00%,avg=3157.17,stdev=7.59,samples=6iops:min=25160,max=25334,avg=25257.33,stdev=60.68,samples=6lat(msec):2=0.11%,4=0.48%,10=99.30%,20=0.11%cpu:usr=3.73%,sys=25.09%,ctx=74895,majf=0,minf=13IOdepths:1=0.1%,2=0.1%,4=0.1%,8=0.1%,16=0.1%,32=0.1%,>=64=99.9%submit:0=0.0%,4=100.0%,8=0.0%,16=0.0%,32=0.0%,64=0.0%,>=64=0.0%complete:0=0.0%,4=100.0%,8=0.0%,16=0.0%,32=0.0%,64=0.0%,>=64=0.1%issuedrwts:total=0,81920,0,0short=0,0,0,0dropped=0,0,0,0latency:target=0,window=0,percentile=100.00%,depth=128Runstatusgroup0(alljobs):WRITE:bw=3156MiB/s(3309MB/s),3156MiB/s-3156MiB/s(3309MB/s-3309MB/s),io=10.0GiB(10.7GB),run=3245-3245msecDiskstats(read/write):nvme0n1:ios=62/79409,merge=0/0,ticks=1/401029,in_queue=401403,util=96.86%[root@localhost~]#
2
依據(jù)NVMe Spec準(zhǔn)備測試文件和命令
使用nvmecli將這10G的數(shù)據(jù)trim掉,利用強(qiáng)大的strace命令跟蹤一下command的耗時(shí),粗略的計(jì)算下Trim的速度。
首先需要按照NVMe Spec協(xié)議中的Dataset Manager設(shè)置(如下圖),創(chuàng)建一個(gè)4096byte的二進(jìn)制文件。一個(gè)range最多trim32bit(0xffffffff*512byte 大約2047GiB)的LBA。
Length in logical blocks和Starting LBA的計(jì)算
10G數(shù)據(jù)按照512byte的format格式得出是:
10*1024*1024*1024/512=20971520個(gè)(LBA)
Fio中offset=10g,因此start LBA也是 :
10*1024*1024*1024/512=20971520
利用python創(chuàng)建二進(jìn)制文件代碼如下(簡單的寫個(gè))
importarraybuf=array.array("B",[0x00]*4096)defsetValue(buf,offset,num,value):#Commonfunctiontosetunsignedintegervaluewithinthegivenrange#offset&numareinbytesforthisfunctionseries.ifnum==1:buf[offset]=valueelse:foriinxrange(num):buf[offset+i]=(value>>(8*i))&0xffreturnbufdefwriteBinaryFile(buf,filepath):withopen(filepath,"wb")asf:buf.tofile(f)#Length in logical blocks :offset=4 num=4 value=20971520buf=setValue(buf,4,4,20971520)#StartingLBAoffset=8num=8value=20971520buf=setValue(buf,8,8,20971520)writeBinaryFile(buf,“/root/trim.bin”)
下面是NVMe Spec里TRIM命令的規(guī)范,使用nvmecli 發(fā)送NVMe command需要照著填寫
Dword11 :二進(jìn)制:0b 0100=0x04
3
準(zhǔn)備工作做足了,接下來就是發(fā)!
發(fā)TRIM時(shí)候,在命令前加上strace –ttt,可以粗略的計(jì)算TRIM的速度。
[root@localhost~]#strace–tttnvmeio-passthru/dev/nvme0--opcode=0x09--namespace-id=1--cdw10=0x00--cdw11=0x04--input-file=trim.bin--data-len=4096–write
我們經(jīng)過計(jì)算得出TRIM耗時(shí)0.00124s,所以Trim的速度大約是:10 /0.00124= 8064.516GiB/s 大約8TB/s
4
TRIM后立即數(shù)據(jù)驗(yàn)證
[root@localhost~]#fio--thread--direct=1--allow_file_creat=0--ioengine=libaio--rw=read--bs=128k--iodepth=128--numjobs=1--name=nvme0n1--filename=/dev/nvme0n1--offset=10g--size=10g--verify=pattern--do_verify=1--verify_pattern=0x00nvme0n1:(g=0):rw=read,bs=(R)128KiB-128KiB,(W)128KiB-128KiB,(T)128KiB-128KiB,ioengine=libaio,iodepth=128fio-3.12Starting1threadJobs:1(f=1):[V(1)][-.-%][r=3176MiB/s][r=25.4kIOPS][eta00m:00s]nvme0n1:(groupid=0,jobs=1):err=0:pid=9241:MonMar421:37:352019read:IOPS=25.4k,BW=3171MiB/s(3325MB/s)(10.0GiB/3229msec)slat(usec):min=9,max=225,avg=11.21,stdev=3.14clat(usec):min=1938,max=11585,avg=5010.57,stdev=1313.65lat(usec):min=1948,max=11595,avg=5021.85,stdev=1313.57clatpercentiles(usec):|1.00th=[2147],5.00th=[2868],10.00th=[3294],20.00th=[3884],|30.00th=[4293],40.00th=[4621],50.00th=[4948],60.00th=[5342],|70.00th=[5735],80.00th=[6194],90.00th=[6783],95.00th=[7242],|99.00th=[8029],99.50th=[8225],99.90th=[8717],99.95th=[9110],|99.99th=[9765]bw(MiB/s):min=3168,max=3176,per=100.00%,avg=3172.88,stdev=3.26,samples=6iops:min=25348,max=25410,avg=25383.00,stdev=26.07,samples=6lat(msec):2=0.47%,4=22.76%,10=76.75%,20=0.01%cpu:usr=45.94%,sys=29.43%,ctx=22554,majf=0,minf=25IOdepths:1=0.1%,2=0.1%,4=0.1%,8=0.1%,16=0.1%,32=0.1%,>=64=99.9%submit:0=0.0%,4=100.0%,8=0.0%,16=0.0%,32=0.0%,64=0.0%,>=64=0.0%complete:0=0.0%,4=100.0%,8=0.0%,16=0.0%,32=0.0%,64=0.0%,>=64=0.1%issuedrwts:total=81920,0,0,0short=0,0,0,0dropped=0,0,0,0latency:target=0,window=0,percentile=100.00%,depth=128Runstatusgroup0(alljobs):READ:bw=3171MiB/s(3325MB/s),3171MiB/s-3171MiB/s(3325MB/s-3325MB/s),io=10.0GiB(10.7GB),run=3229-3229msecDiskstats(read/write):nvme0n1:ios=79930/0,merge=0/0,ticks=394735/0,in_queue=395214,util=96.95%[root@localhost~]#
可以看到加上--verify_pattern=0x00之后,err= 0,證明TRIM后數(shù)據(jù)都變成0了,至于更細(xì)節(jié)的說明,在此不再贅述。
通過一系列的介紹和實(shí)驗(yàn)驗(yàn)證,我們看到了TRIM的價(jià)值和實(shí)現(xiàn)原理。在TRIM的幫助下,NVMe SSD的GC等操作效率更高,進(jìn)而達(dá)到降低寫放大,提高產(chǎn)品性能和壽命的效果。
-
NAND
+關(guān)注
關(guān)注
16文章
1690瀏覽量
136461 -
SSD
+關(guān)注
關(guān)注
21文章
2887瀏覽量
117857 -
數(shù)據(jù)存儲
+關(guān)注
關(guān)注
5文章
983瀏覽量
51058
原文標(biāo)題:TRIM,讓你的SSD再次飛起來
文章出處:【微信號:SSDFans,微信公眾號:SSDFans】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論