UMP(Unified MySQL Platform)系统是淘宝核心系统数据库团队开发的低成本和高性能的MySQL云数据方案,关键模块采用Erlang语言实现。系统中包含了 controller服务器、proxy服务器、agent服务器、API/Web服务器、日志分析服务器、信息统计服务器等组件,并且依赖于 Mnesia、LVS、RabbitMQ、ZooKeeper等开源组件。
在“低成本和高性能的MySQL云数据库的架构探索”一文中,我们介绍了UMP的系统结构和各个组件的功能,本文里,我们会进一步来探索RabbitMQ 和ZooKeeper在系统中的应用以及proxy服务器的实现,整个系统如何实现容灾、读写分离、分库分表等功能,介绍资源管理、隔离和调度等技术,以 及在保障用户数据安全上的做法。
RabbitMQ
RabbitMQ是一个用Erlang开发的工业级的消息队列产品。集群中各节点间的通信(不包括SQL查询、日志等大数据流的传输,这些还是直接走TCP的)都通过RabbitMQ,作为消息通讯的中间件来使用,来保证消息发送的可靠性。
集群初始化时会在RabbitMQ中为集群里的每个节点创建一个队列,作为节点的“信箱”。节点间发送消息时不管对方在不在线,只要写消息到对方的“信 箱”里即可,接下来由对方节点上运行的RabbitMQ客户端接收消息,调用相应的处理例程。消息处理完后,客户端会回复一个ACK包到 RabbitMQ,从“信箱”中删除这条消息。基于RabbitMQ可以实现RPC,客户端除了回复ACK包给RabbitMQ删除Request消息 外,还向发送者的“信箱”写入一条Reply消息。RabbitMQ是支持事务的,可以保证删除Request消息和写Reply消息在一个原子操作中完 成。
图1节点之间通过RabbitMQ实现RPC
如果接收者在处理消息的过程中崩溃了,那么消息还会存储在RabbitMQ中,重启后,消息会再次推送过来,由接收者继续处理。
RabbitMQ可以保证消息被发送出去,被接收者处理,但不幸的是,无法保证消息只被发送/处理一次,主要原因在于RabbitMQ不支持XA。首先, 发送者将消息写到MQ和在本地写一条日志不能在同一个事务中完成,如果发送者将消息写到MQ之后,在本地写日志之前崩溃了,重启后无法确定消息是否被发 送,只能尝试重发;同样,消息的接收方无法将处理消息和从MQ中删除消息放在同一个事务中完成,如果消息的接收方在处理完消息之后,从MQ中删除消息之前 崩溃了,那么重启后仍然会继续收到并处理这个消息。
因此消息的接受方在处理消息时需要保证幂等性(idempotent),即同一条消息被处理多遍不会有副作用,比如controller向agent 发送备份命令时可以捎带上一次备份的时间点,agent检查这个时间点一致后再执行备份操作,这样可以保证同一条备份命令被发送多次时不会创建多个备份。
利用RabbitMQ的路由功能(Exchange)还可以实现消息广播,例如系统中会创建一个叫proxy的Exchange,类型配置 为’fanout’,当有新的proxy服务器注册时,节点的“信箱”就会绑定到该Exchange上。这样当controller服务器需要向所有的 proxy服务器发送通知时,比如执行主备切换操作,发送到Exchange上的消息会写入所有proxy服务器的“信箱”中。
RabbitMQ还实现了一种镜像队列(mirrored queue)的算法提供HA。创建队列时可以通过传入“x-ha-policy”参数设置队列为镜像队列,镜像队列会存储在多个Rabbit MQ节点上,并配置成一主多从的结构,可以通过“x-ha-policy-params”参数来具体指定master节点和slave节点的列表。所有发 送到镜像队列上的操作,比如消息的发送和删除,都会先在master节点上执行,再通过一种叫GM(Guaranteed Multicast)的原子广播(atomic broadcast)算法同步到各slave节点。GM算法通过两阶段的提交,可以保证master节点发送到所有slave节点上的消息要么全部执行成 功,要么全部失败;通过环形的消息发送顺序,即master节点发送消息给一个slave节点,这个slave节点依次发送给下一个slave节点,最终 消息回到master节点,保证了主从节点上的负载差别不大。
ZooKeeper
ZooKeeper在分布式集群中提供分布式锁、名字服务等,它把分布式集群比做动物园,而自己则扮演动物园管理员的角色。ZooKeeper最早是由 Yahoo!开发,应用在Hadoop软件栈中发挥Google Chubby的作用,我们在项目中单独使用ZooKeeper,实现三个功能:
1.作为全局的配置服务器。配置文件原先是放在本地的,变更配置需要到所有的节点上去修改,这不仅是重复性的工作而且容易出错。放在ZooKeeper上后,所有节点都监视配置文件的变化,文件一旦被修改,所有节点都会重新加载并触发相应动作。
2. 提供分布式锁。集群中部署了多个controller服务器通过热备实现HA,但这些controller服务器不能同时执行同一个操作。例如,一个 MySQL实例挂掉后,如果所有的controller服务器都去跟踪处理并且发起主备切换流程,proxy服务器和agent服务器就会收到多条切换的 命令,集群就乱套了。因此简单起见,我们规定同一时间,整个集群中多个controller服务器只能选举出一个leader,由这个leader负责发 起各种系统任务。Leader的选举功能就是通过ZooKeeper的分布式锁功能实现的。
3. 监控所有MySQL实例。我们为MySQL服务器开发了一个ZooKeeper客户端插件,启动后会连接到ZooKeeper服务器上并创建一个临时节 点,如果MySQL进程死掉,经过5秒的超时时间,这个临时节点就会被删除,从而被后台运行的监控daemon检查到,如果死掉的MySQL进程是主库的 话则触发主从切换流程,是从库的话则从库的读权重被设置为0。
容灾
当MySQL服务器出现故障时,系统会执行对用户透明的故障恢复过程,用户感知不到主库宕机和上线事件,proxy服务器向用户隐藏了这些事件,提供给用户的是一直可用的数据库连接。
对每个用户,系统中都会维护主库和从库两个MySQL实例,而把主从库的复制(Replication)关系配置成Dual Master结构,即两个MySQL实例都把对方设置为自己的Master,从对方读取数据更新,复制到本地,这样向其中任意一个MySQL实例写入数 据,都会更新到另一个实例上。Dual Master结构存在的问题是,如果两个MySQL实例同时修改同一行数据,就会有发生冲突的可能性,最终写到两个实例中的数据版本不相同,因此为了保证 数据的一致性还需要保持"single write",即只向主库中写入数据,这点由proxy服务器来保证。
当主库宕机后,MySQL插件在ZooKeeper上保持的临时节点会因为会话超时而被删除掉,controller服务器检测到这一事件后,会发起 主从切换操作,在路由表中把主库标记为不可用状态,并通过RabbitMQ通知所有的proxy服务器执行切换。
当宕机的主库再次上线时,策略会稍微复杂一点。这时候从库中的数据比主库要新一些,主库需要一段时间执行更新,当主库的版本接近从库 时,controller服务器会发送停写命令到从库,等待主库和从库状态完全一致后,发起主从切换操作,在路由表中恢复主库为活动状态并通知proxy 服务器把写操作切回主库上,全部完成后再把从库修改为可写状态。从上述过程可以看出,把主从库的复制关系配置为Dual Master结构,简化了执行主从切换的步骤。
上述过程中,宕机的主库再次上线会使用户感受到短时间的不可写,进一步的,proxy服务器端可以通过捕捉错误,延迟重试的方法屏蔽掉这个问题。
读写分离
我们还实现了对用户透明的读写分离。当功能的开关打开时,proxy服务器会解析用户传入的SQL语句,将写操作发送到主库,读操作负载均衡的分发到主库 与从库上执行。为了避免用户刚写入数据到主库,在同步到从库之前就去读从库,从而读不到或者读到旧版本的情况出现,我们在每次写操作发生后都会添加一个计 时器,用户每次写操作后300毫秒内读任何数据都会强行分发到主库。通过主从多线程复制技术,300毫秒基本可以保证数据从主库同步到从库,而这个值也可 以在配置中调节。
proxy服务器还需要解析MySQL连接相关的属性,例如用户通过连接参数或者“use database”语句设置的默认库,以及通过set语句设置的会话变量(session variables)等,将这些参数设置到主库和从库的连接上,并记录到一张内存表中,当与后台数据库新建连接或与断开重连时,会重新设置这些环境参数, 避免让用户感知到差异。
分库分表
我们还实现了对用户透明的分库分表(shard / horizontal partition)。在创建用户账号的时候就需要指定类型为多实例,并设置实例的个数,会创建多组MySQL实例。用户建表时需要指定分库分表的规则, 规则中需要指定分库分表的字段(partition key),partition key怎么映射到分表上去,分表怎么映射到多个实例上去。这些规则可以通过在建表语句前添加SQL注释的方式的传入。
首先,proxy服务器会对用户传入的SQL语句进行语法分析,抽取出重写和分发SQL语句所需要的信息,例如SQL语句操作的表名,插入语句中每条记录 里partition key所对应的值(必须包含该值),查询语句中的where子句中的条件,order by、group by语句中的字段,以及limit语句中对结果条数的限制等。目前,支持的SQL限于insert,select,update,delete这四种 DML语句的基本形式,表连接和嵌套select查询目前还不支持,order by和group by也限于单个字段,这些地方还要继续投入人力去实现与完善。
下一步,是将SQL语句重写为到各个分表上去执行的子语句的形式,主要是表名替换和where条件改写,接着将子语句并发的发送到对应的分表上去执行。
最后,是接收与合并各个子表上返回的执行结果。为了避免查询语句的结果集过大撑爆proxy服务器的内存,或者是在用户只需要一部分结果的情况下减小通迅 开销,我们对查询结果得接收与合并过程做了一些优化。通过设置缓冲区大小,可以限制MySQL实例每次返回的结果行数,当所有分表上都返回部分结果后,就 开始执行归并排序,并将排好序的结果返回给用户,当来自某个分表的结果都用完后,再去读socket填充缓冲区,获取下一批结果。整个过程比较类似于搜索 引擎中将查询分发到检索服务器再进行结果合并的过程。
图2 Proxy服务器的实现层次
为了提升性能,SQL的解析、重写以及合并多个MySQL服务器返回的结果集均是用C++实现,通过NIF接口方式被Erlang语言编写的状态机调用。
资源管理
我们参考了VMware DRS等云计算系统中资源管理的方法,实现了一套资源池机制来管理数据库服务器上的CPU、内存、磁盘等计算资源。管理员先按照整个集群所有服务器的机 型、所在机房等因素划分多个资源池,服务器上的agent进程启动后会注册到controller节点上,管理员再通过web管理界面将每台服务器加入到 合适的资源池中。
分配实例的单位是资源池,管理员可以根据应用部署在哪些机房、需要的计算资源等因素分别指定主库、从库所在的资源池,实例管理服务再从资源池中选择负载较 轻的服务器来创建实例。后期我们还将开发资源池内的调度管理,如果资源池中一台服务器的负载长期明显高于其他服务器,调度进程会将其中的MySQL实例迁 出到低负载的机器上。
除了将服务器划分为资源池,在每台服务器内部,我们也结合Cgroup将它的资源进一步的细化以方便管理和隔离。例如,一台16核,48G的服务器, 我们会将它的资源划分到16个进程组中,相当于每个进程组分配到一个CPU核和2G的内存,这样一个进程组中可以放入8个内存规格为256M的MySQL 进程,而一个需要4G内存的MySQL进程可以通过合并两个进程组来实现。Cgroup可以限制每个进程组使用资源的上限,也可以保证进程组之间相互隔 离。还有一点是,这种资源管理方式是可能造成碎片的,例如向16个进程组每个组里都分配一个内存256M的MySQL进程,这时总共才占用4G内存,服务 器上还有44G空闲内存,但此时已经无法分配出一个内存4G的MySQL进程了,这个问题可以通过Buddy System来解决。
资源调度
目前系统中支持三种规格的用户:
第一种是数据量和流量比较小的用户,例如博客站点、小应用以及开发中的应用。多个小用户可以共享同一个MySQL实例,每个用户一个库,单机可以支持几百到上千个小用户,但文件数量过多会对系统性能有不利的影响。
第二种是中等规模的用户,每个用户独占一个MySQL实例,每个实例占用的内存从256M到32G不等。用户的内存空间和磁盘空间也是可以调节的,当前机器满足不了用户对资源的要求时,可以迁移到资源有空闲或者更高配的服务器上。
图3通过实例迁移实现资源调度
第三种是需要分库分表的用户,用户可以占有多个独立的MySQL实例。这些实例可以同其他实例共存在同一台物理机上,也可以因为业务数据量规模的增长每个实例独占一台物理机。
用户的规格可以在创建的时候指定,也可以通过迁移工具升级或降级。我们使用了集团中间件团队开发的愚公系统,这是一个全量复制结合bin log分析进行增量复制的工具,可以实现在不停机的情况下动态扩容、缩容和迁移。目前,用户规格的升级和降级需要在控制台上触发,将来,我们希望可以基于 用户过去一段时间数据库使用情况的统计信息进行自动化的调度。
资源隔离
当多个用户共享同一个MySQL实例,或者是多个MySQL实例共享同一台物理机时,资源隔离显得尤为重要。例如某用户执行了一条IO操作非常多的SQL 语句,例如没有为字段设置索引造成在一张大表上进行全表扫描,会严重影响其他用户的体验。目前我们采用在数据库服务器上用Cgroup限制MySQL进程 资源,以及在proxy服务器端限制QPS相结合的方法进行资源隔离。
第一种方法是,是通过建立进程组,利用Cgroup的cpuset、memcg以及blkio子模块分别限制用户的MySQL进程最大可以使用的CPU使用率、内存和IOPS。这种方法适用于多个MySQL实例共享同一台物理机的情况。
第二种方法,是通过在数据库端部署的agent服务器分析MySQL进程的slow query log,采集和汇总用户最近执行的SQL语句的开销,并定期将信息反馈到controller服务器,controller服务器将数据同用户的配额进行 比较,如果明显超出,会通知proxy端通过增加延迟的方法去限制用户的QPS,达到了减小该用户消耗的系统资源的目的。这种方法比较适用于多个用户共享 同一个MySQL实例的情况,因为无法使用Cgroup进行进程间的限制。
数据安全
用户和企业的安全部门都会比较关心数据的安全问题,我们实现了多种方法保证用户数据的安全性:
- 支持SSL连接,proxy服务器实现了完整的MySQL客户端/服务器协议,可以与客户端之间建立加密连接。
- 通过白名单来设置允许访问数据库的IP地址列表,用户可以把白名单配置成应用服务器的地址,增加账号的安全性。
- Proxy服务器会把用户所有的数据库操作记录到日志分析服务器,安全部门可以定期导出日志文本,扫描检查安全漏洞。
- Proxy服务器可以根据安全部门的要求拦截各种类型的SQL语句,例如全表select *的语句、结果条数超出限额的语句等。
后期,我们还会保留MySQL实例的bin log和slow query log,这样用户在误操作删除数据又没有备份的情况可以通过bin log工具恢复数据,后台会定期运行slow query log分析工具,对用户SQL执行过程中索引使用情况、IO操作数量等进行分析,指导用户改进SQL语句。
结束语
在工程实践中,我们坚持着不去重复发明轮子的原则,充分利用开源的、成熟的技术和工具。例如我们在Erlang的网络编程框架上实现高性能的proxy服 务器,基于RabbitMQ实现消息中间件,使用ZooKeeper管理服务器心跳,也充分利用了集团内部成熟的数据备份、迁移、扩容/缩容方案及其他 bin log工具。这一原则使得我们可以将有限的资源关注在降低成本和改善用户体验上。
http://blog.csdn.net/ywh147/article/details/8954625
相关推荐
通过这次报告的分享,可以看出构建低成本和高性能MySQL云架构需要综合考虑多方面因素,并借助于先进的技术和合理的架构设计来实现。这不仅对于淘宝这样的大型电商平台具有重要意义,也为其他企业提供了宝贵的参考...
【低成本和高性能MySQL云架构探索】的议题主要围绕着如何在保证数据库服务质量的同时,降低运维成本和提升系统性能。此话题对于架构师来说至关重要,因为这涉及到如何有效地管理和优化大型互联网公司的数据库基础...
在过去一年时间里,我们(阿里集团核心系统数据库团队)在MySQL托管平台方向做了大量工作,设计和实现了一套UMP(UnifiedMySQLPlatform)系统,提供低成本和高性能的MySQL云数据服务。开发者从平台上申请MySQL实例资源...
【MySQL 数据库实践】 在构建高性能的网站时,MySQL数据库扮演着至关重要的角色...总的来说,高性能网站的MySQL数据库实践需要综合考虑硬件配置、内存管理、I/O优化和数据库调优策略,以实现最优的系统性能和稳定性。
MySQL是一个广泛使用的开源关系型数据库管理系统,因其低成本、高性能、可扩展性以及稳定性而备受青睐。在分布式系统环境中,数据库同步是确保多节点间数据一致性和高可用性的重要手段。本文将深入探讨基于MySQL的...
在京东云数据库架构实践中,我们深入探讨了云环境中数据库的关键设计和实现,这对于任何希望优化其数据基础设施的架构师和数据库专业人士来说都是极其重要的。京东作为国内领先的电商平台,其数据库架构的设计与实施...
移动云数据库RDS是针对企业需求设计的一种云数据库服务,其架构和实现旨在提供高可用性、高性能和易管理性。2019年,移动云数据库RDS项目启动,基于Kubernetes(k8s)和容器技术进行构建,旨在实现云原生的数据库...
在过去一年里,我们在MySQL托管平台方向做了大量工作,设计和实现了一套UMP(Unifield MySQL Platform)系统,提供低成本和高性能的MySQL云数据库服务。开发者从平台上申请MySQL实例资源,通过平台提供的单一
所以利用更多的低成本的普通pc服务器是我们接下来所要讨论的,我们需要在低成本 的环境下,保证数据的完整性,一致性,高可用性与高性能。而mysql-mmm就为我们带 来了一个优秀的解决方案,下面的文档会带领我们一...
- **MySQL**:版本为3.23.58-nt,是一款开源的关系型数据库管理系统,因其轻量级、高性能和低成本优势,特别适合中小型企业及互联网应用。 ### 安装与配置 - **Oracle**:默认安装目录为C:\ORAWIN95,各种实用程序...
本资料“计算机软件-编程源码-用Delphi开发低成本高性能的数据库应用系统.zip”正是针对如何利用Delphi进行此类开发的一份详细资源。 首先,Delphi的集成开发环境(IDE)提供了丰富的组件库,如VCL(Visual ...
MySQL以其高速、低成本、易用性、可移植性以及丰富的接口而受到青睐。其安全性高,支持多用户连接,并且提供多种工具进行数据库管理,如命令行工具`mysql`和图形界面工具MySQL Workbench,后者提供数据库设计、SQL...
总的来说,MySQL数据库集群是一种有效应对高流量和高可用性需求的解决方案,通过合理的集群设计和负载均衡策略,能够在保持低成本的同时,提供可靠且可扩展的数据库服务。随着开源社区的持续发展,MySQL的集群技术和...
Oracle数据库则是一款企业级的、高性能的数据库解决方案,广泛应用于大型企业和组织。Oracle提供了强大的ACID(原子性、一致性、隔离性、持久性)事务处理能力,并支持复杂的SQL查询和存储过程。Oracle数据库的特色...
MySQL 的特点包括开放源代码、小巧易用、高性能低成本、高可靠、高速发展、支持所有平台、广泛应用于嵌入式、网站应用、企业级应用等。 MySQL 的技术进展包括:从 MySQL 3.23 开始支持外键(InnoDB),从 MySQL ...
- **体积小、速度快、总体成本低、开放源代码**:这些特点使得 MySQL 成为许多企业和个人用户的首选数据库系统。它不仅易于安装和配置,而且在性能上表现优异,特别是在处理大量数据时仍能保持较高的运行速度。 - **...
1.2 MySQL数据库:MySQL是开源、轻量级的数据库系统,因其高效、易于管理和低成本而受到青睐。在云环境中,MySQL可以快速扩展,适应高并发和大数据量的需求,尤其适合互联网和云服务场景。 二、转型的原因 2.1 ...
MySQL数据库的缺点包括功能略有不足、保障体系成熟度不如Oracle、BUG更新不如Oracle、并发机制较粗、软件成本低、运维成本依赖数据规模等。 在选择存储引擎时,需要考虑业务需求、数据规模、读写频率等因素。选择...