日前,阿里云推出了业内首个百万IOPS的ESSD云盘服务,性能上有近50倍的飞跃,直接将AWS、Azure及国内众厂商的SSD云盘远远甩在身后,对业务的提升也是非常明显,实测在真实业务场景中,PostgreSQL数据库的写入速度快了26倍。
但如此夸张的性能,让人不禁产生疑问,为什么其他云厂商做不了这种云盘,阿里云用了什么秘密技术?是不是用了什么先进的架构?如何保障数据安全?
针对这类问题,阿里云的技术专家撰文,用1937年建成至今的金门大桥做比喻,形象解释了阿里云在存储领域的冗余设计思路:一些暂时不清楚的问题可能会有风险,但阿里云做了充分的冗余设计来抵御这种未知的风险,通过充分的冗余来斩断可能形成的故障链。
原文如下:
舞动的桥
作者:阿里云资深技术专家吴均平
1940年11月7日,竣工才4个月的塔科马海峡大桥在微风中大幅度舞动,桥上的汽车急速滑动,很快就戏剧性的垮塌。这件事故给建筑工程行业造成极大的震惊,很违反直觉,很低的风速居然会吹垮一座钢铁建造的大桥,在此之前所有的桥梁专家都没有意识到这个问题,事实上若干年后桥梁结构学与空气动力学得到极大发展,人类才彻底解决这个问题。
在工程领域通常将这类事前缺少认知,只有发生后才能意识到的问题统称为险恶性问题,这类问题杀伤力极大,对于盘古这样的分布式系统同样会面临这类险恶性问题,既然对问题都没有认知,又防御何谈呢?阳光之下并无新事,我们从各种安全至关重要的行业中广泛的学习,发现各个行业在面对这类问题时,已经有较为丰富的经验了,同样以桥梁为例,早于的塔科马海峡大桥的金门大桥(1937年建成通车)已经巍然屹立了80多年,可谓饱经风霜,后人在分析其设计者留下的设计手稿时发现早期的设计者在面对未知世界时非常谦卑,他们知道有些问题他们搞不清楚,可能会有风险,所以他们做了充分的冗余设计来抵御这种未知的风险,通过充分的冗余来斩断可能形成的故障链。
其实存储是一个高危行业,首先要保障的是不错,不丢,可访问,只有在这个前提下,极致的性能才有意义。不错,不丢,可访问,看起来平淡无奇,但实践下来常有如履薄冰之感,因为分布式问题太过复杂,因为操作系统、硬件都不是绝对可靠的,因为代码不可能绝对无bug,运维也不可能从不出错。有太多险恶性问题,即使行业先行者也出现过数据丢失和不可用。在盘古设计之初我们学习了上文中冗余设计的做法,承认自己所知有限,在很多地方做了冗余设计来抵御未知风险,并且在长期的演进中不但强化这类冗余设计,绝不为了性能或者其他的目标来做冗余设计上的妥协。
这些年来阿里云存储团队的同事们始终心存畏惧,铁棒磨针,始终专注于提供稳定可靠高性能的存储,天道酬勤,10年来我们做到了数据不错,不丢,非常庆幸。
下面我分享几个阿里云在存储方面的冗余设计:
•E2E的数据校验
磁盘可能出错,内存也会出现bit反转,内核和应用程序更可能出错,甚至我们遇到过某厂的一块CPU在做某些特定运算时就会出错,在这样一堆不可靠的软硬件环境下,要构建出一个稳定可靠的存储平台(没有哪个用户能接受哪怕一个bit的错误),是非常困难的,一般的做法是端到端的逐层做数据校验,盘古很早就做了E2E 的数据校验。但一次在一个长时间大压力的测试环境上MySQL 报数据错,核对数据发现CRC和数据是匹配的,并没有出错,核对另外2份拷贝,发现另外两份数据也是CRC自洽的,而且另外两份完全一致,但与MySQL读取的这一份差异非常大。初步判定是MySQL读取的这一份数据出错了,但这份错误的数据是CRC自洽的,这就非常奇怪了,如果是存储介质出错,不太可能还保持CRC自洽,在读写链路上查看了所有日志,没有找到任何异常。调查的同事反复核对三份拷贝,说这一份看起来就不像是这个文件的数据。
说者无心,听者有意,另外一个同事想在哪种情况下会出现这样的错误,由于我们的CRC和数据是逻辑空间上是相邻的,会不会是这片数据其实不属于当前文件,而是和另外一个文件搞串了?大胆假设,小心求证,全盘扫描后果然证实了猜想:A和B两个文件中间有一部分内容写串了,详细调查后确认是EXT4 文件系统的BUG,它在做空间管理的时候出错,导致A文件的一个数据片写入到文件B, 文件B中有一个数据片写入到文件A中,由于写入的流程一致,CRC又和数据放置在一起,导致CRC无法发现这个问题,确认问题后解决起来就很简单了,要么将CRC和数据分开放置,要么在计算CRC的时候加上文件的一个特征值。
有E2E的数据校验是否就安全了呢?呵呵坑深不见底,硬件行业的人知道磁盘极小的概率发生静默错误(读出来的数据是错误的,但底层接口不报错,磁盘本身也不报错),如果三份拷贝很长时间都未被读取,而在这个较长的时间窗口内,如果有三份拷贝所在的3块盘都发生了静默错误,用户读取数据时,存储系统就会发现3份CRC校验都不通过,尽管知道出差错了,却没有任何办法修复。为了降低这种情况发生的概率,我们会定期扫描冷数据,校验其CRC。
•压缩检验
一天新来的同事问大家:“我们在做压缩的时候,为啥压缩完后,立刻又解压缩一次,并且将解压数据和原始数据再去比对一次?直接压缩不就完了吗?”,众人笑而不语,他思考良久,也未能找到足够的理由。团队内老司机告诉他,压缩本身是一个很复杂的东西,有些库是第三方提供的,尽管我们会review代码,有严格的引入测试,但没人能保障其绝对正确,万一压缩出来的内容是错的怎么办?CPU也可能存在一些偶发性的错误,如果压缩时发生这类小概率的偶发性错误,该怎么办呢?但户数据是绝对不能错的,所以我们这里采取防御性编程,压缩完后立即解压,再和原始内容比对,确保数据不错。
•PAXOS
说到分布式存储,很多人就言必称PAXOS和RAFT,PAXOS俨然就成了救世主。PAXOS, RAFT 的确是好东西,但并不是所有的场景都适用。在一个分布式系统中,大家会认为在一个较小的时间窗口内同时发生2台机器failover是一个小概率事件,但随着集群规模的扩大,集群数量的增多,最终小概率事件长期积累,就变成必然事件了,在quorum=3的时候,PAXOS 协议是无法处理double fail的,甚至无法自愈,需要紧急人为干预才能恢复。想想半夜收到告警,你能在几分钟能处理好用户的IO HANG? 适合的才是最好的,实践是检验真理的唯一标准。
•磁盘错误
对于做存储的人来说,磁盘故障是司空见惯的事情了,本身有一套成熟的处理机制。但百密一疏,我们还是在这上面栽过跟头,进程主动检测到binary所在的系统盘故障,老司机当然知道此时不能再在该盘上发起任何IO 操作,日志写入到内存中,调用exit, 安静的退出,不带走一片云彩即可。但进程居然无法退出,调用exit 无法退出!而此时其它线程还在继续工作,在干坏事。所有人都觉得匪夷所思,为啥主线程调用 exit, 进程未能退出,其他线程在长达几分钟内还在继续干坏事?团队大牛反复推演,不放过任何一个蛛丝马迹,终于搞明白了,原来磁盘故障后,exit这段代码本身并不在内存中,调用时会产生major fault, 中断处理程序会尝试从磁盘上load相应的代码段,而磁盘已经故障了,load 被hang住,导致出现前面这些匪夷所思的怪事。
今天云计算已经成为互联网的基础设施,随着众多电力,水务,医疗企业上云,阿里云又成了这些基础设施的基础设施,任何一个黑天鹅都有可能带来难以估量的影响。只有对这个未知的世界保持敬畏,保持谦卑,才能走得更远。
【本文作者:阿里云资深技术专家吴均平】