一、业务背景
提到计算存储分离,必须要提到“云”,因为计算存储分离是“云”存在的模式和形态之一,也是最有成本优势的方式之一。
“云”时代已经真正来临,它在不断的为客户创造价值,因此它是一种新的商业模式。另外,“云”也是一种服务,是一种IT服务,如大家常见IaaS,PaaS,SaaS等。
从安全角度来讲,又可以分为“公有云”和“私有云”。另外,它其实也是大家所提倡的“共享经济”和“规模经济“的一种。
1.1 云计算
那么“云”倒底是什么,或者说由哪些技术所构成呢?要回答这个问题,首先我们来看“云”技术的分层架构,一般可以大致分为以下三层:
第一层是基础设施层,如IDC机房,服务器以及网络。其中,“软件定义网络”发生在这一层中,虚拟网络涉及到非常多的技术,如虚拟网卡或者switch,overlay,vxlan等。IaaS(Infrastructure
As a Service: 基础设施服务)一般就是指将这一层的能力进行虚拟化,提供“云”服务。一般“公有云”客户按时间进行租用。
第二层是存储层,将所有独立的存储服务器进行集中式统一管理。而对统一存储来讲,一般就是大家所熟知的分布式存储了,如开源社区的Ceph,Google的GFS,Hadoop生态的HDFS等。业界所谓的“软件定义存储”,就是指这一层。
第三层是计算层,计算层涉及到的面是最广的。如中间件,应用,大数据计算(MaxCompute),以及计算存储分离后的数据库等。
这么分层后,带来的好处就是每一层可以按各自的能力进行极限扩展,虚拟化后,按租户隔离,提供高效率的弹性以及成本缩减等。如Amazon,Google,Azure以及阿里云等。
对于这种“云”技术架构分层的价值,从IT的角度来讲至少可以有以下两大优势:
节约财务成本
学过ITIL V3的同学知道,从公司或者企业架构来讲,互联网公司首先必须解决IT服务战略问题,而服务战略中最为核心之一就是财务成本控制。
当一个企业发展到一定规模后,为IT付出的成本必须由粗放型转到集约型模式。否则,一个公司的盈利将被巨额的IT成本所吞噬。所以一个大公司的IT服务自身就可以形成私有云分层架构。
分层后,提高IDC资源,网络,存储的使用率,从而节省成本。另外,也提高了IT服务的灵活性和效率。当在业务平峰阶段时,以最小IT投入成本运行;当有计划的业务活动时,如“电商大促”等,则可以对资源进行弹性(离线资源等),从而节省成本。
使能IT服务
很多企业,尤其是非互联网公司,很少具备大而全的所有IT服务,因此,可以借云的服务,来为业务提供可能,扩展业务的边界。
如SaaS服务或者PaaS服务,客户可以通过租用这些服务,从而具备了某些IT服务的能力。如GPS服务,大数据服务,人工智能等。
1.2 计算存储分离
从上面分析可知,计算和存储分离是一种新的技术架构趋势,尤其在IT规模发展到一定程度后。各层做到极致,从而实现规模和共享经济,以更少的财务成本实现业务服务。这也是这里借时下流行的“云”的技术分层架构,引出计算存储分离的价值。
回到正题,计算存储分离仅是一种技术架构手段,但是在迈向这个分层的体系之前,各个业务都需要做大量适合自己业务特性的优化。在我们数据库领域,尤其如此,而且要求更加苛刻,难度更大。
在数据库实现计算存储分离时,我们在各层做了诸多的优化,使得数据库的计算存储分离成为可能,我们需要软硬件结合优化,需要数据库吞吐优化,需要统一存储调度等。
下面将一一展开,但不做技术细节阐述,有兴趣的同学,欢迎大家线下和我交流并帮忙指正。
二、分布式存储优化
在开始讲分布式存储前,先解释几个重要的概念:
服务可用性
是指能提供连续服务的能力,P=(服务总时间 - 故障时间)/ 服务总时间 * 100。一般以多少个“9”来表示。如存储服务提供8个“9”的高可用性。
服务可靠性
是指两次故障间的时间,T=故障总时间/故障次数。
服务可恢复性
一般以RPO(Recovery Point Object)和RTO(Recovery Time Object)两个指标来表示。
“RPO“是指服务或者数据能恢复到业务发生故障时间点的距离。RPO越小越好,如果”RPO“为”0“,就是无损恢复。如果有损,就是基于时间点的恢复(PITR:
Point In Time Recovery)。
“RTO”是指业务恢复正常时,服务或者数据恢复所花的时间。一般有相关的SLA指标,如“5”分钟恢复,“秒”级恢复等。
一般大家将“可用性”和“可靠性”搞混淆了,其实是完全不同的两个概念。
比如说,一个应用一秒内有“1”毫秒出现一次服务故障。那么这个应用的高可用性为6个”9“,但是实际上服务可靠性是非常差的,每秒都发生故障了。
另外,如果一个应用一年中,有1小时发生故障,其它时间都正常,那么高可用性比较低,约为4个“9“,比较差;而可靠性比较好,只发生一次。
2.1 增量和异步恢复
原来,我们单一的服务器,其磁盘故障率往往都比较低,MTTF(Mean Time To Failure)一般为100w小时。然而,当大规模的磁盘或者SSD(通常1000)组合在一起放入到统一分布式存储集群中之后,其故障率将明显变大。
我们可以简单做一个计算,一个磁盘在一个小时内的可用率为:1/1,000,000,99.9999%,6个“9“。而当一个集群磁盘达到1000个规模,每一个小时发生磁盘故障的概率为0.01
%。一天24个小时,那么每天将有 14.4分钟是有可能在这个集群中发生磁盘故障。这已经是非常大的一个数字。在一个大集群中,按这样子的概率,几乎每天都有可能会有磁盘fault发生。这是一个不可避免而又时常发生的事件。
在分布式系统设计原理中,故障并不可怕。比故障更重要的是做好服务高可用性和数据的高可靠性。
因此,一般分布式存储都提供了三副本(replica)来保证数据的可靠性以及存储服务的高可用性。三个副本的数据,按三个机架位部署后,其高可用性一般能达到8个9。但是三个副本中,因一台机器Down机,而发生副本暂时性减少或者永远丢失时,我们就需要把数据快速恢复回来。如果不及时进行恢复,长时间处于degrade状态,再发生盘的故障后,其可用性会大大降低。
因此在这种场景下,恢复对于分布式存储来讲,怎么不去影响业务的写入是一个非常关键的问题。
在进行集群后台数据恢复时,我们业务要求总体吞吐不能下降为原来的80%,恢复时不能使存储服务发生中断。因为这些都会影响可用性与可靠性。
因此,我们做了增量恢复和异步恢复,效果前后对比如下。其中“红色”的为优化后的IOPS曲线图,“蓝色”的为优化前的IOPS曲线图,大大提高了存储集群的高可用性。
2.2 长尾优化
计算存储分离后,所有的IO都变成了网络IO,因此对于单路IO时延影响的因素非常多,如网络抖动,慢盘,负载等,而这些因素也是不可避免的。因此,我们必须有一种方法,能够比较合理地规避这些影响。
我们设计了“副本达成多数写入即返回的策略(commit majority feature)”,能够比较有效的使长尾时延抖动做到合理的控制,以满足业务的需求。
正常情况下,慢盘因素会很快消失,除非出现持续性的慢,这可能由硬件故障等因素导致。
我们做了一个阈值控制,根据经验,通常为”200”ms(可配置)。当三个副本写成功的时间在200ms以内时,数据照样以三个副本写成功的模式返回,而当其中一个节点慢时,且超过200ms,则两个副本写成功就返回给客户端。这样做的目的是,在保证数据可靠性的同时,又消除长尾延时影响。
另外,我们会保存perf counter值,如果commit majority的操作(operation)超过一定数值时,且没有消退的迹象,就会发告警出来,人为介入处理。
以下是commit majority feature开起前后的效果对比。其中“蓝色”为优化后的长尾时延,“红色”为优化前长尾时延,效果非常显著。
2.3 流控设计
一般分布式系统都会有流控,或者是ITIL 规范中提到的QoS控制(Quality of Service)。一般都是对分布式存储后台活动的流量控制,如数据恢复或者数据平衡等。这往往是不够的,我们需要关注前端业务的写入与后端存储集群活动做一个“速度联动比率”,简称“速动比”。
新的流控方案设计,主要关心三个方面:其一是优先级控制,其二是quota控制,其三是业务与后台活动的速动比。
优先级控制
主要是指存储后端活动降低优先级,前端业务写入有最高优先级,这主要是为了保证业务写入的时延最低。
Quota控制
主要是指存储后端活动进行数据恢复和数据重平衡时不能占据高带宽以及IOPS,不然会影响前端业务的写入。
速动比
主要是指存储后端的活动与业务写入的速度做一个平衡。一般如果集群后端活动太低,会影响数据恢复,这会提高多盘故障的概率,降低了数据的可靠性。所以传统分布式存储只做到以上两种,我们经过优化后,通过滑动窗口机制,做到了前后端数据写入的速动,在不影响业务写入的情况下,尽最大可能提高数据恢复速度,保证多副本数据的完整性。
提高数据重平衡的速度,也是为了保证整个集群的性能。因为一出现数据倾斜时,部分盘的负载将变大,从而会影响整个集群的整体时延和吞吐。
流控效果如下:
2.4 状态机加速
数据中心的存储机型,一般都会提供大容量规格的存储。如我们目前使用的V41机型,单机12张卡,每张卡4T存储容量。在分布式存储中,一般一张卡设计为一个数据节点。因此,当一台机器故障时,就会出现12个数据节点不可用。
分布式系统中或者分布式存储中,当节点出现heartbeat信号丢失时,会进行peering活动,这个活动会涉及到集群状态机的变迁,或者是metadata元数据的变更。然而这些变更为了原子性,都是持有锁的。这就会导致前端的业务写入会有短暂的block。
根据实际数据库业务需求,我们进行了优化,将状态机的过程进行拆分,细粒度化mutex锁,从而提高并发能力,将peering过程控制在秒级以内。目前经过优化后,吞吐从原来的12次抖动并“跌0”变为只下降到正常水平的4/5,大大保证高可用性。以下为优化后的效果:
2.5 存储成本优化
我们拿到了数据多副本的红利,如分布式集群的高可用性以及高可靠性,但是随之付出的代价就是存储成本。因此,我们接下来会使用EC(Erasure
Code),来减少存储成本的使用。EC成熟度以及性能上还需要优化。前面讲几个点我们已经实现了。EC这个功能还需要进行重新设计,而且对明年的机型演进发挥比较大的重要。下半年,我们会重点来攻克这个业界难题,“如何在不影响性能的基础上,实现成本缩减”。
另外,传统的EC性能比较差,尤其是在出现部分盘故障时,数据重算和恢复的时间比较久,像微软已经引入LRC(Local
Re-generated Code)来实现。
如何做到对读写无损的EC,一直以来都是一个非常大的挑战。总体的方案无非就是两种,一种通过数据分层来解决,一种通过冗余空间,对历史版本进行EC。这两种实现在业务都有相应的原型,具体实现细节这里暂不做展开。
三、数据库设计
讲了这么多分布式存储的问题以及优化,这是因为,分布式存储的稳定性是基石,没有这个基石的稳定性,其它都不可能。因此,我们上半年花了比较多时间在分布式存储本身的优化上。
那么,回归到数据库本身,来看计算存储下需要攻克的一些难点。我想,最重要的问题莫过于“如何提高数据库的性能和吞吐”。我们分为以下几个点来讲。
3.1Redo优化
当所有的IO都变成网络IO后,我们要做的就是如何减少单路IO的延迟,当然这个是分布式存储以及网络要解的问题。分布式存储需要优化自身的软件stack以及底层SPDK的结合等。而网络层则需要更高带宽以及低时延技术,如25G
TCP或者25G RDMA,或者100G等更高带宽的网络等。
但是我们可以从另外一个角度来考虑问题,如何在时延一定的情况下,提高并发量,从而来提高吞吐。或者说在关键路径上减少IO调用的次数,从而从某种程度上提高系统的吞吐。答案是一定的。
大家知道,影响数据库事务数的最关键因素就是事务commit的速度,commit的速度依赖于写REDO时的IO吞吐。所谓的REDO也就是大家熟知的WAL(Write
Ahead Log)日志。
在脏数据flush回存储时,日志必须先落地,这是因为数据库的Crash Recovery是重度以来于此的。在recovery阶段,数据库先利用redo进行roll
forward;再利用undo进行roll backward,最后再撤销用户未提交的事务。
因此,存储计算分离下,要想在单路IO时延一定时提高吞吐,就必须要优化commit提交时的效率。我们通过优化redo的写入方式,让整个提高吞吐50%左右,效果如下:
另外,也可以优化redo group commit的大小,结合底层存储stripe能力,做并发与吞吐优化。
备注:”D13”是一种已经做过raid的SATA SSD
3.2 原子写
在数据库内存模型中,数据页通常是以16K做为一个buffer page来管理的。当内核修改完数据之后,会有专门的“checkpoint”线程按一定的频率将Dirty
Page flush到磁盘上。
我们知道,通常os的page cache是4K,而一般的文件系统block size也是4K。所以一个16k和page会被分成4个4k的os
filesystem block size来存储,物理上不能保证连续性。
那么会带来一个严重的问题,就是当fsync语义发出时,一个16k的page flush,只完成其中的8k,而这个时候client端crash,不再会有重试;那么整个fsync就只写了一半,fsync语义被破坏,数据不完整。
上面的这个场景,我们称之为“partial write”。一般我们通过以下两个方案来解:
数据页连续?
OS层为数据库分配的数据页16k是否连续?如果连续,底层block layer调度时,是否做为一个IO
request?
如果数据页物理连续,可以保证IO request的原子性,那么我们就可以使用ext4 的bigalloc特性,在上层对齐写后,来保证原子性,或者至少在一定程度来减少出现partial
write的可能性。
备注:Oracle通常不使用文件系统,使用裸的块存储或者ASM(Automatic Storage
Management),可以做到一个IO Request的原子性;而MySQL使用Double Write
Buffer来避免partial write的问题。
对于MySQL而言,在本地存储时,使用Double Write Buffer问题不大。但是如果底层变成网络IO,IO时延变高时,会使MySQL的整体吞吐下降,而Double
Write Buffer会加重这个影响。
所以将MySQL的Double Write Buffer关掉,从而在慢速网络IO下,提高MySQL的吞吐。
OS Filesystem是否支持16k?
如ext4是支持16k的block size分配的,但是mount时会报错。因为mount时,不支持超过内存页大小(4k)的文件系统。当然也可以通过fuse-ext2工具mount起来,但是成熟度上还不够。
另外,fuse也是一个比较好的方法,但是可能要兼容POXIS协议的难度会比较大。当然一般业务更愿意上层做一些改造,做一个简单的文件系统,去适配底层分布式存储。
3.3 Data Activity offload
计算存储分离后,对网络带宽是一个非常大的压力,尤其是InnoDB引擎,double write buffer加上redo,dirty
page以及binlog,数据存在多次写。通过IO原子性关掉double write buffer,那么对于dirty
page的处理呢? Aurora给了我们一个非常的例子,将所有与数据相关的操作都下放到存储后端:
步骤1:前端计算节点只负责REDO向存储集群分发
步骤2:持久化存储接收到的日志到分布式存储上
步骤3:返回ack给计算节点,以表示本存储节点已经收到日志并做持久化存储
步骤4:与其它存储集群进行peering,利用Gossip协议修补缺失的日志;异步处理,时间不计在ack内
步骤5:将日志应用到数据页上,为异步处理
步骤6:进行GC活动,回收和整理数据页以及日志
步骤7:进行数据校验以及多副本之间的数据校验
另外,对于MySQL实例crash后的recovery阶段,也是在存储节点上处理。其RTO(Recovery
Time Object)在2分钟以内。
这些与数据相关的操作,我们统称为“Data Activity”,在计算存储分离的趋势下,都可以做到优雅的下放。
大致处理逻辑如下:
3.4 读能力扩展
当存储与计算分离后,如何提供“一份数据,多份计算”的能力就至关重要。Aurora已经有了SDP(Shard
Disk Parallel)架构,用redo去失效备库cache,用于读能力的扩展。
四、统一调度
统一调度主要分为存储调度与计算节点的调度,涉及的内容比较多,如存储如何扩容?存储Volume如何管理?计算节点如何调度?以及网络拓扑架构如何调计?等等。由于篇幅受限,将在后面章节中重点讲述。
另外,对于网络拓扑设计感兴趣的同学,请参考:《计算存储分离之“数据存储高可用性设计”》
五、新技术与展望
目前我们正在进行软硬件结合(RDMA,SPDK)以及上层数据库引擎与分布式存储融合优化,性能将会超出传统SATA
SSD本地盘的性能。
虽然大规模下,部署RDMA环境还在一定程度上受到限制,但是在一个POD内的分布式存储集群中使用RDMA是完全有可能的。为此,我们不仅架设了高带宽网络如25G以及将来的100G等,而且TCP与RDMA网络的failover方案也真正酝酿中。
RDMA和SPDK的特点就是kernel pass-by。下面是我们进行测试的一组数据,其中本地用的是SATA
SSD,并且做了raid,但是其性能略低于基于RDMA和SPDK的分布式存储。
这些网络和硬件技术的发展,将会给“云计算”带来更多的可能性,也会给真正的“云计算”新的商业模式带来更多憧憬,而我们已经在这条阳光的大道上。
欢迎有更多的人一起参与进来,一起携手迈进未来。
|