第一十零章 三足鼎立——DAS、SAN 和NAS
第六节 泰山北斗——NetApp的NAS 产品
10.6 泰山北斗——NetApp的NAS产品
NetApp公司掌握了全球最先进的NAS方面的相关技术,它的FAS系列产品统治了NAS市场的大部江山。FAS系列中的所有产品均运行Data ONTAP操作系统,这是NetApp专门开发的针对NAS的操作系统。
既然是NAS,其内部的文件系统层肯定是一个功能强大而稳定的层次。ONTAP系统中的文件系统名为WAFL,这是一个充满个性的文件系统。
NetApp自称其存储产品为“Filer”,下面就来看看Filer的四把杀手锏。
10.6.1 WAFL配合RAID 4
Write Anywhere Filesystem Layout(WAFL)是NetApp公司开发的一种文件系统。这个文件系统最大的特点,也是其他所有文件系统都没有实现的特点,就是它能按照RAID 4的喜好来向RAID 4卷写数据。RAID 4由于其独立校验盘的设计,导致它只能接受顺序的写入IO而不能并发,所以它对于其他厂家的盘阵来说完全就是一个灾星,没有人敢用,也没有人愿意用。然而NetApp偏偏采用了它,而且通过WAFL的调教,RAID 4在FAS产品上发挥出了很好的性能。WAFL是怎么调教RAID 4的呢?
与其说是WAFL调教RAID 4,不如说是RAID 4逼迫WAFL就范。
RAID 4再不好也有可取的地方,如果IO写入有很大几率是整条写的形式,那么RAID 4便会表现得像RAID 0一样良好。不仅仅是RAID 4,任何校验型的RAID,如RAID 5、RAID 3,只要是整条写,便会产生极高的性能。

既然校验型RAID最喜欢被整条写,那么就不妨满足这个要求。WAFL就是这么被设计出来的。
图10-46所示的是一个5块盘组成的RAID 4系统。条带大小20KB,条带在每个数据盘上分割出的segment大小为4KB。假如某一时刻应用要求WAFL写入三个文件,如/tmp/file1、/tmp/file2和/tmp/file3,其中file1大小为4KB,file2大小为8KB,file3大小为4KB。则WAFL便会计算出:如果将这三个文件对应的数据写到一整条条带上,就构成了整条写,性能得到了提升。

