RAID中可以做TRIM操作吗?

不知道大家有没有考虑过这样一个问题:在RAID中是否可以支持TRIM操作?

试想在SSD上建立RAID之后,应用软件(文件系统)直接运行在RAID软件之上,那么此时如何通过TRIM命令将SSD中的数据块unmap掉呢?看起来这好像不是一个问题,其实对于RAID而言这是一个比较大的问题。存储老吴可以带领大家从研发人员的角度一探RAID中TRIM所引入的问题,从中也可以一窥用户所应该注意的问题。

目前,RAID方面的开源软件是MD,很多用户对MD这套软件是非常热衷的。认为这套软件运行非常的稳定,性能不错,功能很全,并且还有很多技术人员对其进行免费开源维护。其实,和专业的RAID存储软件相比,MD就是一个演示系统。目前,在MD软件中是不支持SSD的TRIM操作的,不是说不想加入这个功能,而是并不容易添加这个功能,这会涉及到很多的开发工作量。

对于SSD的TRIM操作,其主要想法是通过释放SSD内部一个逻辑地址(LBA)的映射数据块来提升SSD本身的性能。这主要是由于SSD内部采用FTL的方式对所有写入数据采用Append write(追加写)的方式,所以,当没有空闲资源的时候,SSD需要通过启动垃圾回收来获取空闲资源。垃圾回收对SSD的性能影响巨大,因此,如果业务能够主动释放空闲资源,那么SSD内部的垃圾回收就会轻松很多,从而可以提升SSD本身性能。TRIM操作就是让应用层主动释放空闲资源的机制。

当应用软件直接架构在SSD上时,其可以很容易的向SSD通过发送TRIM命令来回收资源。但是,在应用软件和SSD之间引入RAID之后,情况发生了巨大变化。首先,让我们来认识一下一个普通的RAID数据布局,这个数据布局会显得非常规整:

在这样的数据布局中,每个条带都会存在一个数据校验块(RAID5),一旦条带中的一个数据块发生故障时,通过校验数据P就可以恢复故障数据。假设此时,位于RAID之上的文件系统想要TRIM一个数据块,这个数据块正好落在SSD1的D数据块区域。对于这种操作,RAID需要做什么呢?一个很直观的操作是当RAID把SSD1上的D数据块TRIM掉之后,需要更新这个条带中的P数据块。原因在于TRIM操作之后,SSD1上的D数据块发生了变化,如果想要保证条带数据的一致性,必须更新P数据块。条带中一个数据块的TRIM操作引发了条带校验数据的更新。这是条带RAID中TRIM操作的重要代价。

其实,事实远比条带更新更加糟糕。一个SSD中的数据块被TRIM之后,这个数据块中的数据会变的不确定。例如一个数据块被TRIM之后,读取的数据可能和原来一样,也有可能为零。并且随着时间的变化,存储块TRIM之后的数据会发生变化。而这完全取决于SSD内部固件程序的实现。这种数据的不确定性给RAID带来的致命的数据正确性问题。例如,上述案例中SSD1中的D数据块被TRIM之后,根据TRIM之后的数据更新P校验数据。过一段时间之后SSD1中的D数据块可能发生了变化,此时整个条带的数据将会处于不一致性状态,对数据的正确性造成影响。

从上述分析来看,RAID的数据TRIM最好以条带为单位,当一个条带中的数据全部可以TRIM,那么此时才可以对SSD发送TRIM操作命令。所以,在RAID中,TRIM操作被放大到了条带级别,不再是原来的Sector块级别操作了。

但是,通常RAID设备暴露给用户仍然是Sector级别的块设备对象,文件系统仍然会给RAID发送Sector级别的TRIM操作。对于这种情况,RAID如何将Sector级别的TRIM操作转换成条带级别的TRIM呢?这就需要RAID内部进行TRIM的合并,例如通过采用Bitmap机制将TRIM操作记录下来,当合并到一定程度之后,再对整条带进行TRIM操作。这种设计将会造成较大的实现复杂度,并且还有很多的问题需要考虑,例如Bitmap占用内存容量,异常掉电等问题。所以,一个优秀的RAID数据保护软件,将TRIM问题处理好是需要化一番真功夫的,并不是一件很容易的事情。

(来自存储老吴的博客——存储之道)

时间: 2024-08-25 19:17:16

RAID中可以做TRIM操作吗?的相关文章

Guava学习笔记:guava中对字符串的操作

