使用Mycat构建MySQL读写分离、主从复制、主从高可用

数据库读写分离对于大型系统或者访问量很高的互联网应用来说,是必不可少的一个重要功能。 

  从数据库的角度来说,对于大多数应用来说,从集中到分布,最基本的一个需求不是数据存储的瓶颈,而是在于计算的瓶颈,即SQL查询的瓶颈,我们知道,正常情况下,Insert SQL就是几十个毫秒的时间内写入完成,而系统中的大多数Select SQL则要几秒到几分钟才能有结果,很多复杂的SQL,其消耗服务器CPU的能力超强,不亚于死循环的威力。在没有读写分离的系统上,很可能高峰时段的一些复杂SQL查询就导致数据库服务器CPU爆表,系统陷入瘫痪,严重情况下可能导致数据库崩溃。因此,从保护数据库的角度来说,我们应该尽量避免没有主从复制机制的单节点数据库。

1. 环境

1.1 最低环境需求

MySQL 5.5及以上
Java JDK 7及以上

1.2 主服务器环境

CentOS 7.4.1708
MySQL 5.6.40
Java JDK 10.0.1
Mycat 1.6

1.3 从服务器环境

CentOs 7.2.1511
MySQL 5.6.35

2. 安装

2.1 主服务器安装

安装MySQL

  本人使用的环境为自动部署上去的,其中已包含Mysql,所以关于MySQL 的单独安装请大家参考网上的教程。

安装Java JDK

  下载地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html

 

点击 DOWNLOAD

同意协议,点击下载。

登录服务器,创建 Java JDK 安装目录

mkdir /usr/local/java

上传 JDK 至目录

解压 JDK 至当前目录

tar -zxvf jdk-10.0.1_linux-x64_bin.tar.gz

编辑配置文件,配置环境变量

vim /etc/profile

添加如下内容:JAVA_HOME根据实际目录来
export JAVA_HOME=/usr/local/java/jdk-10.0.1
export CLASSPATH=$JAVA_HOME/lib/
export PATH=$PATH:$JAVA_HOME/bin
export PATH JAVA_HOME CLASSPATH

重启机器

sudo shutdown -r now

查看安装情况

java -version

安装Mycat

  MyCAT有提供编译好的安装包,支持windows、Linux、Mac、Solaris等系统上安装与运行。

  下载地址:http://dl.mycat.io/

  这里我选择下载1.6版本:Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz

上传 Mycat 至服务器 /usr/local

解压 Mycat 至当前目录

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

移动安装包至 mycat 文件夹

mv Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz /usr/local/mycat/

创建用户并设置

useradd Mycat
chown -R Mycat.Mycat /usr/local/mycat/
passwd Mycat

mycat 文件夹目录说明

/usr/local/mycat
├── bin
├── catlet
├── conf
├── lib
├── logs
└── version.txt

  目录解释如下:

  bin 程序目录,存放了window版本和linux版本,除了提供封装成服务的版本之外,也提供了nowrap的shell脚本命令,方便大家选择和修改,进入到bin目录:

  Linux下运行:./mycat console,首先要chmod +x *

  注:mycat支持的命令{ console | start | stop | restart | status | dump }

  conf目录下存放配置文件,server.xml是Mycat服务器参数调整和用户授权的配置文件,schema.xml是逻辑库定义和表以及分片定义的配置文件,rule.xml是分片规则的配置文件,分片规则的具体一些参数信息单独存放为文件,也在这个目录下,配置文件修改,需要重启Mycat或者通过9066端口reload.

  lib目录下主要存放mycat依赖的一些jar文件.

  日志存放在logs/mycat.log中,每天一个文件,日志的配置是在conf/log4j.xml中,根据自己的需要,可以调整输出级别为debug,debug级别下,会输出更多的信息,方便排查问题.

  注意:Linux下部署安装MySQL,默认不忽略表名大小写,需要手动到/etc/my.cnf 下配置 lower_case_table_names=1 使Linux环境下MySQL忽略表名大小写,否则使用MyCAT的时候会提示找不到表的错误!

增加环境变量

  MyCAT在Linux中部署启动时,首先需要在Linux系统的环境变量中配置MYCAT_HOME,操作方式如下:

vi /etc/profile

在文件中增加
export MYCAT_HOME=/usr/local/mycat

刷新环境变量

source /etc/profile

Mycat 集群配置

  如果是在多台Linux系统中组建的MyCAT集群,那需要在MyCAT Server所在的服务器上配置对其他ip和主机名的映射,配置方式如下:

vi /etc/hosts

例如:我有4台机器,配置如下:

IP 主机名:

192.168.100.2 sam_server_1

192.168.100.3 sam_server_2

192.168.100.4 sam_server_3

192.168.100.5 sam_server_4

  编辑完后,保存文件。

启动 Mycat

  经过以上两个步骤的配置,就可以到 /usr/local/Mycat/bin 目录下执行:(先不要动配置文件)

