完整文章在《程序员》第2013.11期第108页


云计算并不是天生为数据库设计的,在云端使用关系型数据库面临着软硬件可靠性差、可预测性低和控制能力弱等诸多挑战,网易云数据库在架构设计中充分考虑了上述因素影响,并通过相应的技术手段解决了这些问题。


架构设计

图1为网易云数据库的总体架构图,下面将详细介绍各个模块扮演的角色和主要功能。


管理服务器:整个系统的调度控制模块,负责实例管理、备份管理、计划任务、高可用、在线Scale-up、平台管理员、计费相关功能。管理服务器对外负责处理所有来自用户的HTTP管理操作请求,对内通过调用API控制底层的计算、存储和网络资源。

为了实现高可用,通常管理服务器部署在三个物理节点上,利用ZooKeeper提供的分布式锁的功能,只有一个对外提供服务。如果该服务器宕机,则系统利用ZooKeeper提供的选主功能选出一个新的节点对外提供服务。

管理服务器的功能模块主要包括三层:第一层是API层,负责定义数据库资源的封装管理操作,对外提供API接口;第二层是管理流程层,负责实现所有的管理操作业务逻辑;第三层是调度控制和外部通信层,主要负责控制和调度所有的管理业务流程,同时封装对外通信的接口。

系统使用了开源组件ZeroMQ和ZooKeeper。

ZeroMQ:消息队列,负责管理服务器和Agent之间的消息通信。ZeroMQ是一种更为轻量级的消息队列,与传统的AMQP协议的消息队列不同,它不需要独立的消息服务器,只需要引用一个LIB库即可实现节点之间的通信。因为异步传输、LockFree、消息不持久化等特性,ZeroMQ相比其他消息队列具有更高手消息通信效率。ZeroMQ的设计理念是专注于底层消息的通信,所以它不负责消息的持久化和序列化。对于持久化问题,上层应用可以通过消息重发来保证消息的可靠传传输,但需要接收方能够判断重复消息,这个可以通过版本号的机制解决,即每个消息都附带一个版本号字段,重复消息使用相同的版本号,接收方记录当前的版本号,如果出现等于或者小于当前版本号的消息 ,则认为是重复消息。对于序列化的问题,可以使用Google的开源序列化框架protobuf实现。

ZooKeeper:开源的针对分布式系统的可靠协调系统,在云数据库中主要实现多个管理服务器之间的分布式锁、统一配置管理和选主的功能。管理服务器在启动时,会在ZooKeeper上生成一个有序节点,同时如果该节点不是最小节点,则需要watch前一个比它小的节点,只有最小节点的管理服务器对外提供服务。如果该服务器宕机,则watch该服务器对应节点的standby节点被唤醒,成为新的对外服务节点,这样避免了多个standby同时watch对外服务节点造成的“惊群现象”。同时,watch宕机节点的所有Agetn被唤醒后,会从ZooKeeper上获取新的管理服务器节点的信息,完成了配置修改。


高可用性

由于云托管的服务器相比专用的硬件可靠性有显著下降,所以高可用是云数据库首要解决的问题。实现高可用唯一的途径就是增加冗余,实现自动故障切换。目前有以下方案:

DRBD:块级别的同步复制,不仅管理复杂,且存在的性能开销。

共享存储:在主机宕机后,从机通过挂载到主机的文件系统上,在主机的数据上执行恢复操作。宕机时间取决于存储引擎的恢复以及预热的速度,通常难以做到1分钟内故障恢复。

复制:使用标准的MySQL复制实现主从同步,目前有两种实现:MMM和MHA。MMM不保证数据一致性,MHA需要主机宕机后依然能够通过SSH获取到主机的二进制日志。

网易云数据库选择基于MySQL复制实现高可用,面临的技术难点主要包括数据一致性的保证和实时故障切换。

