作为一个分布式的存储,对象存储底层是采用多副本方式实现的,以便在一个可用区内,保证每个写入的对象都有极高的可靠性,其数据可靠性不低于“12个9”、服务设计可用性(或业务连续性)不低于99.995%。虽然硬盘故障、单机异常等情况不会影响到数据可用性和可靠性,但是在面对机房级别故障(如停电、网络异常)或自然灾难(如地震、海啸)等导致的一个数据中心无法提供服务时,使用该数据中心的客户服务还是会受到影响的,因此异地容灾能力不可或缺,当某集群发生异常时,需要快速切换服务,保障业务的可用性。
淘宝图片业务异地多活架构
上图所示的是淘宝图片业务异地多活架构,数据中心分别位于张北、上海、成都三地,对于淘宝上的所有商品图片,三地都会有一份全量的数据。正常情况下,用户浏览图片,内容分发网络(Content Delivery Network,CDN)就近回源到各个地域(Region)业务层图片空间ImageGW应用,ImageGW通过从同地域对象存储读取数据进行业务逻辑处理后返回内容分发网络,展示到客户端。这个过程中三地都是多活提供服务的。当某个地域发生异常时,通过切换内容分发网络回源,快速将流量调度到其他两地,保障服务的高可用。
1、异地多活容灾实现细节
一写多读模式
淘宝图片业务异地多活架构采用如上图所示的一写多读模式,主集群开通了到两个备集群跨地域复制的功能,写入时只写入主集群,利用数据同步技术将数据复制到各个备集群,各个备集群都有全量的数据。
读取时,根据地域就近读取,降低延时。由于写入时只写一份数据到主集群,数据是异步复制到备集群的,所以用户读备集群数据时,可能还有数据没来得及复制到备集群,导致读取不到。这时,通过镜像回源读功能,可以直接从主集群回源读取数据,达到主备集群都能实时读取数据的目的。
2、容灾切换(备集群不可用)
备集群不可用
当备集群不可用时,对于内容分发网络读流量,只需要将内容分发网络回源从地域2备集群切换到地域1和地域3,流量均分,业务就能立刻恢复。同理,将业务读对象存储的桶数据切换到其他两个集群,也能达到容灾的目的。
3、容灾切换(主集群不可用)
主集群不可用
当主集群不可用时,如上图所示,这时就需要切换写了。将地域2设置为目标主集群,首先需要开通从地域2到地域3的跨地域复制,客户端通过更换写入的桶配置,切换写到地域2,通过数据复制技术,将数据同步到地域3了。对于读来说,由于地域1主集群已不可用,镜像回源配置就需要切换到新主集群地域2了。
此时和上述“备集群不可用”时切换读方式一样,通过切换内容分发网络回源配置和用户读对象存储的桶配置,即可将业务读切换到其他两个正常的集群。对于线上淘宝图片业务,阿里云已经预先开通好了各个地域互相复制的能力。在切换写时,客户端可直接切换写入的桶,不需要再配置跨地域复制关系,将切换过程尽量简化。
在主集群故障,但并没有受到毁灭性灾难摧毁时(如只是停电、断网导致暂时不可用,而不是地震、海啸等导致数据中心损毁的情况),对于刚写入主集群还未被复制到备集群的数据,在故障期间并不会丢失,集群恢复后这部分数据还是会被复制到备集群。
由于容灾切换主集群后,用户可能在新集群写入了数据,这部分数据可能会和容灾切换前写入主集群的数据有相同的名称,所以就可能会产生冲突。对象存储系统同步只保证最终一致性(按照文件写入的先后顺序),如果用户对同一个文件有覆盖操作,并且对中间结果有依赖,那就要么建议用户开启多版本功能,要么建议不要让文件名重复。在淘宝图片空间场景中,文件名由客户端唯一生成,不会重复,容灾切换和恢复时也不会存在文件冲突的场景。
系统中最重要的部分是数据同步部分,也就是对象存储跨地域复制(Cross-regionBucket Replication),其架构如下图所示,通过跨不同数据中心,针对用户的数据,进行异步的复制,将对源端数据的改动,如新建、覆盖、修改、删除等,同步到另一个地域中去。目标地域的数据是源端数据的精确副本,具有相同的名称、创建时间、拥有者、用户自定义的元数据、对象内容等。
对象存储跨地域复制架构
简而言之,一旦用户为桶配置了跨地域复制功能之后,任何对象在上传到开启这个功能的桶时,对象存储都会自动地为其在用户所指定的另一个地域中的桶里进行备份。当用户修改对象内容或属性时,对象存储也会自动复制,始终保证源桶和目标桶中的对象一致,且完全不需要用户干预。对象存储数据复制(如下图所示)包含四大模块:请求处理与转发层(Process Layer)、持久化层(飞天盘古)、异步日志处理层(Scanner)、复制服务(Replication Service)。
对象存储系统跨地域数据复制模块
用户的请求从Web Server进入之后,经过处理(如协议解析、权限验证、切片、校验)持久化到飞天盘古系统。同时,对象存储在写入数据时,会记录一条日志,后续由异步日志处理层会对这些日志进行异步扫描,产生复制事件。
复制服务会在后台运行,它是一个分布式的服务,分为主节点(Master)和工作节点(Worker)。主节点处理桶元数据信息,调度任务到不同的工作节点上执行。工作节点分为三种:一种是消费复制事件的工作节点,叫作消费者(Consumer);一种是调度复制事件的工作节点,叫作调度者(Scheduler);一种是复制数据的工作节点,叫作复制者(Replicator)。当有复制事件产生时,消费者会取出该事件,解析验证,交由调度者负责调度;调度者会分配任务到某个复制数据的复制者去处理,同时负责资源控制、均衡压力;复制者就将数据复制到另外一个地域中去,它会负责数据的切分、传输及校验。
那么,在这样的架构下,如何实现海量数据的快速复制呢?
首先,系统中所有工作节点,包括消费者、调度者、复制者都是无状态的,当发生失效转移(Failover)时,不用依赖于上下文信息,可以迅速地重新加载。如果没恢复,主节点会将其上的任务调度到其他工作节点上执行,不会导致某些任务无法运行。
其次,包括扫描日志,以及从对复制任务做分发到复制任务的执行在内的所有流程都是解耦并异步执行的,充分利用了系统资源的能力。
再次,所有的任务都是哈希打散开的,包括事件消费、分发和复制任务都是均匀分布到多个工作节点上执行,没有单点瓶颈。
最后,数据复制采用的是流式复制方式,数据不落盘,从源端获取到一个缓存后就开始复制,进一步提升效率。