Guava学习笔记:guava中对字符串的操作 转载:http://outofmemory.cn/java/guava/base/Strings 在google guava中为字符串操作提供了很大的便利,有老牌的判断字符串是否为空字符串或者为null,用指定字符填充字符串,以及拆分合并字符串,字符串匹配的判断等等. 下面我们逐一了解这些操作: 1. 使用com.google.common.base.Strings类的isNullOrEmpty(input)方法判断字符串是否为空        

python 中对list做减法操作

问题描述:假设我有这样两个list,          一个是list1,list1 = [1, 2, 3, 4, 5]          一个是list2,list2 = [1, 4, 5]           我们如何得到一个新的list,list3,          list3中包括所有不在list2中出现的list1中的元素.          即:list3 = list1 - list2          解决方案:我们可以用set(集合)操作          list3 = l

nodejs之利用第3方包,做数据库操作、登录页面验证案例(案例中的动态页面都是基于后端渲染的)

1.先安装第3方包 新建项目文件夹->建入口js文件->npm init 创建包管理文件 package.json ->npm install mysqljs/mysql 2.在项目入口文件来做数据库操作(数据库操作语句,其实可以去npm官网查看这个masql插件的文档) 真实的工作场景中,数据库位于一台单独的服务器上 3.mysql的sql语句的学习   4.封装操作数据库的api 5.登录页面小案例---走通前端+后端+数据库一套流程 原文地址:https://www.cnblogs

Swing中耗时任务需要另起新线程,这个新线程中更新GUI的操作仍需由EDT来做(转)

最近调试程序时发现,点击某个界面时会出现卡死的情况,出现的频率还是比较频繁的. 再次出现卡死的情况后,利用jvisualvm查看线程的运行情况,dump操作之后发现线程间出现了死锁:Found one Java-level deadlock:============================="Thread-122":  waiting to lock monitor 0x484052e4 (object 0x1af2bb08, a com.raisecom.ems.temple

你知道RAID中的Write Hole问题吗?

RAID系统中会存在一个称之为Write Hole的问题,这到底是一个什么问题?会给用户带来什么影响?目前开源RAID系统中如何解决这个问题?这类问题需要采用什么方式来解决呢?存储老吴从研发的角度和大家一起分析一下这个问题,看看这个问题的本质以及解决思路. Write Hole是一种非常形象的描述.对于一个采用条带内部通过校验数据进行数据保护的系统,当应用程序正在更新条带内部数据的时候,如果系统突然断电,条带数据无法正常更新完成,那么此时就会出现条带中的数据部分更新完成.在这种情况下,当系统重启

raid磁盘阵列OFFLINE后如何操作挽救数据

磁盘阵列(Redundant Arrays of Independent Disks,RAID),有"独立磁盘构成的具有冗余能力的阵列"之意.服务器磁盘阵列是由很多价格较便宜的磁盘,组合成一个容量巨大的磁盘组,利用个别磁盘提供数据所产生加成效果提升整个磁盘系统效能.利用这项技术,将数据切割成许多区段,分别存放在各个硬盘上.磁盘阵列还能利用同位检查(Parity Check)的观念,在数组中任意一个硬盘故障时,仍可读出数据,在数据重构时,将数据经计算后重新置入新硬盘中.-------定义

Python中列表list常见操作

主要涉及知识点 列表是我们python里面最常见的数据类型,我们主要有以下的操作. 1.索引 2.切片 3.追加 4.删除 5.长度 6.循环 (也称遍历) 7.包含 8.嵌套 例如定义列表: List2=['openstack','python','linux',"docker","zabbix","nginx","linux","linux","123","ww33##&q

关于有默认值的字段在用EF做插入操作时的思考

今天在用EF做插入操作的时候发现数据库中一个datetime类型的字段(CreateDate)的值居然全部为null.于是赶紧看表结构发现CreateDate字段居然是允许为空的. 虽然为空,但是设置了默认值getdate(),按说不应该为null的.于是开始测试. 字段允许Null值的情况 Users表结构如下: 假如一个字段有了默认值,并且又允许为Null,在做插入操作时会发生什么? 如上图中的表结构,CreateDate是允许为null的,而又有默认值getdate().这样在用传统SQL

javascript中对字符串的操作总结

没听过一句话吗?程序员的世界,不处理字符串就是处理数组.这是群里的一位前辈和我说的,显然这和我之前理解的DOM是javascript的核心的不同的,看了几个面试题的内容,感觉前辈说的话非常的有道理,因此总结下,javascript中对字符串的操作. String类型 首先字符串类型是基本类型,但是在这里我们所说的是字符串的对象包装类型.因为只有引用类型才会有属性和方法.实际上每读取一个基本类型的同时都会创建一个对应的基本包装类型,从而让我们能够调用一些方法来操作数据.1.charAt() 和 c