MySQL读写分离

实现MySQL读写分离的前提是我们已经将MySQL主从复制配置完毕,可参考我上一篇关于MySQL主从复制的文章。
读写分离实现方式:
1)配置多数据源;
2)使用mysql的proxy中间件代理工具;
第一种方式中,数据库和Application是有一定侵入性的,即我们的数据库更换时,application中的配置文件是需要手动修改的。而第二种方式中,我们可选择mysql proxy固定连接一个数据库,即使数据库地址更换也无需更换项目中的数据库连接配置。
同样,在开始配置实现MySQL读写分离之前,我们会遇到一个选型问题,那就是在诸多的MySQL的proxy中间件工具中,如mysql-proxyatlascobarmycattddltinnydbroutermysql router等,我们该如何取舍呢?所以在择工具实现前,我们先对以上的proxy中间件做一个简单的优劣介绍,以便我们根据不同的场景选择。

1.MySQL的proxy中间件工具优劣

以下主要对比MyCat和MySQL Router。

1.1 MyCat

是基于阿里巴巴的Cobar方案优化而来,支持半自动化分片,join。为什么叫"半自动化"呢?因为需要DBA对每个表的分片策略进行配置和干涉。
优点:

  • 功能较丰富,对读写分离和分库分表都有支持;
  • 易用,且对原有的应用系统侵入比较小,系统改造比较易于实现;
  • 支持故障切换;

不足:

  • 在整个系统中,MyCat作为一个单节点来路由其他数据库,在数据库比较多的情况下,MyCat本身的CPU性能压力会越来越大。因此,在生产系统中,MyCat不可避免的会需要一些高可用的手段;
  • 同样,由于MyCat本身需要解析sql,也需要合并各个数据库返回的结果,本身CPU消耗会比较高,当达到一定临界点时,CPU可能会不堪重负。

为此,在数据库较多的情况下,生产环境下的部署可能是这样的:


部署图
1.2 MySQL Router

MySQL Router是MySQL官方提供的一个轻量级中间件,可以在应用程序与MySQL服务器之间提供透明的路由方式。主要用以解决MySQL主从库集群的高可用、负载均衡、易扩展等问题。Router可以与MySQL Fabric无缝连接,允许Fabric存储和管理用于路由的高可用数据库服务器组,使管理MySQL服务器组更加简单。

MySQL Router是一个可执行文件,可以与应用程序在同一平台上运行,也可以单独部署。虽然MySQL Router是InnoDB Cluster(MySQL 7.X)的一部分,MySQL 5.6 等版本数据库仍然可以使用Router作为其中间代理层。MySQL Router的配置文件中包含有关如何执行路由的信息。它与MySQL服务器的配置文件类似,也是由多个段组成,每个段中包含相关配置选项。

MySQL Router是MySQL Proxy的替代方案,MySQL官方不建议将MySQL Proxy用于生产环境,并且已经不提供MySQL Proxy的下载。

优点:

  • 类似于nginx,位于Application与MySQL Server之间。Application不再直连MySQL Server,而是与Router相连,根据Router的配置,将会把应用程序的读、写请求转发给下游的MySQL Server;
  • 支持故障切换:当下游某个Server失效时,Router可以将其从Active列表中移除,当其online后再次加入Active列表,即提供了Failover特性;
  • 当MySQL Server集群拓扑变更时,比如增减Slaves节点,只需要修改Router配置即可,无需修改应用中的数据库连接配置;
  • 如果MySQL Servers为5.7+版本,且构建为InnoDB Cluster模式,那么Router还能基于metaCache(metaServers)机制,感知MySQL Servers的主从切换、从库增减等集群拓扑变更,而且基于变更能够实现Master自动切换、Slaves列表自动装配等。比如Master失效后,Cluster将会自动选举一个新的Master,此时Router不需要任何调整、可以自动发现此新Master进而继续为应用服务。

