MySQL - 多主多从

3,068 阅读4分钟

hello ~, 之前我在另外一篇文章中向大家分享过如果去搭建一个简单的MySQL主从复制环境,本篇是上一章的进阶版本,双主多从的集群基本上就可以满足绝大多数公司对数据库的性能要求了

准备工作

在看下面的配置步骤时,大家最好先认真看完下面的文章,以便更好的理解下面的操作步骤

MySQL - 主从复制

MySQL - 多线程复制

MyCAT - 环境安装

演示环境配置介绍

centos7 - mysql8 - 192.168.188.159 (Master - 1)
centos7 - mysql8 - 192.168.188.156 (Master - 2)
centos7 - mysql8 - 192.168.188.160 (Slave - 1)
centos7 - jdk1.7 - 192.168.188.158 (mycat - vip)

# 我这里使用的配置是两台写服务器,一台读服务器(可以根据自己的要求增减),一台代理服务器

配置步骤

# 配置主服务器
(1): [root@localhost ~]vim /etc/my.cnf

[mysqld]
gtid_mode = on  # 开启GTID复制
enforce_gtid_consistency = on # 强制GTID一致性
auto_increment_offset = 1   # 主键自增起始值
auto_increment_increment = 2    # 主键自增累加数
server-id = 1 # 编号, 这个在集群内必须唯一,否则会报错
innodb_buffer_pool_size = 2G    # 缓存池大小 (参数值设置为内存的70%)
innodb_log_file_size = 512M # 日志文件大小
innodb_log_buffer_size = 16M # 日志缓存大小
innodb_flush_log_at_trx_commit = 0 # 同步模式

# 另外一台主服务器配置相同,只需要修改
server-id = 2 # 编号, 这个在集群内必须唯一,否则会报错
auto_increment_offset = 2   # 主键自增起始值
auto_increment_increment = 2    # 主键自增累加数

(2):添加从服务器账号

mysql> create user '账号'@'服务器IP' identified by '密码';
mysql> grant replication slave on 库名(*=全部).表名(*=全部) to '账号'@'服务器IP';
mysql> flush privileges;

(3):获取GTID

mysql> show master status;
# 关注Executed_Gtid_Set
b6ac33e3-7944-11ea-8c39-000c29474b11:1-[position]
        
# 配置从服务器
(4):[root@localhost ~] vim/etc/my.cnf

gtid_mode = on
enforce_gtid_consistency = on
master_info_repository = table
relay_log_info_repository = table
slave-skip-errors = all
server-id = 3

(5):  连接主服务器
mysql> stop slave;
mysql> reset master all;
mysql> change master to master_host='192.168.188.159',master_port=3306,master_user='账号',master_password='密码',master_auto_position=ID for channel '1';
mysql> change master to master_host='192.168.188.156',master_port=3306,master_user='账号',master_password='密码',master_auto_position=ID for channel '2';
mysql> start slave;
# 检查启动状态
mysql> show slave status\G;
# 两个Slave_IO_Running和Slave_SQL_Running都是Yes就表示配置成功了

配置代理服务器环境

先自行完成上面的mycat安装哦,如果你的代码能解决多数据库连接实例的路由问题,可以也不配置代理服务器