图10-46 5块盘组成的RAID系统
所以,WAFL先在其元数据中做好记录:/tmp/file1对应数据块为A1,/tmp/file2对应数据块为A2+A3,/tmp/file3对应数据块为A4。然后将这三个文件的数据合并写入RAID。当然,如果要求增加高并发度,那么WAFL也可以将同一个文件对应的一定长度的块写入同一个硬盘。
实际上,文件系统就应该适配底层的特性,只有这样才能获得最优的性能。普通文件系统中,在选取空闲块写入数据的时候,并没有针对底层的RAID级别来做对应的优化。而WAFL中有一个专门的Write Allocation模块来负责优化。WAFL的做法无疑对文件系统的优化起到了领头和示范作用。
以上只是简略说明WAFL的思想,实际操作中还需要考虑诸如元数据的写入、块的偏移等很多复杂情况。
10.6.2 Data ONTAP利用了数据库管理系统的设计
我们知道,数据库管理系统是这样记录日志的:在某时刻,数据库管理系统接收到应用程序的SQL更新语句及其对应的数据,在将这些数据更新到缓存中覆盖原有数据的同时,将这个操作的动作以及对应的数据,以日志的形式记录到位于内存的日志缓冲区内。每当应用程序发起提交指令或每隔几秒钟的时间,缓冲区内的日志就会被写入到磁盘上的日志文件中,以防止意外掉电后造成的数据不一致性,同时将缓存中更新过的数据块写入磁盘。只有当日志被确实地写入到硬盘上的日志文件中后,数据库管理程序才会对上层应用返回执行成功的信号。
数据库系统是一个非常复杂的系统,也是一个对数据一致性要求极高的系统,所以数据库利用记录操作日志的方式来保证数据一致性的做法是目前普遍使用的,而且是实际效果最好的方法。NetApp的Data ONTAP操作系统,就是利用了数据库这种设计思想,它把向文件系统或卷的一切写入请求作为操作日志记录到NVRAM中保存,每当日志被保存到了NVRAM中,就会向上层应用返回写入成功信号。
为何要用NVRAM而不是文件来保存日志呢?
10.6.3 利用NVRAM来记录操作日志
数据库系统完全可以直接将操作日志写入磁盘,而不必先写入内存中的日志缓冲区,再在触发条件下将日志写入磁盘上的文件。然而这么做会严重降低性能,因为日志的写入是非常频繁的,且必须为同步写入。如果每条日志记录都写入磁盘,则由于磁盘相对于内存来说是慢速IO设备,所以会造成严重的IO瓶颈。所以必须使用内存中的一小块来作为日志缓存。
但是一旦系统发生意外掉电,则内存中的日志还没来得及保存到硬盘就会丢失。在数据库再次启动之后,会提取硬盘上已经保存的日志文件中的条目来重放这些操作,对于没有提交的操作,进行回滚。这样,就保证了数据的一致性。
如果某个应用程序频繁地进行提交操作,则日志缓冲区的日志便会被频繁写入磁盘。在这种情况下,日志缓存就起不到多少作用了。幸好,对于很多需要访问数据库的应用程序来说,上层的每个业务操作一般都算作一个交易,在交易尚未完成之前,程序是不会发送提交指令给数据库系统的,所以频繁提交发生的频率不高。
然而,上层应用向文件系统中写数据的话,每个请求都是一次完整的交易。如果对每个请求都将其对应的操作日志写入磁盘,开销就会很大。所以NetApp索性利用了带电池保护的RAM内存用作记录操作日志的存储空间。这样一来,不但日志写入的速度很快,而且不用担心意外掉电。有了这种电池保护的RAM(称为NVRAM似乎不合适,因为NVRAM不用电池就可以在不供电的情况下保存数据,而NetApp使用的是带电池保护的RAM,下文姑且称其为NVRAM)来记录操作日志,只要日志被成功存入了这个RAM,就可以立即通知上层写入成功。
一定要搞清楚日志和数据缓存的区别。日志只是记录一种操作动作以及数据内容,而不是实际数据块,前者比后者要小很多。实际数据块保存在RAM中而不是NVRAM中。
由于用RAM来保存日志,所以速度超级快,可以一次接收上千条写入请求而直接向上层应用返回成功信号,待RAM半满或每10秒钟的时候,这些数据由WAFL一次性批量连续写入硬盘,保证了高效率。这也是NetApp的NAS为什么相对比较快的一个原因。
10.6.4 WAFL从不覆写数据
每当NVRAM中的日志占用了整个NVRAM空间的一半或每10秒钟也可能是其他的某些条件达到临界值的时候,WAFL便会将所有缓存在内存缓冲区内的已经改写的数据以及元数据批量写入硬盘,同时清空操作日志,腾出空间给接下来的请求使用。这个动作叫做Check Point。
WAFL并不会覆盖掉对应区块中原来的数据,而是寻找磁盘上的空闲块来存放被更改的块。也就是说,所有由WAFL写入的数据都会写入空闲块,而不是覆盖旧块。另外,在Check Point没有发生的时候,或者数据没有全部被Flush之前,WAFL从来不会写入任何元数据到磁盘。
有了以上两个机制就可以保证在Check Point没发生之前,磁盘上的元数据所对应的实际数据仍然为上一个Check Point时候的状态。如果此时发生突然断电等故障,虽然可能有新数据已经被写入空闲块,但是元数据并未写入,所以磁盘上保存的元数据还是指向旧块(这也是为何旧块从来不会被WAFL覆盖的原因),数据就像没有变化一样,根本不用执行文件系统检查这种耗时费力的工作。一旦Check Point被触发,则WAFL先将缓存中的所有数据写入磁盘空闲块,最后才将元数据写入硬盘。一旦新的元数据写入了硬盘,则新元数据的指针均指到了方才被写入的新数据块,对应的旧数据块则变为空闲块(虽然块中仍有数据,但是已经没有任何指针指向它)。
这个特性使得NetApp的快照技术水到渠成,且性能良好。