抖音技术能力大揭密!钜惠大礼、深度体验,尽在火山引擎增长沙龙,就等你来! 立即报名>> 了解详情
写点什么

利用 Mycat 中间件实现 RDS MySQL 的分库分表及读写分离功能

2019 年 11 月 18 日

利用Mycat中间件实现RDS MySQL的分库分表及读写分离功能

随着移动互联网的兴起和大数据的蓬勃发展,系统的数据量正呈几何倍数增长,系统的压力也越来越大,这时最容易出现的问题就是服务器繁忙,我们可以通过增加服务器及改造系统来缓解压力,然后采用负载均衡、动静分离、缓存系统来提高系统的吞吐量。然而,当数据量的增长达到一定程度的时候,增加应用服务器并不能明显地提高系统的效率,因为所有压力都会传导到数据库层面,而大多数系统都是用一个数据库来存储和管理系统数据的,因而一个支持高性能、高并发并且易于扩展的数据库系统变的尤为重要。


Amazon RDS 是 AWS 上托管的关系型数据库服务,目前支持业界主流的 MySQL、Oracle、SQL Server、PostgreSQL、MariaDB 引擎及 AWS 提供的 Aurora,通过多可用区主备及读副本等技术,能够支持绝大部分的应用场景。


对于更大容量的数据库,可以使用 Amazon Aurora,Aurora 是一个关系型数据库引擎,结合了高端商用数据库的速度和可用性,同时还具有开源数据库的简单性和成本效益。Amazon Aurora 的设计与 MySQL 5.6 及 PostgreSQL 9.6.1 兼容,它提供的性能比同一硬件上运行的标准 MySQL 最多高达五倍,比 PostgreSQL 最多高达二倍。


下表是单个数据库实例能够支持的存储容量大小:


col 1col 2
RDS数据库引擎存储容量
MySQL6TB
Oracle6TB
PostgreSQL6TB
MariaDB6TB
SQL Server4TB
Aurora64TB


不过由于 Aurora 目前并未在所有 region 提供,比如中国北京,同时支持的引擎有限,对于中国区用户及使用其他数据库引擎的用户,不得不考虑其他的解决方案。随着近年来海量数据存储、并行计算、异构数据互联等一系列新技术在市场上不断出现。相信数据库行业的很多从业者都对传统关系型数据库的单点故障及容量问题头疼不已,而数据库分库分表也早已成为解决此类问题的基础。


本文要介绍的 Mycat 是一款面向企业级应用的开源数据库中间件产品,支持事务、ACID,能够对接 Oracle、MySQL、DB2、SQL Server、MongoDB、SequoiaDB 等数据库,支持透明的读写分离机制,支持各种 MySQL 集群,包括标准的主从异步集群、MySQL Galera Cluster 多主同步集群等,通过大表水平分片方式支持 100 亿级大表的分布式存储和秒级的并行查询能力,内建数据库集群故障切换机制,实现自动切换,可满足大部分应用的高可用性要求。


配置步骤:

第一步 创建 RDS 数据库实例

创建一个 RDS 将会使用的参数组 mycat



在分库分表的情况下,Mycat 可以通过如下几种方式保证自增主键的全局唯 一:


  1. 本地文件方式


在 sequence_conf.properties 文件中设置主键的当前值,最小值和最大值


  1. 数据库方式


在其中一个 MySQL 节点中建立一张表,存放 sequence 的名称,当前值,步长 等信息,并通过存储过程修改更新信息


3. 本地时间戳方式


  1. 注解方式


本例使用第二种方式,为了使存储过程能够顺利执行,需要修改参数组的 log_bin_trust_function_creators 为 1



此外,可以按需设置时区及大小写不敏感




接着创建两台 RDS MySQL 实例,注意需要在创建的时候选择 mycat 参数组



本例使用 MySQL 5.6.34 版本,开启 Multi-AZ 及自动备份功能,并且为每个 MySQL RDS 实例创建一个读副本做读写分离



数据库 endpoint 如下:


mysql1


mysql1.cbqbpwftrsrj.rds.cn-north-1.amazonaws.com.cn

mysql1-read-replica


mysql1-read-replica.cbqbpwftrsrj.rds.cn-north-1.amazonaws.com.cn

mysql2


mysql2.cbqbpwftrsrj.rds.cn-north-1.amazonaws.com.cn

mysql2-read-replica


mysql2-read-replica.cbqbpwftrsrj.rds.cn-north-1.amazonaws.com.cn

第二步 安装配置 Mycat

本例使用 Cento 6.7 创建 EC2


  1. 安装 epel 及 mysql 源


rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm


rpm -ivh https://repo.mysql.com//mysql57-community-release-el6-9.noarch.rpm


  1. 修改/etc/yum.repos.d/mysql-community.repo 如下



  1. 安装相关软件包


yum update -y


yum install mysql-server java-1.8.0-openjdk.x86_64 vim wget -y


  1. 下载并安装 Mycat


wget http://dl.mycat.io/1.6-RELEASE/Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz


tar xzvf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz


  1. 配置 Mycat 中间件


5.1 vim mycat/conf/server.xml


该配置文件主要用于创建 mycat 用户及 mycat 的系统参数设置,这里只列出保证 mycat 正常工作的参数配置,其中还有很多优化项需要读者根据需要自行修改,具体可以参考文末的参考书及链接



其中 sequenceHandlerType 为 1 表示使用数据库方式实现自增主键


5.2 vim mycat/conf/schema.xml


该配置文件主要用于配置逻辑库、表、分配规则、分配节点及数据源,同样这里的配置并不包括参数优化在内



上面配置有几个地方需要注意


  1. 分片 dn1 和 dn2 分别对应于 mysql1 中的 db1 和 mysql2 中的 db2,需要事先登入这两台 RDS 实例,并分别创建 db1 和 db2 数据库

  2. user 表会在两台 RDS 实例中分片,基于 id 字段,使用 mod-long 算法进行分片

  3. orders 表作为 user 表的子表,使用 ER 关系表进行分片,是 Mycat 中避免跨库 join 的其中一种方式,适用于有父子关系的两张表,这里 orders 表中的 user_id 字段对应于 user 表中的 id 字段,当需要对 orders 表进行插入操作的时候,Mycat 会对 user_id 应用父表的 mod-long 算法找到具体的分片并插入,这样 order 表和 user 表基于 user.id=orders.user_id 的 join 操作可以在每个分片中进行,无需跨库

  4. country 表的 type 为 global,设置为全局表,也就是在每个 RDS 实例中均有完整的 country 表信息,是 Mycat 中另外一种避免跨库 join 的方法,适用于内容较为固定,数据量不大的字典表

  5. dataHost 标签中的 balance 为 3,实现读请求完全到 readHost 上进行

  6. dataHost 标签中的 switchType 为-1,意思是当 writeHost 故障的时候不进行切换,这是针对 RDS 特有的配置,由于 RDS 已经启用了 Multi-AZ 的功能,主库故障会自动切换到 standby 实例,无需 Mycat 切换到某台 readHost

  7. user,password 为具体 RDS 实例的登入用户账号

  8. user 表和 orders 表设置了 autoIncrement=true 主键自增

  9. mycat_sequence 表用于存储其他表的自增主键信息


5.3 vim mycat/conf/rule.xml


该配置文件主要用于定义分片算法,由于本例使用两台 RDS 实例,需要将 mod-long 分片算法的 data nodes 参数设成 2



5.4 vim mycat/conf/sequence_db_conf.properties


该配置文件用于设置主键自增表的自增信息,这里将 user 表和 orders 表的自增信息存到 dn1,也就是 RDS mysql1 中,注意这里的 USER,ORDERS 需要大写



5.5 启动 Mycat,并建表


./mycat/bin/mycat start &


mysql –h 127.0.0.1 –u root –p –P 8066


show databases 可以看到定义的逻辑库 test



下面是具体的建表语句




下面设置 user 表及 orders 表的自增主键的当前值为 0,自增步长为 1



5.6 配置实现主键自增的存储过程


存储过程需要在具体的 RDS 实例上创建,在这里是 RDS mysql1


mysql –h mysql1.cbqbpwftrsrj.rds.cn-north-1.amazonaws.com.cn -u root –p



第三步 功能验证

  1. 登入 Mycat


mysql –h 127.0.0.1 –u root –p –P 8066 use test;


  1. 验证主键自增




  1. 验证 user 表在两台 RDS 实例中分片




  1. 验证 country 表为全局表,并且能够和 user 表做 join



在两台 RDS 实例上可以看到 country 表的全部内容




  1. 验证 orders 表的分片规则关联父表 user 表,即 orders 表中的 user_id 与 user 表中 id 字段相等的行存储在同一个 RDS 实例中,并且两张表能够 join




在两台 RDS 上查看到 user 表与 orders 表的存储关系




  1. 验证使用 ShareJoin 实现分片 join