不足:

  • Router中间件本身不会对请求“拆包”(unpackage),所以无法在Router中间件上实现比如“SQL审计”、“隔离”、“限流”、“分库分表”等功能。但是Router提供了plugin(C语言)机制,我们可以开发自己的plugin来扩展Router的额外特性;
  • 数据存储在内存中,数据量较大时,硬件需求会提升;
  • 在非InnoDB Cluster架构模式下,如果主从库拓扑变更,需要手动修改Router配置。且Router不支持“reload”,修改配置后需要重启,这在一定程度上会影响Application的服务可用性。

对比以上两种proxy工具,本文选择了MyCat实现。

2.MyCat实现MySQL读写分离

实验环境

服务器名称 版本 MySQL版本 IP
MyCat代理中间件 Centos7.3 - 192.168.ww.ww
主数据库 Centos7.3 5.7 192.168.xx.xx
从数据库 Centos7.3 5.7 192.168.yy.yy
2.1 安装MyCat

安装JDK
因为MyCat是用java语言编写的,需要JDK支持,JDK安装可参考此博客:点此查看

安装MyCat
本文下载的版本为Mycat-server-1.6.5-release-20180122220033-linux.tar.gz点此下载

将压缩包用xftp上传到服务器/usr/local/下并解压

cd /usr/local/
tar -zxvf Mycat-server-1.6.5-release-20180122220033-linux.tar.gz

配置环境变量vim /etc/profile 在文件末尾加入如下代码,并保存:

MYCAT_HOME=/usr/local/mycat
PATH=$MYCAT_HOME/bin:$PATH
export MYCAT_HOME PATH

使配置文件生效source /etc/profile

2.2配置MyCat

MyCat常用配置文件
文件位置都在mycat下的conf目录中:

文件 说明
server.xml MyCat的配置文件,设置账号、参数等
schema.xml MyCat对应的物理数据库和数据库表的设置
rule.xml MyCat分片(分库分表)规则
wrapper.conf MyCat启动日志信息

配置server.xml

server.xml中主要配置内容如下(此为默认配置),其他部分默认即可


主要配置

避免图片失效,多粘一份吧=-=!

<user name="root" defaultAccount="true">
                <property name="password">123456</property>
                <property name="schemas">TESTDB</property>

                <!-- 表级 DML 权限设置 -->
                <!--            
                <privileges check="false">
                        <schema name="TESTDB" dml="0110" >
                                <table name="tb01" dml="0000"></table>
                                <table name="tb02" dml="1111"></table>
                        </schema>
                </privileges>           
                 -->
        </user>

        <user name="user">
                <property name="password">user</property>
                <property name="schemas">TESTDB</property>
                <property name="readOnly">true</property>
        </user>

MyCat将多个MySQL集群整合起来对外提供服务,提供的服务接口仍然采用MySQL的形式。以上为MyCat对外的"虚拟数据库"配置文件。

  • 以上片段为MyCat默认配置的两个虚拟用户,分别为用户名为root和用户名为user的两个虚拟用户;
  • 默认用户为root用户,该用户没有配置readOnly的属性,为此拥有读写权限。而用户名为user的用户配置了readOnly的属性为true,为此只有读权限;
  • root的密码被设置为123456,而user的密码被设置为user
  • 两者使用的都是TESTDB逻辑库,TESTDB逻辑库的配置在schema.xml

以上的用户名和密码我们都可以根据个人需求进行修改。

配置schema.xml

以下为schema.xml默认的配置文件(其实我删了一小部分schema中的table,因为我们目前做的只是读写分离,因此忽略此部分):

<mycat:schema xmlns:mycat="http://io.mycat/">
        <!--逻辑数据库配置,name与server.xml中配置的数据库对应-->
        <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
                <!-- 如果只是做读写分离,那么我们就不需要配置这个table -->
                <!--<table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />-->
        </schema>
        <!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743"
                /> -->
        <!--设置实际服务器中数据库-->
        <dataNode name="dn1" dataHost="localhost1" database="db1" />
   
         <!--物理数据库配置-->
  <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <!-- can have multi write hosts -->
                <writeHost host="hostM1" url="localhost:3306" user="root"
                                   password="123456">
                        <!-- can have multi read hosts -->
                        <readHost host="hostS2" url="192.168.1.200:3306" user="root" password="xxx" />
                </writeHost>
                <writeHost host="hostS1" url="localhost:3316" user="root"
                                   password="123456" />
                <!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
        </dataHost>