./mycat start

  即可启动mycat服务!

  注:mycat支持的命令{ console | start | stop | restart | status | dump }

  初次执行可以使用 ./mycat console 命令执行,这样有失败信息直接就能显示出来。

  检验执行是否成功可以使用 ./mycat status 

开放端口

  如果开启防火墙需要开放8066/9066端口,9066和8066分别侦听管理员和应用程序的连接请求。

vim /etc/sysconfig/iptables

添加:
-A INPUT -p tcp -m state --state NEW -m tcp --dport 8066 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 9066 -j ACCEPT

重启 iptables
service iptables save
systemctl enable iptables.service
systemctl restart iptables.service

2.2 从服务器安装

   从服务器主要用到的是 MySQL,环境为自动部署上去的,其中已包含Mysql,所以关于MySQL 的单独安装请大家参考网上的教程。

3. 配置MySQL主从复制

  配置mysql端主从的数据自动同步,mycat不负责任何的数据同步问题。

  关于 MySQL 主从复制的介绍我不多赘述,其中优缺点有兴趣的可以查阅相关资料。主要复制方式:

  • 基于SQL语句的复制(statement-based replication, SBR),
  • 基于行的复制(row-based replication, RBR),
  • 混合模式复制(mixed-based replication, MBR)。

  基于SQL语句的方式最古老的方式,也是目前默认的复制方式,后来的两种是MySQL 5以后才出现的复制方式。

3.1 主服务器配置

登录MySQL,创建一个同步账号,并分配用户权限

CREATE USER 'AiMasterSlave'@'%' IDENTIFIED BY '123456';

GRANT REPLICATION SLAVE ON *.* TO 'AiMasterSlave'@'%';

修改/etc/my.cnf

server-id = 2 # 每台服务器标识要唯一,不要设置为0,为0会拒绝所有链接

log_bin = mysql-bin

重启Mysql

service mysqld restart

登录MySQL,查看二进制日志

show master status;

  记录下来,一会要用到。

检查3306端口是否开放,如果没开放,开放端口,参考上面打开8066端口方法

3.2 从服务器配置

先别着急配置,尝试远程链接主服务器,检验一下

mysql -h192.168.1.45 -uAiMasterSlave -p123456

  如果不能链接,请检验主服务器用户配置

修改/etc/my.cnf

server-id = 1
replicate_wild_do_table=master_slave_test.% # 同步库
replicate_wild_ignore_table=mysql.% # 排除库

重启Mysql

service mysqld restart

登录MySQL

stop slave;

CHANGE MASTER TO
MASTER_HOST='192.168.1.45',
MASTER_USER='AiMasterSlave',
MASTER_PASSWORD='123456',
MASTER_LOG_FILE='mysql-bin.000013',
MASTER_LOG_POS=680;

start slave;

查看状态

show slave status \G;

  如果上面两处都为 Yes 说明配置就没问题。为 NO 或者 connecting 请检查配置和防火墙设置是否准确。

3.3 测试主从复制

 

  我在主服务器写的数据,从服务器会自动同步,说明配置生效。

4. 配置Mycat读写分离

  关于 Mycat 的详细配置说明,请到官网去查阅文档,太多了我就不搬过来了。资料下载:百度云

4.1 server.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- - - Licensed under the Apache License, Version 2.0 (the "License"); 
    - you may not use this file except in compliance with the License. - You 
    may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 
    - - Unless required by applicable law or agreed to in writing, software - 
    distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT 
    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the 
    License for the specific language governing permissions and - limitations 
    under the License. -->
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
    <system>
    <property name="useSqlStat">0</property>  <!-- 1为开启实时统计、0为关闭 -->
    <property name="useGlobleTableCheck">0</property>  <!-- 1为开启全加班一致性检测、0为关闭 -->

        <property name="sequnceHandlerType">2</property>
      <!--  <property name="useCompression">1</property>--> <!--1为开启mysql压缩协议-->
        <!--  <property name="fakeMySQLVersion">5.6.20</property>--> <!--设置模拟的MySQL版本号-->
    <!-- <property name="processorBufferChunk">40960</property> -->
    <!-- 
    <property name="processors">1</property> 
    <property name="processorExecutor">32</property> 
     -->
        <!--默认为type 0: DirectByteBufferPool | type 1 ByteBufferArena-->
        <property name="processorBufferPoolType">0</property>
        <!--默认是65535 64K 用于sql解析时最大文本长度 -->
        <!--<property name="maxStringLiteralLength">65535</property>-->
        <!--<property name="sequnceHandlerType">0</property>-->
        <!--<property name="backSocketNoDelay">1</property>-->
        <!--<property name="frontSocketNoDelay">1</property>-->
        <!--<property name="processorExecutor">16</property>-->
        <!--
            <property name="serverPort">8066</property> <property name="managerPort">9066</property> 
            <property name="idleTimeout">300000</property> <property name="bindIp">0.0.0.0</property> 
            <property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> -->
        <!--分布式事务开关,0为不过滤分布式事务,1为过滤分布式事务(如果分布式事务内只涉及全局表,则不过滤),2为不过滤分布式事务,但是记录分布式事务日志-->
        <property name="handleDistributedTransactions">0</property>
        
            <!--
            off heap for merge/order/group/limit      1开启   0关闭
        -->
        <property name="useOffHeapForMerge">1</property>

        <!--
            单位为m
        -->
        <property name="memoryPageSize">1m</property>

        <!--
            单位为k
        -->
        <property name="spillsFileBufferSize">1k</property>

        <property name="useStreamOutput">0</property>

        <!--
            单位为m
        -->
        <property name="systemReserveMemorySize">384m</property>


        <!--是否采用zookeeper协调切换  -->
        <property name="useZKSwitch">true</property>


    </system>
    
    <!-- 全局SQL防火墙设置 -->
    <!-- 
    <firewall> 
       <whitehost>
          <host host="127.0.0.1" user="mycat"/>
          <host host="127.0.0.2" user="mycat"/>
       </whitehost>
       <blacklist check="false">
       </blacklist>
    </firewall>
    -->

    <user name="mycat">
        <property name="password">123456</property>
        <property name="schemas">TESTDB</property>
        <property name="readOnly">false</property>
    </user>