数据一致性:官方版本的复制是异步的,主机发生故障时容易出现主从数据不一致。MySQL5.5版本以后推出了半同步复制,虽然将返回客户端成功与发送从机同步起来,但还是没解决丢失数据的问题。为了保证主从的数据一致性,网易MySQL技术组修改了主机事务提交次序,在内部我们称为虚拟同步复制(Virtual Sync Replication)。Oracle官方MySQL5.7也已经支持类似同样的功能,相信这会成为今后MySQL数据库高可用的一种标准手段。此外,为了保证主机写入性能不受影响,我们在二进制日志层做了Group Commit以fsync的次数,提高了二进制的写入性能。需要注意的是,考虑到从机SQL单线程回放效率的问题,我们这里仅是将主机上的更新写入从机的relaylog后即返回,而不是等到从机完全apply该更新(全同步复制),所以从机可能无法立即读到这部分更新。这就需要在主从切换后,需要将人机所有未apply的relaylog全部回放完毕后,再提供给用户读写,这就引入了第二个问题:实时切换。

实时切换:由于MySQL复制的过程中,从机是单线程回放主机上的更新,所以往往会出现从机落后的情况。而为了保证数据的一致性,在主从切换后从机落后的时间里,服务是不可用的。所以要实现实时切换,从机使用多SQL线程并行复制是一种有效解决方案。MariaDB提供了基于行的并行复制,要求是Row格式的二进制日志。我们采取了类似MariaDB的实现方式,根据表的主键判断两个事务是否冲突,从机按照事务分发线程,如果一个事务的更新中包含上一个事务更新涉及的主键,必须等待上个事务执行完毕后才可以执行,否则或并发执行。更重要的是,网易MySQL技术组还实现了并行复制的crash safe功能,保证在意外宕机情况下,依然能保证主从数据一致性。

主从切换后,需要对原先的宕机数据库实例进行修复操作,首先就是要重启。但我们从图2的的事务提交流程可以看出,虚拟同步复制主机事务提交先写入二进制日志,然后再发送给从机,如果在这个过程中主机宕机,就会出现主机上有一部分未提交的二进制日志,而这部分日志中涉及的事务更新也未在从机执行。

对于未提交的二进制日志中的事务,MySQL会在系统启动时自动提交,这样就会出数据不一致的问题。所以在重启前,先对二进制日志进行修剪,去掉这部分二进制日志,这样就保证了启动后的该实例和当前服务的实例数据一致性,然后再建立到当前对外服务实例的复制关系即可。如果重启失败,则系统会将该实现提交给重建队列进行重建。



Scale-up与Scale-out

数据库的扩展主要分为两类:Scale-up和Scale-out。Scale-up是指通过增加一台服务器的资源来增强数据库实例的处理能力。资源的动态伸缩是云计算最显著的优势,所以在云计算环境下Scale-up将会变得非常容易。但在底层资源的伸缩过程中,会出现服务的中断,造成数据库的不可用,所以云数据库的Scale-up需要解决的是资源扩展过程中服务可用性的问题。

借鉴高可用的设计思路,可以通过创建冗余,在从机上先进行Scale-up,然后通过一次主动的主从切换,将服务切换到已完成Scale-up的实例上,从而完成不停服务的在线Scale-up过程。

Scale-out是指通过将用户的请求分布到多个数据库实例上来提供整体的处理能力。按照网易私有云的规划,网易云数据库并不直接提供用户的Sharding的功能,而是作为另外一个私有云PaaS服务分布式数据库的底层节点对外提供服务。分布式数据库服务直接利用云数据库提供的API实现数据库实例的操作和管理,然后在上层实现Sharding功能。


读后感

MySQL复制使用虚拟同步技术,等到主机二进制日志传送到从机relaylog后,主机再commit,这种会增加主机事务提交的响应速度,如果网络或从机出现问题,则事务提交失败。如果从机relaylog成功后,而网络出现问题,或者主机的问题,导致主机commit失败,还是会发生数据不一致的现象,而且情况会更复制。

从库即使使用多线程的SQL,在主机高并发写的情况下,它依然会落后于主机,因为从机不可能比主机执行的更快。

在主从的实时切换上,感觉到目前为止,还没有一种可靠的工具能完全自动化的并且保证一致性的情况下,自动实时切换。


我想关于主从一致的问题上,还是应该结合具体的应用,对主从一致性的容忍程度上,在应用层来避免主从不一致情况下从库的读写问题。但云数据库无法灵活的结合应用层业务来实现这一点,因为它是个统一的架构来面向服务的。


Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