</mycat:schema>

简单解释一下上面代码各参数的含义:

参数 说明
schema 数据库设置,此数据库为逻辑数据库,name与server.xml中的schema对应
dataNodel 分片信息,也就是分库相关配置
dataHost 物理数据库,真正存储数据的数据库

每个节点的属性详细说明
schema

属性 说明
name 逻辑数据库名称,与server.xml中的schema对应
checkSQLschema 数据库前缀相关设置,建议看文档,这里暂时设为folse
sqlMaxLimit select 时默认的limit,避免查询全表
dataNode 分库配置

table

属性 说明
name 表名,物理数据库中表名
dataNode 表存储到哪些节点,多个节点用逗号分隔。节点为下文dataNode设置的name
primaryKey 主键字段名,自动生成主键时需要设置
autoIncrement 是否自增
rule 分片规则名

dataNode

属性 说明
name 节点名,与table中dataNode对应
dataHost 物理数据库名,与datahost中name对应
database 物理数据库中数据库名

dataHost

属性 说明
name 物理数据库名,与dataNode中dataHost对应
balance 负载均衡策略,0为不开启读写分离,1为开启读写分离
writeType 写入方式
dbType 数据库类型
heartbeat 心跳检测语句,注意语句结尾的分号要加

详细介绍以下几个属性值:

  • balance="1":全部的readHost与stand by writeHost参与select语句的负载均衡;
  • writeType="0":所有的写操作都发送到配置文件中的第一个writeHost。(注意:第一个writeHost故障切换到第二个后,即使之后修复了仍然维持第二个为写库)。推荐取值为0,不建议修改;
  • switchType="1":1为默认值,即自动切换。

罗列了这么多的属性意思,想必大家已经知道需要配置什么了吧!我们可以根据自己的需求来进行配置,那么接下来我以简单的读写分离来示例配置,以下介绍修改的地方:

  • 在以上默认配置文件schema中并没有设置属性dataNode,为此我们加入dataNode="dn1",其中dn1对应<dataNode/>部分中的name属性值;同时,将默认设置的table部分注释掉,最终schema剩余部分如下
<schema name="test" checkSQLschema="false" sqlMaxLimit="100"  dataNode="dn1" >
 <!-- 本文做的是单纯的读写分离配置为此此处不需要table ,将默认的table注释掉   
    <table name="travelrecord" dataNode="dn1" rule="auto-sharding-long" />
    -->    
</schema>
  • <dataNode/>部分中的database属性值改为我们实际储存数据的数据库名称;默认配置中给我们设置了3个dataNode,本环境中只有一个主数据库和一个从数据库,为此我们只保留一个dataNode,如下
<!--其中database为这是连接的数据库名称,我配置的是我真实数据库中的spring数据库-->
<dataNode name="dn1" dataHost="localhost1" database="spring" />

  • <dataHost/>部分的<writeHost>中的host属性值可改可不改,但是url需要改成我们真实数据库的地址,因为我们在主库中进行写操作,为此此处的url改为我们的主数据ip,即url="192.168.xx.xx";而userpassword两个属性的属性值设置为连接主数据库的用户名和密码;同时,需要将balance的属性值改为1,即balance="1",若为0会在测试时发现读写都是在主库执行;

  • <readHost>部分设置host属性值可改可不改;而url改为我们的从数据库ip,即url="192.168.yy.yy",user和password设置为连接从数据库的用户名和密码;

  • 此处因为实验环境是一个主数据库,一个从数据库,为此这里只配置了一个WriteHost和一个readHost;在默认的配置文件中可以看到是可以配置多个的,我们将多余的一个writeHost,最终剩下如下部分

 <dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="hostM1" url="192.168.xx.xx:3306" user="root"
                                   password="password">
                        <readHost host="hostS2" url="192.168.yy.yy:3306" user="root" password="password" />
                </writeHost>
        </dataHost>

log4j2.xml
将日志等级改为debug