</mycat:server>
View Code

4.2 schema.xml

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

    <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"></schema>

    <dataNode name="dn1" dataHost="aiMasterSlave" database="master_slave_test" />

    <dataHost name="aiMasterSlave" maxCon="1000" minCon="10" balance="3"
              writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <!-- can have multi write hosts -->
        <writeHost host="hostM1" url="192.168.1.45:3306" user="AiMasterSlave"
                   password="123456">
            <!-- can have multi read hosts -->
            <readHost host="hostS2" url="192.168.1.239:3306" user="aliyun" password="123456" />
        </writeHost>
    </dataHost>

</mycat:schema>

4.3 测试读写分离

开启debug级别日志(生产环境不要一直设置日志级别为debug) 

vi /usr/local/mycat/conf/log4j2.xml 

重启Mycat

使用本地 Shell 测试

检验物理数据库

  数据已同步,说明没问题!

查看Mycat日志

  可以看到读和写分别走两个服务器。至此,读写分离和主从配置完毕!

5. Mycat高可用方案

  Mycat作为一个代理层中间件,Mycat系统的高可用涉及到Mycat本身的高可用以及后端MySQL的高可用。在大多数情况下,建议采用标准的MySQL主从复制高可用性配置并交付给Mycat来完成后端MySQL节点的主从自动切换。

5.1 应用强制走写/从

  一个查询SQL语句以/*balance*/注解来确定其是走读节点还是写节点。 1.6以后添加了强制走读走写处理:

强制走从:

/*!mycat:db_type=slave*/ select * from travelrecord 
/*#mycat:db_type=slave*/ select * from travelrecord 

强制走写:
/*#mycat:db_type=master*/ select * from travelrecord /*!mycat:db_type=master*/ select * from travelrecord

5.2 根据主从延时切换

  1.4开始支持MySQL主从复制状态绑定的读写分离机制,让读更加安全可靠,配置如下:

  MyCAT心跳检查语句配置为 show slave status ,dataHost 上定义两个新属性: switchType="2" 与 slaveThreshold="100",此时意味着开启MySQL主从复制状态绑定的读写分离与切换机制,Mycat心跳机制通过检测 show slave status 中的 "Seconds_Behind_Master", "Slave_IO_Running", "Slave_SQL_Running" 三个字段来确定当前主从同步的状态以及Seconds_Behind_Master主从复制时延, 当Seconds_Behind_Master>slaveThreshold时,读写分离筛选器会过滤掉此Slave机器,防止读到很久之前的旧数据,而当主节点宕机后,切换逻辑会检查Slave上的Seconds_Behind_Master是否为0,为0时则表示主从同步,可以安全切换,否则不会切换。

<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native"
          switchType="2" slaveThreshold="100">
    <heartbeat>show slave status</heartbeat> <!-- can have multi write hosts -->
    <writeHost host="hostM1" url="localhost:3306" user="root" password="123456"></writeHost>
    <writeHost host="hostS1" url="localhost:3316" user="root" password="123456"/>
</dataHost>

1.4.1 开始支持MySQL 集群模式,让读更加安全可靠,配置如下: MyCAT心跳检查语句配置为 show status like ‘wsrep%’ , dataHost 上定义两个新属性: switchType="3"
此时意味着开启MySQL集群复制状态状态绑定的读写分离与切换机制,Mycat心跳机制通过检测集群复制时延时,如果延时过大或者集群出现节点问题不会负载改节点。 

<dataHost name="localhost1" maxCon="1000"
minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="3" >
    <heartbeat> show status like ‘wsrep%’</heartbeat>
    <writeHost host="hostM1" url="localhost:3306" user="root" password="123456"></writeHost>
    <writeHost host="hostS1" url="localhost:3316" user="root" password="123456"></writeHost>
</dataHost>

  ps:没想到写了这么长,边搭边记录,最后我是跑通了!但愿没有误导他人的地方,感谢阅读,再会!

猜你喜欢

转载自www.cnblogs.com/bndong/p/9225064.html