一 为什么要研究存储系统的可靠性
说实话,只要不涉及到大规模的文件上传和分发,大家的架构都比较类似,对于结构化数据,我们的处理办法已经足够成熟和丰富,但是对于持久化的文件存储问题,很难选择一个合适的方案。
研究存储系统可靠性的目的是什么?当然是为了找到一个又便宜,响应又快,忍受得了很多故障,故障恢复速度又高的存储系统以供大家把玩。
提升可靠性的主要途径大体上三类:
1. 提高存储介质的品质
2. 提高传输线路的品质
3. 提高冗余度
前两项的实现依赖花钱和等待人类科技进步,这个我就不做讨论了。提高冗余度的直接办法,似乎也是花钱,多来几个副本就好了。
看来存储的可靠性所依赖的和讨老婆所依赖的是一个东西——有钱的爹,这个社会真是令人心痛。
但是,不要忘了,我们研究存储系统的可靠性的目的之一就是想办法节约成本。如果是自用,而且很有钱,什么贵用什么好了,可靠性肯定差不离。但是如果是提供存储服务,或者服务依赖于存储,靠这个赚钱的,那么节约成本就是重中之重了。
尤其是市面上,大多数人采用的方案是基本一致的。如果,你能提供比别人便宜但是性能指标更好的服务,那就赢得了市场的先机。
上面我们讨论出,对于一个存储集群来说,可靠性通过提高冗余度的方式来提升。带来冗余的方式除了副本,其实还有一个途径就是erasure code.
也就是说,在这一层面上,我们是有技术选型的还能有点余地的。这有就有了讨论这个问题的价值。
二 我们可以选择的冗余方案
在选择冗余方案之前,我们先应该看看我们是给什么样的一个系统做冗余。这就好比在讨论人生的另一半的寻找之前,先要确定一下自己喜欢的是同性还是异性,划定一下范围。
首先,它得是个大型的存储系统,太小的系统太不稳定,突发的情况很多。比如,今天我突然挂了,对于我来说死亡率是100%,但对于全人类的死亡率贡献是微不足道的。
其次,我们得定义一下这个存储系统是用来干嘛的。我们可以把存储系统理解为计算机的外部存储,功能是存,取,删和移动资源。另外,这么大一个系统,肯定是要满足N多人来做这些操作。有些人反应过来了——这不就是云存储中的对象存储吗?
是的,我在这里讨论的就是对象存储(以及类对象存储的文件存储系统)的可靠性问题。
然后,它是追求优秀设计的系统。淘汰一些缺陷影响比较大的设计或者复杂度太高的设计。
最后,整个系统的总体成本得比较低,这样昂贵的和少见的硬件规格就被淘汰了。
我们率先可以淘汰全闪存的设计。为什么呢?因为爱情,也因为贫穷。另外企业级磁盘也被淘汰了。关于企业级磁盘的稳定性分析可以去看backblaze这家业界良心的公司出的报告(个人认为这些数据的全面公开不仅仅是业界良心的表现,还跟企业的严谨程度有关,我猜测很多做云服务的公司让他拿也拿不出什么严谨的数据,因为根本没有记录)。这篇报告的大致结论就是企业级磁盘省在质保周期比较长,仅此而已(实际上,在扇区错误上企业级磁盘有一定优势)。那么,我们就用最便宜的民用级的SATA盘作为存储介质好了。
等等,有人可能会说了。 这个性能可能不够啊?
答案要从两个方面找,一个是提高网络传输水平,另一个是提高缓存质量。没错,在一个又大又便宜的系统中,性能的提升的不二法门就是良好设计的缓存。当然,这是题外话了,简单来说就是副本集群上面有个SSD热门资源的集群,再在SSD之上还有内存缓存,再出口外部还有一圈CDN做缓存。实际上,副本集群的磁盘并没有你想象中那么辛苦。
目前,我们已经确定经济上的最优选择的方向是桌面级的SATA盘。另外,还要再仔细一点的话,可以再考究一下磁盘容量,磁盘故障率,磁盘单价等因素,关于如何选择磁盘。backblaze也有自己的推荐,数据还是挺全面的。
现在我们一步步开始淘汰不应该有的设计。
很简单的,无冗余的方案第一个被淘汰。无冗余意味着坏任何一块盘,任何一个扇区,你都要丢数据,这太扯淡了。没人会这么做,除非公司老板是你情敌。或者,你认为数据不重要。既然数据丢了没关系,那也不用研究什么可靠性了。因此无冗余方案不做考量了。
冗余的两个途径,要么做副本,要么做erasure code。其中,三副本是最常见的实现方式,可用性和可靠性都不错,就是成本高。
为了节约成本,很多人使用了erasure code。
EC(erasure code)用的多的有这么几种实现:Reed Solomon codes(RS),Tornado Codes(LDPC),另外还有fountain codes,Xcode,weaver等等。
其中RAID5,应该是大家对熟悉的。但是,RAID5在不考虑扇区故障的情况下,只能容许一组raid中一块盘的去世,这个可靠性似乎不够用(准确的说是相当不够用,1副本的策略带来的效果和没有副本几乎是一样的)。我们要降低成本,但也不能可靠性还不如三副本吧?本来要买车代步,结果为了省钱转而买了双好鞋的即视感。
而且比起三副本来说,RAID还有一些性能问题:
为什么这么说呢?就算不考虑写入和恢复数据的计算问题,另外由于磁盘一次只能一个IO(SSD就忽略这条吧),不管是盘挂了要decode还是有一个大文件读写,都会影响整个条带上的所有磁盘。那么这个时候倘若有其他用户要做文件操作,就只能排队等待了。理想状态当然是通过合理的条带深度来匹配单次IO的大小,但是那毕竟是理想状态。
RAID6要稍微好一点,虽然RAID6的概念比较混杂,我们可以粗略的认为容许坏两块盘的就是RAID6(在不考虑扇区故障的情况下)。RAID6有了三副本类似的可靠性标准,但是考虑到其性能问题,我们得另作安排:
首先尽可能继续提高对磁盘损坏的容忍度,因为其性能不能满足要求,那么将起作为然后转第二集群,存放三副本落下来的冷的持久化存储。既然是持久化,其抵抗损坏的能力总得要比三副本明显高出一筹才行。
这样方式的实现,显然不是RAID6了(超过2块的容忍度)。那么,RAID6的实现很多是基于RS的,我们何不干脆直接使用RS。然后将RS集群作为较冷的存储。(PS:为了提高RS的计算效率,我们可以引入柯西矩阵替换原来的范德蒙矩阵,以提高逆矩阵的计算效率。另外有限域的计算也可以转换成XOR计算,其基本出发点类似于蒙哥马利算法。这种RS,我们称为CRS,即Cauchy Reed-Sololmon code)
RS(Reed Solomon)应用比较广,著名的有facebook,Azure.不过他们使用的是LRC(Locally Repairable Codes),部分使用了RS.虽然牺牲了MDS性质(MDS 性质了保证n=k+m 个磁盘中容忍任意m个磁盘死掉,而数据不发生丢失)但是修复表现更好,在系统容许挂掉的盘数到一定数量之后,这样的取舍是值得的。
Parity-check array codes计算开销比RS要小,但是一般只能接受2-3块盘去世。因为,既然我们已经决定把纠删码集群作为相对冷的存储了,只有这点能耐不够看。
LDPC和fountain code则比较有意思了。在云存储领域,流行程度为0.
他们的性能超级高(相对RS),空间表现也不错(我们只考虑systematic erasure codes形式的erasure codes,即data和parity symbols相分离,这样R/W性能会优秀一些)。那为嘛不用呢?
因为数学理论要求更高了。还有就是LDPC这玩意是有专利的。反正,现在计算机计算性能这么优秀,RS又有CRS的方法提升性能,另外又可以利用LRC去进一步提高修复性能。唉,罢了罢了。
我们再来看看fountain code. 恩,其两种实现LT code和Raptor code都有专利限制。嘿嘿。
总得来说这两种方法的可靠性都很好,计算性能根据不同的操作环境会有变化,在部分状态下,是RS的N个数量级的提升。只不过由于专利限制和数学实现的问题,在商用上可能会碰到麻烦。另外还有一个考虑是,RS的计算速度已经能满足修复多个磁盘的要求了,毕竟网络上的可供修复使用的带宽是有限的(这也是不能直接全盘使用RS的另一个原因,repair traffic将吃光你的网络资源),廉价磁盘的外部传输速度也是非常低的。
自古华山一条路,RS code就看你了。