您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
   
 
 
     
   
 订阅
  捐助
MySQL数据库读写分离中间件Atlas
 
作者:朱超 来源:极客头条 发布于 2017-2-28
   次浏览      
 

Atlas是由奇虎360公发的基于MySQL协议的数据库中间件产品,它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基础上,修改了若干Bug,并增加了很多功能特性。目前该产品在360内部得到了广泛应用,覆盖80%以上的MySQL业务,每天读写量达数十亿次,于GitHub开源后,业界几十家公司将其应用于生产环境。

Atlas项目源代码托管地址https://github.com/qihoo360/atlas

产品研发背景

该项目最早在2012年提出,主要为了解决两个问题:

一是业务程序员对数据库细节关注过多。在没有中间件的情况下,应用程序直接连接MySQL的主从库,需要在配置文件中指定主从库的IP和端口,并由业务程序员自行决定将写语句和读语句分别发往主库和从库,在数据量较大的情况下还需要自行管理分库分表等技术细节,使得业务程序员负担较重。

二是DBA运维工作不方便。数据库宕机是家常便饭,在需要切换或上下线数据库时,DBA需要协调业务程序员修改配置,运维操作也会对业务造成一定干扰,影响DBA工作顺利进行。

我们希望能将业务与DB进行一定程度的隔离,使业务程序员尽量少关心DB的细节,可以专注于编写业务逻辑;另一方面DBA的运维操作尽量做到对业务无影响。如此则需要将读写分离、分库分表、平滑上下线DB等逻辑提炼出来,以公共组件的方式提供给以上两类人群使用。从形式上看有两种,一种是独立的中间件服务,另一种集成于客户端的LIB。前者优点是升级更新较方便,而且与语言无关,缺点是网络增加一跳,数据需要转发,性能可能不如LIB形式,后者优缺点正相反。经过权衡我们选择了前者,除以上考虑外还有部分原因是我们团队与各条业务线是独立的部门,要推动业务工程师升级LIB有相当的困难。

开始时调研了MySQL官方的MySQL-Proxy、阿里巴巴的Cobar、Amoeba、TDDL等产品,其中MySQL-Proxy更新缓慢,长期停留在Alpha版阶段,Cobar安装部署相对复杂,Amoeba不支持事务,TDDL未完整开源。最终我们选择了MySQL-Proxy进行二次开发。

技术架构

部署架构

Atlas一般搭配LVS使用,客户端通过LVS访问Atlas,以避免单点故障,当然也可以使用Keepalived等。Atlas后面挂接MySQL的一主多从集群,需要注意的是主从同步需要DBA预先配置好,Atlas只涉及客户端与DB间的网络交互,DB与DB间的通讯与Atlas无关。

图1 读写分离架构

Atlas会把客户端发来的SQL语句根据读写分别路由到主库和从库上,对于有多台从库的情况,还会根据加权负载均衡策略决定选择哪台从库来执行每条读语句。

线程模型

Atlas的线程模型与Memcached相似,都是由一个主线程和若干个工作线程组成。主线程负责监听客户端的新连接,工作线程在系统启动时即创建完成,并监听管道读端的读事件。当有客户端连接到来时,主线程将客户端的IP和端口等信息封装成一个CON结构,然后选择某个工作线程来处理该客户端的请求。选择的方法可以是Round-Robin方式,也可以根据各个线程的负载情况选择负载最轻的线程(可以粗略认为待处理队列最短即为负载最轻)。主线程选定工作线程后,将CON结构放入该线程对应的待处理队列,然后向相应管道的写端写入一个字节(字节内容无所谓),则工作线程会收到管道读端的读事件,并从队列中取出CON结构,进行下一步处理。当然也可改用Linux的新系统调用eventfd实现对工作线程的唤醒,性能比管道更高。

图2 线程模型

两个经典技术问题

字符集

MySQL支持多种字符集,字符集状态与会话(连接)绑定,即各个连接上的字符集互不相干。而Atlas拥有连接池,要求实现连接复用,这就不可避免会导致字符集混乱。

图3 访问架构

如图3所示,客户端发来SET NAMES UTF8语句,Atlas从连接池里取出一个空闲连接(连接1),在连接1上执行该语句后,将连接1放回连接池。客户端再发来一条SELECT语句,Atlas又从连接池里取出一个空闲连接(连接2),连接2大概率与连接1不是同一个连接,在连接2上执行SELECT语句,而连接2并未设置UTF-8字符集,因此造成乱码。

图4 访问架构

解决方案:Atlas记录每个客户端和每个连接的当前字符集状态(以一个正整数表示即可)并进行相关修正。当客户端发来SQL语句时,Atlas会检查该语句是否要设置字符集(SET NAMES或SET CHARACTER_XXX)。如某个客户端发来SET NAMES UTF8,Atlas从连接池内取出连接1并执行该语句,执行成功后,将该客户端和连接1的当前字符集均置为UTF-8。之后该客户端发来SELECT语句(或其他非SET类语句),Atlas从连接池内取出连接2,然后比较客户端的当前字符集(上步已设置为UTF-8)和连接2的当前字符集(假定为GBK),若一致则直接执行,若不一致则在SELECT前插入一条SET NAMES UTF8,将两条语句一起发给MySQL,第一条语句起到将连接2的字符集修正为UTF-8的作用,然后再执行SELECT则不会乱码。当然也可以进一步优化,就是由Atlas直接返回SET类语句的结果(OK)给客户端,省去一次与MySQL的交互过程。

自验证

图5 连接认证

图5是MySQL的连接认证示意图。

1.Connect阶段,客户端建立与MySQL的TCP连接;

