Dark Side of Cloud Storage —— 数据对像的分块消重
数据对像(可以通俗地认为是文件)的分块存储具有久远的历史。长久以来,单机文件系统一直将文件切分为若干固定大小的小块。其主要目的是为了进行有效的空间管理。互联网时代,大规模数据存储逐步发展起来。出于降低成本的考虑,人们在分块存储的基础上进行数据块的复用,即所谓的“消重”。但对于大型的在线对象存储而言,分块消重是有害的。
具体来讲,分块消重是将数据对像切分成固定大小的数据块。数据对像之间有些数据块可能是一样的,那么就让它们共享数据块。换句话说,相同的数据块只留一份,所有用到这个数据块的对象,都指向这块数据。因为重复的数据块都被去除了,所以实际存储空间小于总的数据量。
数据对像被切块之后,需要对每个数据块做指纹运算,通常会采用数据块的哈希值。每个数据块计算指纹之后,在存储系统中检索数据块是否存在。如果不存在,就把数据块保存下来;如果存在,就不再保存了。一旦所有数据块都保存完成,就需要为数据对像构造一个索引数据块,依次引用每个数据块,而数据对像最终指向的是这个索引块。
数据块的大小决定了消重效率。数据块越小,重复的可能性越大,消重效率越高。但是随着数据块尺寸的减小,一个数据对像引用的数据块数量越来越多,因而索引数据块的尺寸越来越大。对于尺寸很大的数据对像,比如数GB,乃至数百GB,索引需要多个数据块构成,有时需要多级(树形)的索引块。相反,过大的数据块尺寸会降低消重效率。
在线对象存储系统由于庞大的数据存储规模,过小的数据块会引发数据块管理的困难,通常都会选择较大的数据块尺寸,一般在几MB至几十MB之间。但是,根据统计数据,来自互联网的数据对像,大部分是在1MB以下的。这意味着,MB级别的数据块大小大多数情况下都是一个数据对像占据一个数据块,块级消重退化为对象级消重,效率大幅降低。
分块消重的第一大问题是没法删除数据。造成这一问题的根源在于分布式环境和巨大的数据量。在分块消重里,一个数据块可能被多个数据对像引用。一个数据对像被删除,它所引用的数据块却不能随便删。因为可能还有其他数据对像正在引用这些数据块。只有在确认一个数据块没有被引用,才能将其删除。而在一个在线存储系统中,确认一个数据块是否被引用,是无法做到的。
我们可以通过检索所有的数据对像,生成一个数据块到数据对像的反向索引。然后找到那些没有被引用的数据块,进行删除作业。这就像内存管理中的垃圾回收功能,定期找出那些不再被引用的内存进行回收。但是,这样做有一个条件,就是整个系统在删除数据块期间不能有数据对象的写入。就如同垃圾回收需要短暂地停止程序的运行。所不同的是,存储系统的垃圾回收的停摆时间是以小时计算的。
内存的垃圾回收需要对内存数据做标记和拷贝,内存非常快,可以很迅速地完成清理。但磁盘的速度同内存相差几个数量级,并且在线对象存储的数据量规模庞大,数以P计。完成这样一次引用管理的梳理所需的时间以小时,甚至以天计算。
垃圾收集的模式不能满足要求,另一种办法就是引用计数。每个数据块维护一个引用计数值,用以记录有多少数据对像引用了这个数据块。这种技术在内存管理和资源管理中也有着广泛的应用。但是,在线对象存储系统中,数据存放在一个庞大的分布式集群里。跨越网络的引用计数增减远远没有内存中的操作来的可靠。从一台服务器向另一台服务器发起对引用计数的加减经常会有失败的情况。更具破坏性的一种情况是,增减引用计数的请求被正确执行,但执行结果的反馈没有成功传递。于是发起方认为引用计数操作失败,但执行方却认为成功,两者不一致随即会导致引用计数的偏差。
更混乱的情况是,在线存储为保证可靠性,往往使用多副本,即一份数据块有多个拷贝,分布在集群中不同的服务器上。多个副本的引用计数的一致性保障同样非常困难。无论是采用事务,还是使用WRN等一致性算法,都只能保证最终一致性,无法严格保证强一致性。这种非一致性时刻在发生,从而导致任何时候我们试图确定一个数据块的引用计数的时候,都无法确保这个数字是准确的。
作为应对,我们可以采用mark-delete的方式,在引用计数归零的时候,将一个块标记成delete。当有用户对被标记的数据块进行读取的时候,将其delete标记清除掉,恢复成正常数据块。在一段时间后,把那些始终未被恢复的数据块删除。但是,多长时间以后呢?对于“热”(即经常被访问)的数据块,错误删除后,很快就可以得到恢复。而对于“冷”(即长时间不被访问)的数据块,可能数周乃至数月不被访问。这样的数据块一旦被删除,便会造成数据丢失。
所以,分块消重将会导致无法(确切地说“不敢”)删除任何一块数据。在经年累月的运行之后,将会存在大量的垃圾数据块,导致存储系统的空间利用率降低,很大程度上抵消了消重带来的收益。
无法清除垃圾数据是运营成本和效率的问题。但是,接下来的问题涉及到在线存储的根本,它们有时是致命的。
我们知道,人造的东西都会坏。在计算机集群中,每一种硬件都会失效。当磁盘失效后,所携带的数据就会丢失。数据一旦丢失,就要尽快恢复。修复的手段就是从其他副本那里将数据复制一份过来。在实际的在线存储系统中,不会对一块盘直接恢复数据。那样太慢,一块有1TB数据的磁盘恢复一下至少需要20000秒,将近6小时。在大型的在线存储系统中,这段时间完全可能有其他磁盘损坏,如果凑巧失效的磁盘有同一数据对像的不同副本,那么该数据对像就可能丢失。所以,我们会将丢失的副本恢复到副本所在的子集群中,让其他服务器共同承担数据恢复的负载。
但是,这样的方式会导致被恢复的副本存储位置发生变化。副本存储位置一旦发生变化,需要尽快更新元数据。但是,当采用分块消重方式的时候,副本位置变化影响的不只是元数据,索引块的内容也需要做相应的变化。检索并修改所有涉及的索引数据块是严重的自虐行为。
对于一个数据块,如何知道它被哪些索引块引用?最基本的方法是扫描每一个索引块。鉴于存储系统的海量数据,完成一次扫描的时间虽然比不上数据块的引用检索那么漫长,但也是数以小时计。这种扫描会消耗大量的存储服务器的资源。而且随着每次数据副本修复,无论是单个数据对像,还是整盘的修复,都需要进行这样的扫描。频繁的检索对系统的稳定性和处理能力产生很大的干扰。
合理的解决方式是在数据块和索引块的层面引入一层间接。每个数据块和索引块赋予唯一的标识,元数据和索引都只引用标识。通常,数据块的标识会使用数据块的的摘要,比如MD5或者SHA1等等。数据块的标识同数据块的存储位置之间的映射通过一组元数据保存。当数据块副本的存储位置发生变化时,只需修改这组元数据,而所有对数据块的引用都无需变化。
但引入数据块层面的元数据使系统增加了复杂性。其问题不仅仅是增加一套数据库那样简单。同任何元数据一样,数据块的元数据需要保障非常高的可靠性,可用性和一致性。此外还有数据块的元数据和数据存储之间,以及数据块元数据同数据对像(索引块)之间的数据同步问题。一套额外的元数据大幅增加系统的复杂性和运维难度。
如果将数据块和数据对像的元数据存放在一套元数据系统里,问题会得到一定的缓和。维护一套元数据系统会比两套系统简单很多。但两级元数据中存在的数据同步问题依然不能解决,依然需要额外的数据核对和修复操作。
元数据是整个存储系统的核心和关键路径,是最复杂的部分,也是容易出现性能瓶颈,数据差错的地方。元数据的量越大,维持可靠性、可用性和一致性越困难。数据块和数据对像的元数据集中在一起,元数据量将会是数据对像数量的两倍以上。随着数据块的尺寸的变小,消重效率会提高,但元数据量会越来越大,可能达到数据对像数量的数倍。对于数据对像数量达到几十,乃至上百亿的时候,这种放大效应产生的影响非常可观。
于是,分块消重陷入一个两难的境地:收缩数据块尺寸,可以提高消重效率,但可能压垮元数据;如果放大数据快尺寸,会减小元数据系统的压力,但消重效果越来越差。再加上无法确定数据块是否被引用,从而无法删除未被使用的数据块,最终导致垃圾数据的积累,而抵消消重带来的好处。所以,在大型的在线对象存储系统中,分块消重是一个破坏者,造成的麻烦远比带来的好处更多。
Dark Side of Cloud Storage —— 数据对像的分块消重的更多相关文章
- Java Client for Google Cloud Storage
关于Google Cloud Storage Google Cloud Storage有益于大文件的存储与服务(serve).此外,Cloud Storage提供了对访问控制列表(ACLs)的使用,提 ...
- Getting Started(Google Cloud Storage Client Library)
在运行下面的步骤之前,请确保: 1.你的项目已经激活了Google Cloud Storage和App Engine,包括已经创建了至少一个Cloud Storage bucket. 2.你已经下载了 ...
- google cloud storage products
https://cloud.google.com/products/storage/ BigTable Cloud Bigtable 是 Google 面向大数据领域的 NoSQL 数据库服务.它也是 ...
- External Storage 数据存储
一些数据存储的封装:http://hubingforever.blog.163.com/blog/static/17104057920129198236599/ External Storage数据存 ...
- Activating Google Cloud Storage
先决条件 你需要下面的内容: 1.一个Google账户,比如来自Gmail.如果你没有,请在Google account signup site注册. 2.一个新的或已经存在的Google Devel ...
- Downloading the Google Cloud Storage Client Library
Google Cloud Storage client是一个客户端库,与任何一个生产环境使用的App Engine版本都相互独立.如果你想使用App Engine Development server ...
- AngularJS Front-End App with Cloud Storage Tutorial Part 1: Building a Minimal App in Seven Steps
原文 : http://www.codeproject.com/Articles/1027709/AngularJS-Front-End-App-with-Cloud-Storage-Tutoria ...
- Openstack之Swift架构(Cloud Storage)
Swift是OpenStack的子项目之一,也称为对象储存,适用于储存永久类型的静态数据,例如:虚拟机镜像文件.图片.存档备份等 复制的三个副本如何联系在一起? 让我们用一些具体场景和介绍一些组件,来 ...
- K3 Cloud的数据中心加载异常处理
以前一直是财务维护的K3 Cloud突然说不能登录,用的SQL 2008的数据库,运维也搞不定,找帮忙,因为是部署在阿里云上,上去看看数据库,这个K3数据库占了600多G,想看看这个表结构,就是打不 ...
随机推荐
- [置顶] NS2中TCP拥塞控制仿真过程中盲点解析
最近利用NS2做TCP拥塞控制协议的仿真,发现很多变量的方法含义都是解释的不清楚,给核心模块修改带来很多麻烦,所以决定用最准确的语言解释成员变量.方法,术语等的含义.限于个人水平,若有错误请留言指正! ...
- 摘记:IIS长时间任务超时处理
1.如果是在客户端调用Webservice,首先设置客户端超时, SoapHttpClientProtocol.Timeout = 3600 * 1000;//单位为秒,这是设置了一个小时 2.如果站 ...
- Qt多工程多目录的编译案例
源地址:http://blog.csdn.net/libaineu2004/article/details/23625441 写这篇文章的目的是为了让Qt像VC++那样,支持一个工程包含多个项目.即1 ...
- SQL Select语句完整的执行顺序
1.from子句组装来自不同数据源的数据: 2.where子句基于指定的条件对记录行进行筛选: 3.group by子句将数据划分为多个分组: 4.使用聚集函数进行计算: 5. 使用having子句筛 ...
- 基于MFC简单图片裁剪工具
话说这几天又没干啥正事,看书没效率,游戏也没怎么玩,尼玛时间都去哪儿了! --------------------------------------------------------------- ...
- 怎样手势的判断android GestureDetector在android开发中
import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view. ...
- 14.9.4 COMPACT and REDUNDANT Row Formats
14.9.4 COMPACT and REDUNDANT Row Formats InnoDB 早期的版本 使用一种未命名的文件格式(现在称为Antelope(羚羊)) 对于数据库文件 在这种文件格式 ...
- Linux IP代理筛选系统(shell+proxy)
代理的用途 其实,除了抓取国外网页需要用到IP代理外,还有很多场景会用到代理: 通过代理访问一些国外网站,绕过被某国防火墙过滤掉的网站 使用教育网的代理服务器,可以访问到大学或科研院所的内部网站资源 ...
- ORACLE 五种表的优缺点总结
ORACLE 五种表的优缺点总结: 1.普通表(heap table):适合大部分设计场景,有长处也有缺点. 长处: a,语法简单方便 b,适合大部分场景 缺点: a,更新日志开销较大 b,Delet ...
- 让VC2012生成的程序支持XP系统(QT的DLL都是支持XP的,只与EXE有关)
如果用的编译器是VC2012以上,那么默认生成出的程序是不能运行在XP系统上的.所以需要修改链接参数 我们要做的是修改qmake.conf文件中的参数,文件路径根据开发环境不同而不同下面以5.1.1 ...