【开源访谈】网易开源数据库中间件 Cetus 如何让 MySQL 更强大?
电商系统中,随着业务量的增大,读写 QPS 越来越高,单节点 MySQL 实例压力越来越大,单纯的对服务器硬件升级已经无法满足生产环境的需要,对数据分片增加多个节点,降低单节点 MySQL 实例的压力成了必然选择。传统的分片是通过 DAO 层进行的,但是 DAO 层对数据分片存在诸多问题:
从业务角度看,配置修改需要重启服务,代价巨大;需要对分片结果集进行处理,业务逻辑愈加复杂;功能相对简单。
从数据库运维角度看,配置管理的统一化难度较大;DB的升级、迁移等操作复杂。
因此 MySQL 数据库中间件应运而生,解决了上述 DAO 层的诸多问题。MySQL 数据库中间件为业务提供了统一的入口、对业务透明,提供了读写分离、分片、丰富的路由策略,以及其它较为实用的统计、管理、鉴权等功能。
目前市面上已经有 OneProxy、TDSQL、MyCat、360 Atlas 等出色的数据库中间件,对于如何选型,不同公司会有不同的考虑,当然也有公司会选择自研,网易电商乐得在实际生产中就根据需要研发了自己的中间件 Cetus,并于不久前开源。
项目地址:
Cetus 主打稳定、高性能和对开发友好,并以 OneProxy 等出色中间件为追赶目标,那它的具体设计思路与能力如何?开源中国采访了 Cetus 负责人@王斌,请他从项目背景、设计思路、研发经验与未来计划等几个方面为读者全面解读 Cetus。本文由采访整理而成。
嘉宾介绍
王斌,网易高级技术专家,爱好开源,tcpcopy 和 Cetus 主要开发人员之一,希望为中国开源做点贡献,目前主要负责 Cetus 项目,关注领域包括分布式数据库、网络与机器学习。
项目背景
乐得作为网易的电商系统,近年来业务不断发展,随之而来的是数据库数据量和访问量的不断变大。当数据量达到一定量级,尤其是写请求过于频繁时,传统 MySQL 架构很难支持乐得的大业务,因此我们考虑用水平切分的方式进行优化,以降低单个库、单个表的压力。
已有的开源分布式 MySQL 中间件具有不稳定、对开发不友好等问题,很难直接采用,于是我们决定自主开发一款分布式事务功能的 MySQL 中间件,我们有几个目标想要达到,包括高可用、高性能、读写分离、分库等。自己开发有个好处就是自研可控,可以按照实际需求添加新功能,并且可以及时修复 bug。
这一次将 Cetus 开源也是想跟同行一起将它打造成一款出色的 MySQL 中间件,把 MySQL 后端集群整合成一个强有力的分布式数据库。
让 MySQL 更加强大
先介绍一下 Cetus 这个名字的意思,Cetus 这个英文翻译成中文是“鲸鱼座”,大家知道 MySQL 官方 logo 是海豚,鲸鱼和海豚同属于一个类别,而鲸鱼体型更大点,把这个项目命名为 Cetus,一方面是想让 MySQL 更加强大的意思,另一方面鲸鱼座代表了我们有着胸怀宇宙的情怀,想把 Cetus 做得更好、更长久。
Cetus 专注于性能、稳定和分布式事务,目标是做一款可以媲美 OneProxy 和 TDSQL 等商业软件的中间件。
下边拿 Cetus 和一些知名的数据库中间件或者NewSQL一起做个小分析:
OneProxy 是商业软件,在稳定性和性能方面远胜其它开源中间件,它一直是我们追赶的对象。
TiDB 代表了 NewSQL,是为大数据设计的,但由于成本较高,在可以使用 MySQL 的地方不建议使用 TiDB。
TDSQL 是腾讯开发的数据库中间件,为腾讯云服务,它在 MySQL XA 分布式事务方面进行了很多探索,为我们的分布式事务处理提供了很多思路。
MyCat 功能较为复杂,细节方面还待改善(如算法没有优化、存在很多使用上的坑),用户的抱怨比较多,与优秀的数据库中间件差距较大。
至于360 Atlas,它是一个长期没有更新的中间件,设计、稳定和性能不佳,导致了很多用户放弃使用。
……
了解到其它开源和商业数据库中间件的设计思路和存在的问题,我们在 Cetus 中大量借鉴和改进,这成了 Cetus 的优势。相比其它开源数据库中间件,Cetus 会更加贴近用户,兼顾开发和整体效率,同时规避了影响数据库中间件稳定和性能的坑。主要特点有:
自主开发的解析器,无需依赖第三方解析器,更新可控
异步处理,无任何阻塞,类似 Nginx
并行处理,对多个后端并行访问,减少延迟
tcp stream 处理,tcp stream 可以分解大响应处理过程,从而可以公平处理各个外部事件,同时也解决了内存炸裂问题
分布式事务支持
对开发无感知,开发无需去了解这个事务是不是分布式事务,像MyCat、DRDS 等中间件需要用户显式去指定这个事务是不是分布式事务,这对开发人员不是很友好
分布式事务深度优化,继承了腾讯 TDSQL 的不少优良特点
紧跟 MySQL 趋势
在重置 MySQL 连接方面,MySQL 5.7 开始支持 reset conn,而 Cetus 已经采用了 reset conn 代替 change user,以降低 MySQL 的 CPU 开销
支持 MySQL Group Replication,集群产生新的写节点,Cetus 会及时更新写节点信息,实现服务高可用
利用GTID tracking,自动实现一致性读(正在开发中)
设计思路与技术细节
Cetus 位于应用程序与 MySQL 数据库之间,作为前端应用与数据库的通讯。其中,前端应用连接 LVS 节点,LVS 节点映射端口到多个 Cetus 服务,后者通过自身的连接池连接到后端的数据库。
整体网络架构如下图所示:
Cetus 主要的功能模块包括以下五个部分:
读写分离
分库
SQL 解析
连接池
管理功能
各个功能模块间的交互关系如下:
其中,SQL 解析模块为后续读写分离和数据分片等功能解析出 SQL 类型、表名和查询条件等关键信息;连接池模块是自维护连接池,支持 Cetus 根据需求查询和检测后端,维护连接数,具有高效连接共享性、事务与 Prepare 的前后端绑定功能和热点连接重用与连接等待机制;管理功能模块通过用户在管理界面输入,独立认证并转到下一状态,给用户回复状态查询结果或调整参数。
Cetus 的整体工作流程:
Cetus 读取启动配置文件和其他配置并启动,监听客户端请求;
收到客户端新建连接请求后,Cetus 经过用户鉴权和连接池判断连接数是否达到上限,确定是否新建连接;
连接建立和认证通过后,Cetus 接收客户端发送来的 SQL 语句,并进行词法和语义分析,对 SQL 语句进行解析,分析 SQL 的请求类型,必要时改写 SQL,然后选取相应的 DB 并转发;
等待后端处理查询,接收处理查询结果集,进行合并和修改,然后转发给客户端;
如收到客户端关闭连接的请求,Cetus 判断是否需要关闭后端连接,关闭连接。
如下图所示:
Cetus 目前分为两个版本,分别是读写分离和分库版本,这主要有两个考虑:
分库解析器和读写分离解析器很不一样
Cetus 是基于 MySQL proxy 基础上做的,由于原先代码架构不是很好,不易统一,随着以后代码架构的不断完善,两个版本统一问题会最终得到解决
在读写分离版本中,通过对 SQL 进行解析,根据 SQL 特点和 GTID tracking 智能选择路由主库或从库,从而实现读写分离,减少主库的压力,同时通过相关策略,保证从库上进行负载均衡。
而分库的思想是参考了 Fabric 和 OneProxy,采用了 vdb 的思想,一个 vdb 代表一个具体的分片规则,Cetus 确保同一个 vdb 内可以 join,不同 vdb 相互隔离,兼顾垂直拆分和开发对 join 的需求,不同 vdb 之间可以走分布式事务。
但 Cetus 基于以下考虑,不支持分表:
MySQL 分区性能会越来越好
Oracle 分区功能强大,而 MySQL 是 Oracle 公司的,并且 MySQL 5.7 以后的分区性能越来越好。
我们电商系统没有用到分表功能
我们预测,未来 MySQL 分区会逐渐取代分表,类似 Oracle 原先走的路线,鉴于这个判断和紧跟 MySQL 趋势,乐得电商放弃了分表功能开发。
研发过程中暴露的问题
在项目开发过程中,我们遇到了一些难点与坑,并且有相应的解决思路,这里与大家分享一下。
构造分库测试环境
我们改造了 tpcc、Zabbix 等软件,以支持分布式数据库使用场景。改造 tpcc 是为了测试分库性能和分布式事务性能;改造 Zabbix,是为了让分库版本尽快用起来,尽早去发现问题。
线上规避问题
线上如果出大的问题,开发是很难接受的,因此确保线上尽量不出大问题,是遇到的最大挑战。为了更好地解决此问题,我们专门优化了 tcpcopy,使其更加适合流量测试。
目前80%以上的线上潜在问题都被流量测试所发现。
分布式事务
MySQL 在这方面是不太完美的,一旦 MySQL 在分布式事务支持方面出问题,是需要去补救的。
在测试过程中,我们发现 MySQL 在分布式事务处理方面有如下两大问题:
1、只有主库存在悬挂事务
MySQL 主库已接受到 xa commit 通知,xa commit 未完成前,kill -9 杀掉 MySQL 主库,再启动 MySQL 主库,主库出现悬挂事务,而从库该分布式事务已提交。主库此时需要执行 xa commit 语句,提交分布式事务,这个操作同步到从库后,会导致从库 SQL 应用进程报错,提示找不到该分布式事务。
2、只有从库出现悬挂事务
Cetus 向后端分片发送 xa prepare,分片 MySQL 主库接收到 xa prepare,xa prepare 未完成前,kill -9 杀掉 MySQL 主库,再启动 MySQL 主库,xa 事务已回滚,主库未出现悬挂事务;从库出现悬挂事务。这种情况下,从库需要回滚 xa 事务,才能保证数据的一致性。
以上两种情况,主库的 xa 事务状态,跟 binlog 记录的事务状态不一致。在 MySQL 官方文档找到解释,MySQL 异常关闭,有可能导致数据库状态和 binlog 不一致。这些 bug,在非正常关闭 MySQL 时才出现,正常关闭 MySQL 不会出现这个问题。如果出现 xa 事务悬挂,可以用 Cetus xa 悬挂处理工具自动处理。
tcp stream 改造
由于 MySQL 协议是有状态的协议,Cetus 是纯异步的,再加上 tcp stream,处理过程就变得异常复杂。我们采用的策略是让线上运行禁止 tcp stream 功能的 Cetus,而流量测试环境使用 tcp stream 的 Cetus,这样就很容易去发现 tcp stream 的很多问题。
网易乐得目前使用 Cetus 已经一年多了,线上没有遇到大的问题,而在测试的时候遇到了原先 MySQL proxy 带过来的一个问题,因为设置 max-open-files 过小导致 CPU 100%,也正因为这个问题,使我们坚决部署了 tcpcopy 流量测试环境。
展望
我们对 Cetus 的短期计划是让用户大量用起来,并完成基于GTID tracking一致性读的功能, 对MGR 的完善支持和扩容工具的完善。
长期计划是在不断成长中,将 Cetus 打造成类似 OneProxy 的高性能数据库中间件,支持多进程、query cache、ssl与更好的安全过滤等,为MySQL保驾护航。