如上两种方式本质上是通过全局表或者相同的分片规则规避分片 join,SQL 语句经过 Mycat 分发到各个 RDS 节点本地 join,然后在 Mycat 中进行结果的汇聚,如果两张表都比较大,不适合作为全局表并且表与表之间没有类似的父子关系时,有两种方式解决


  1. 增加冗余列,即人为在两张表中构建相同的两列,比如上例的 user.id 和 orders.user_id,然后基于这两列来分片

  2. 通过 ShareJoin 注解,ShareJoin 本质上是将一条 join 语句拆分成单表的 SQL 语句,然后把各个节点的数据汇集

  3. 登入 RDS mysql1,对 orders 表人为插入一条 user_id 为奇数的信息,使得 orders 表的分片规则与 user 表的出现



此时再使用 join 语句将会丢失刚刚插入的那一行,因为 RDS mysql1 在本地执行 join 语句时,本地 user 表中并没有 user.id=1 的条目



通过在 SQL 语句前加上 ShareJoin 的注解,实现跨分片 join 功能



笔者在实际使用过程中发现,ShareJoin 并不是总能够正常工作,怀疑可能是 bug 或者语句限制,不到万不得已,建议使用上面的两种方式来规避跨库 join,比如上面的语句如果只是取出某几列,ShareJoin 并不总能正确输出



另外还有一种 Mycat 支持的跨分片 join 技术是 catlet,也叫做人工智能(HBT), 主要是参考了数据库中的存储过程的实现方式,需要用户根据系统提供的 API 接口在代码中实现跨分片 join,具体可以参考文末的参考书中的内容


  1. 验证读写分离


修改 RDS 参数组 mycat,开启 general log



注意:开启 general log 会影响数据库的性能并占用存储空间,不建议在常规时间开启,这里只是用于验证


登入 Mycat,执行如下语句,可以看到在 15:42:09-15:42:29 的时间段内,一共执行了两次对 country 表的全表扫描,一次 user 表的全表扫描,和三次 user 表的单行查询,需要验证的结果如下:


  1. 由于 country 表是全局表,只会在一台实例上执行,所以两台 read-replica 中一共可以看到两条语句

  2. user 表是分片表,所以全表扫描会在每台 read-replica 中看到一条语句

  3. user 表的单行扫描会按照 Mycat 的分片规则分配到相应的 read-replica 中执行

  4. 所有语句不会出现在 mysql1 和 mysql2 写库的日志中






分别登入 mysql1,mysql2,mysql1-read-replica,mysql2-readreplica 执行 select * from mysql.general_log,查看 15:42:09-15:42:29 时间段内的日志


mysql1,mysql2 中没有执行的语句日志


mysql1-read-replica 中,可以看到两条 country 的全表扫描,一条 user 的全表扫描和 user 表 id 为 2 的查询语句,其中全表扫描的 limit 100 为 Mycat 自动添 加,可以通过配置修改



mysql2-read-replica 中,可以看到一条 user 的全表扫描和 user 表 id 为 1,3 的查询语句,其中全表扫描的 limit 100 为 Mycat 自动添加,可以通过配置修改



第四步 配置 Mycat 的冗余

  1. 设置 Mycat 开机自启动


vim /etc/rc.local,添加如下启动指令


sh /home/centos/mycat/bin/mycat start


  1. 根据需要设置 iptables 防火墙策略

  2. 创建 AMI,通过 AWS autoscaling-group,实现 Mycat 冗余及高可用,应用层对两台 MyCat 的负载均衡可以在应用层实现或者使用负载均衡器,由于这部分配置比较基础,此处不做详细介绍


最终拓扑图如下:



第五步 使用 Mycat-web 实现监控(可选)

Mycat-web 为 Mycat 提供了一个基于 Web 的监控平台,功能非常丰富,可以对 Mycat 实例,Mycat 所在机器的 JVM 以及具体的 MySQL 节点进行监控


  1. 安装启动 Mycat-web


本例使用一台独立的 EC2 安装,使用 Centos 6.7,配置 internet 可以访问


Mycat-web 依赖 zookeeper,需要先安装 zookeeper


wget http://mirror.bit.edu.cn/apache/zookeeper/stable/zookeeper- 3.4.9.tar.gz


cd zookeeper-3.4.9/conf


mv zoo_sample.cfg zoo.cfg


cd …/bin


./zkServer.sh start &


安装 Mycat-web


wget http://dl.mycat.io/mycat-web-1.0/Mycat-web-1.0-SNAPSHOT- 20170102153329-linux.tar.gz


cd ~/mycat-web/WEB-INF/classes


vim mycat.properties


zookeeper=localhost:2181(默认已经修改)


cd ~/mycat-web


./start.sh &


  1. 配置 Mycat-web


通过浏览器访问 mycat-web



添加 Mycat 节点




添加 JVM 节点





添加 MySQL 节点





接下来就可以通过 Mycat-web 查看系统的各项参数