(6):[root@localhost ~] vim /usr/local/mycat/conf/server.xml
<!DOCTYPE mycat:server SYSTEM "server.dtd">
    <!-- 0为需要密码登陆、1为不需要密码登陆 ,默认为0,设置为1则需要指定默认账户-->
    <property name="nonePasswordLogin">0</property>
    <property name="useHandshakeV10">1</property>
    <!-- 1为开启实时统计、0为关闭 -->
    <property name="useSqlStat">0</property>
    <!-- 1为开启全加班一致性检测、0为关闭 -->
    <property name="useGlobleTableCheck">0</property>
    <property name="sequnceHandlerType">2</property>
    <!-- 子查询中存在关联查询的情况下,检查关联字段中是否有分片字段 .默认 false -->
    <property name="subqueryRelationshipCheck">false</property>
    <!-- <property name="useCompression">1</property>--> <!--1为开启mysql压缩协议-->
    <!-- <property name="processorBufferChunk">40960</property> -->
    <!-- <property name="processors">1</property> -->
    <!-- <property name="processorExecutor">32</property> -->
    <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">3308</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> -->
    <!--
    handleDistributedTransactions 分布式事务开关
    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">64k</property>
    <!--单位为k-->
    <property name="spillsFileBufferSize">1k</property>
    <property name="useStreamOutput">0</property>
    <!--单位为m-->
    <property name="systemReserveMemorySize">384m</property>
    <!--是否采用zookeeper协调切换 -->
    <property name="useZKSwitch">false</property>
    <!-- XA Recovery Log日志路径 -->
    <!--<property name="XARecoveryLogBaseDir">./</property>-->
    <!-- XA Recovery Log日志名称 -->
    <!--<property name="XARecoveryLogBaseName">tmlog</property>-->
</system>
# 重点关注这里, name = 账户,passwor = 登录密码,schemas = 数据库名和规则名称
<user name="root" defaultAccount="true">
        <property name="password">123456</property>
        <property name="schemas">pvcat</property>
</user>
</mycat:server>

(7):修改规则文件 (/usr/local/mycat/conf/schema.xml)

<?xml version="1.0"?> 
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <schema name="pvcat" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"></schema>
    <dataNode name="dn1" dataHost="localhost1" database="pvcat" />
    <dataHost name="localhost1" maxCon="20000" minCon="10" balance="0"  writeType="1" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM1" url="192.168.188.159:3306" user="远程连接账户" password="远程连接密码">
            <readHost host="hostS1" url="192.168.188.160:3306" user="远程连接账户" password="远程连接密码" />
            <!-- 如果有多台从服务器可以复制readHost —> hostS1后修改配置参数即可 -->
        </writeHost>
        <writeHost host="hostM2" url="192.168.188.156:3306" user="远程连接账户" password="远程连接密码" />
    </dataHost>
</mycat:schema>

(8):启动mycat

[localhost@root ~]  /usr/local/mycat/bin/mycat start

# 大家用navicat连接数据库试试效果了 
    host = 192.168.188.158
    port = 3308
    user = root
    password = 123456

FAQ

为什么按照上面的配置完成后程序连接会报错 “1184 - Invalid DataSource:0”

如果是使用MySQL8.0.30或以上版本需要修改一下MyCAT的schema配置文件

(1):下载mysql-connector-java-8.0.11.jar至/mycat/lib目录下,并授予执行权限
(2):修改schema.xml -> dataHost标签的dbDriver属性至jdbc
(2):修改schema.xml -> writeHost及readHost标签的url属性至jdbc:mysql://[host]:[port]

 # 你们要是遇到的了别的连接报错也可以留言哈,我在接着补充

双主环境下如何保证主键ID唯一

主键冲突问题有两种解决方案

(1):按照我上面的方案,有两台主机,一台奇数自增,一台偶数自增
(2):在程序中指定ID,使用类似uuid,雪花算法这样的方案保证ID唯一

双主环境下如何去增改数据表结构

由于上述配置操作两台主机互不隶属,你在修改表结构时确实会遇到增加,删除,修改数据表时一个命令要执行两次的情况,所以你可以两台主机之间配置为互为主从

如何验证代理服务器的读写请求有没有正确转发到不同的服务器

# 开启运行日志 

mysql> set global log_output = 'TABLE'; 
mysql> set global general_log = 'ON'; 

# 查询SQL运行日志 
mysql> select * from mysql.general_log where argument != 'select user()' order by event_time desc; 

# 关闭运行日志 
mysql> set global log_output = 'TABLE'; 
mysql> set global general_log = 'OFF';

# 验证无误后清空运行日志 
mysql> truncate table mysql.general_log;