2.HandShake阶段,MySQL向客户端发送握手包,其中携带多项信息,如服务端的特性标志、字符集等,此处我们主要关心的是其包含的20个字节的随机串;

3.Auth阶段,客户端将握手包内的随机串取出,与自身的密码一起执行以下运算SHA1( password) XOR SHA1( “20-bytes random data from server” SHA1( SHA1( password ) ) ),得到一个加密串,加上客户端的用户名、特性标志、字符集等附加信息,组成认证包发给MySQL。

4.Auth-Result阶段,MySQL通过在mysql.user中保存的该用户名对应的密码,也执行同样的运算得到一个加密串,并与认证包中的加密串对比,若相同则认为密码正确,返回结果OK给客户端,否则返回ERR拒绝连接。

返回OK后应用层连接即建立完毕,接下来客户端向MySQL发送SQL语句,并从MySQL接收语句的执行结果,然后再发送下条语句……直至有一方断开连接为止。

图6 Atlas连接访问工作原理

图6是1.x版本的Atlas的工作过程。

可以看到,在连接认证阶段,Atlas简单地透传客户端与MySQL双方的通讯包。初看似乎并没有问题,但考虑到Atlas后面挂接的是一主多从多台MySQL时,情况就变得比较复杂。

客户端向Atlas建立连接时,Atlas需要选择转而向哪台MySQL建立连接。以最简单的一主一从为例:若Atlas向主库建连接,则从库上没有连接,无法实现读写分离;若向从库建连接,则问题更严重,因为主库上没有连接,所以写语句无法执行。那么能不能同时向两台MySQL建连接呢?问题在于两台MySQL都会发送握手包,而客户端遵循MySQL协议,它不可能一次接受两个握手包……

在1.x中,我们使用了一个取巧的办法,即在主库上预留一定数量的连接,比如32个。客户端向Atlas建立连接时,首先检查主库上的连接数是否已经达到32个,若未达到则向主库建连接,若已达到则向从库建连接。这样既保证了写语句可以在主库上执行,又使得读语句可以在从库上执行,从而正确实现读写分离。这个办法有几个潜在的问题:

1. 若有多于32个客户端同一瞬间发送写语句,则主库上连接数将不够用,当然也可以让某些客户端阻塞等待其他客户端让出连接来部分解决;

2. 无法支持长连接;

3. 在主库连接数达到32个之前,仍然无法读写分离。

仔细分析以上情况,可以得知,其本质原因是Atlas需要依赖客户端的连接动作转而向MySQL建连接,因此能建立连接的数量最大不超过客户端的Connect次数,这就极大地制约了Atlas作为中间件的灵活性。为了摆脱这一束缚,就要求Atlas能自主决定何时、向哪台MySQL、建立多少个连接。实现该特性的前提是,Atlas必须知悉客户端的用户名和密码,因为从1.x的交互图上可知,Atlas透传客户端的认证包给MySQL,而认证包内只有加密串而没有密码明文,也不可能反解(否则我们就破解了MySQL的加密协议)。

图7 Atlas 连接访问工作原理

图7是2.x版本Atlas的工作过程。

用户名和密码事先已经作为配置在Atlas启动时加载进来(当然也可以通过Atlas的管理接口进行动态的增删改查)。当客户端来连接Atlas时,Atlas自行产生一个握手包(包含20字节随机串)发给客户端,然后接收客户端发来的认证包,根据配置的用户名和密码进行加密计算并检查结果,根据结果正确与否返回OK或ERR给客户端,从而完成客户端的连接认证工作。客户端发来SQL语句时,Atlas检查连接池中是否有空闲连接,若有则直接使用,若没有则根据配置的用户名和密码自行向MySQL建立新连接,然后供该语句使用。

此方案的优点:真正完全的读写分离,支持长连接,连接按需建立,连接数随并发度上升而增加,随并发度下降而减少(可以依靠MySQL的wait_timeout,也可以由Atlas监控连接的空闲时间)。

小结

从以上内容可以看出,MySQL中间件产品的设计与开发需要对相关协议有比较深入的了解,且因MySQL数据库软件自身的升级,协议还可能随之改变。限于篇幅,还有不少功能点不能一一细述,有兴趣者可查阅项目源码托管平台上的资源。

   
次浏览       
相关文章

基于EA的数据库建模
数据流建模(EA指南)
“数据湖”:概念、特征、架构与案例
在线商城数据库系统设计 思路+效果
 
相关文档

Greenplum数据库基础培训
MySQL5.1性能优化方案
某电商数据中台架构实践
MySQL高扩展架构设计
相关课程

数据治理、数据架构及数据标准
MongoDB实战课程
并发、大容量、高性能数据库设计与优化
PostgreSQL数据库实战培训
最新活动计划
LLM大模型应用与项目构建 12-26[特惠]
QT应用开发 11-21[线上]
C++高级编程 11-27[北京]
业务建模&领域驱动设计 11-15[北京]
用户研究与用户建模 11-21[北京]
SysML和EA进行系统设计建模 11-28[北京]

MySQL索引背后的数据结构
MySQL性能调优与架构设计
SQL Server数据库备份与恢复
让数据库飞起来 10大DB2优化
oracle的临时表空间写满磁盘
数据库的跨平台设计
更多...   

并发、大容量、高性能数据库
高级数据库架构设计师
Hadoop原理与实践
Oracle 数据仓库
数据仓库和数据挖掘
Oracle数据库开发与管理

GE 区块链技术与实现培训
航天科工某子公司 Nodejs高级应用开发
中盛益华 卓越管理者必须具备的五项能力
某信息技术公司 Python培训
某博彩IT系统厂商 易用性测试与评估
中国邮储银行 测试成熟度模型集成(TMMI)
中物院 产品经理与产品管理
更多...