目前有一个问题,Mycat-web 只能够收集到 read 的操作,所有 insert/delete/update 等写操作无法收集


通过 Mycat 服务端口 8066 登入一台 Mycat,执行一系列 select 及 insert 读写操作,退出后通过管理端口 9066 登入,查看日志发现所有 insert 写操作并未记录到日志中,因此可以确定不是 Mycat-web 的问题,而是可能由于 Mycat 本身配置不当或者由于 bug 导致写操作没有记录到日志中,已经在 github 上提交 issue,等待答复中





参考内容:


《分布式数据库架构及企业实践:基于 Mycat 中间件》


Mycat 自增主键配置:


http://deweing.github.io/2016/06/29/mycat-auto-increment.html


https://my.oschina.net/bodi666/blog/797277


作者介绍:


余骏


亚马逊 AWS 解决方案架构师,负责基于 AWS 的云计算方案架构的咨询和设计,同时致力于 AWS 云服务在国内的应用和推广。在加入 AWS 之前,在思科中国担任系统工程师,负责方案咨询和架构设计,在企业私有云和基础网络方面有丰富经验。


本文转载自 AWS 技术博客。


原文链接:


https://amazonaws-china.com/cn/blogs/china/mycat-rds-mysql/


2019 年 11 月 18 日 08:00491

欲了解 AWS 的更多信息,请访问【AWS 技术专区】

评论

发布
暂无评论
发现更多内容

今日随想

Nydia

Java8 Stream 数据流,大数据量下的性能效率怎么样?

xcbeyond

Java java8 Stream<T> 3月日更

优雅编程 | javascript代码优化的15个小知识

devpoint

ES6 JS代码优化 JS迭代

《接口测试入门》 学习笔记

骆俊

七日更 3月日更

如何在 Python 中清屏

HoneyMoose

Wireshark数据包分析学习笔记Day5

穿过生命散发芬芳

Wireshark 数据包分析 3月日更

更新60篇的复盘:持续书写,见证文字的力量

boshi

写作 七日更

冰河公开了进大厂的核心技能,服了!

冰河

程序员 面试 大厂技能 面试总结 硬核技能图谱

正则表达式.04 - 引用

insight

正则表达式 3月日更

《精通比特币》学习笔记(第五章)

棉花糖

区块链 读书笔记 3月日更

CR量化交易APP开发|CR炒币机器人软件系统开发

开發I852946OIIO

系统开发

LeetCode题解:518. 零钱兑换 II,动态规划,JavaScript,详细注释

Lee Chen

算法 LeetCode 前端进阶训练营

算法攻关 - 二叉树最大深度 (O(n))_0104

小诚信驿站

刘晓成 小诚信驿站 28天写作 算法攻关 二叉树最大深度

算法喜刷刷

Kylin

算法 3月日更 21天挑战

不一样的软件们——GitHub 热点速览 v.21.10

HelloGitHub

数据库 GitHub 开源项目

Node.js 模块化你所需要知道的事

vivo互联网技术

前端 nodejs Node

如何用python优雅的写论文

张鹤羽粑粑

28天写作 3月日更

(28DW-S8-Day17) 讲故事能力

mtfelix

28天写作 讲故事能力 复述能力

越来越受欢迎的Vue想学么,90后小姐姐今儿来教你

华为云开发者社区

算法 Vue 前端框架 框架 组件

进步

lenka

3月日更

鼎昂量化交易系统APP开发|鼎昂炒币机器人软件开发

开發I852946OIIO

系统开发

线上MySQL读写分离,出现写完读不到问题如何解决

程序员历小冰

MySQL 读写分离

面试被吊打系列 - Redis原理

云流

数据库 架构 面试

【动态规划/总结必看】从一道入门题与你分享关于 DP 的分析技巧 ...

宫水三叶的刷题日记

算法 LeetCode 面试数据结构与算法

事务消息应用场景、实现原理与项目实战(附全部源码)

中间件兴趣圈

RocketMQ 实战 消息中间件 事务消息

Python 数据类型

HoneyMoose

币神量化交易系统开发|币神量化交易APP软件开发

开發I852946OIIO

系统开发

3-8 工作日志

技术骨干

准备参加软考的小伙伴注意了!

IT蜗壳-Tango

IT蜗壳 3月日更

vm

梅花鹿鹿

28天写作 28天挑战 3月日更

Elasticsearch Dynamic Mapping

escray

elastic 七日更 28天写作 死磕Elasticsearch 60天通过Elastic认证考试

Study Go: From Zero to Hero

Study Go: From Zero to Hero

利用Mycat中间件实现RDS MySQL的分库分表及读写分离功能-InfoQ