<asyncRoot level="debug" includeLocation="true">
            <!--<AppenderRef ref="Console" />-->
            <AppenderRef ref="RollingFile"/>
</asyncRoot>

至此,整体配置已经完成了,我们开始进行测试!

3.测试配置是否成功

开启MyCat
我们要开启MyCat直接输入启动指令即可,后两条指令为我们停止和重启的时候使用;

cd /usr/local/mycat/bin
# 启动
./mycat start

#停止
./mycat stop

#重启
./mycat restart 

查看端口
其中9066为虚拟schema管理端口,用于查看MyCat运行的情况;
其中8066为虚拟schema登录端口,用于SQL管理,跟普通MySQL差不多

netstat -tnlp
查看端口

登录MyCat读写分离服务

# 9066是管理端口
mysql -u root -p 123456 -h 127.0.0.1 -P 9066

查看心跳检测

show @@help; #查看帮助
show @@heartbeat; #查看心跳
#RS_CODE为1表示心跳正常
查看心跳状态

查看机器的读写分离配置情况

show @@datasource;
读写分离状况图

可以看到hostM1拥有W写权限,hostS2拥有R读权限

MyCat读写分离验证
登录到MyCat的SQL管理服务:

mysql -u root -p 123456 -h 127.0.0.1 -P 8066

可以用简单的指令查看当前数据库

show databases;
use xxx; # 其中xxx为刚才看到的数据库中的一个
show tables; 
select * from jerry; #为后续做验证准备,这个我们可以按照我们真实表来,此处因为我的数据库中有jerry表,所以以此来示例
简单查看
查询

验证部分
有两种思路来验证:
1) 在从数据中关闭slave(即关闭主从复制);然后在mycat管理端中往某个表中插入一条数据;再使用select查询该表,可以看到查询出来的结果中并没有新的那条数据。(解释:因为关闭了主从复制,插入新数据在主库进行,而查询的是从库,为此不会查询到新插入的数据);
2)不关闭slave的主从复制,直接在从库中修改表中的某个值,而主库的值不变,直接使用查询表数据时会发现查询出来的结果是从库表中的数据(可以根据改变的值对比看出)

本文主要使用第一种思路进行验证:

  • 打开从数据库服务器,并进入mysql中,并停止上篇文章中配置的主从复制;
mysql -u root -p #进入从数据库
stop slave; #关闭主从复制
  • 再回到我们的mycat安装的服务器中,在已登录的MyCat的SQL管理服务中进行插入一条数据,我的示例如下;
insert into jerry (name) values ('liang');#我表id是自增的,所以只插入name
select * from jerry;#查看
验证结果图

可以发现并没有刚插入的数据,我们再打开主数据库,查看是否有更新;(是因为我多次测试,之前没把balance属性值设置为1,导致读写一直是在主库执行,为此主键已经到12了==!)

验证结果图

至此,读写分离验证成功了!第二种小伙伴们可以亲自去尝试一下。对了,验证完记得到从数据库中start salve开启主从复制,避免以后忘了。

参考资料

https://segmentfault.com/a/1190000009520414
https://www.cnblogs.com/joylee/p/7513038.html
https://www.2cto.com/database/201709/676648.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容

  • 为什么需要读写分离 至于为什么需要读写分离,在我之前的文章有介绍过了,相信看到这篇文章的人也知道为什么需要读写分离...
    Raye阅读 1,348评论 0 6
  • Mycat 实现 MySQL 读写分离 环境:CentOS 6.8 实验拓扑: mycat: 192.168.0....
    C86guli阅读 9,285评论 1 17
  • 前言 随着业务的不断扩展,数据量的不断增大,由单台Mysql作为独立的数据库是完全不能满足实际需求的。读和写又存在...
    slicn阅读 965评论 0 0
  • https://www.jianshu.com/p/51861107b04a 数据库中间 MyCAT 读写分离实现...
    运维开发_西瓜甜阅读 6,782评论 0 76
  • 数据库中间 MyCAT 读写分离实现 Mycat 是一个开源的分布式数据库系统,但是由于真正的数据库需要存储引擎,...
    Lengfin阅读 276评论 0 0