目录
linux搭建主从数据库和Mycat读写分离
搭建主从数据库服务器
搭建主从数据库服务器
从数据库可以理解为主数据库的实时备份, 当主数据库发生变化, 从数据库也会发生变化
从库可以有多个, 但是一般不会超过3个从库
一般从数据库为只读, 如果从数据库数据认为的更改了, 主数据库不会该表
图解
工作原理
左边为主数据库, 有边为从数据库
工作原理说明:
- 数据库主库将更新的数据信息写入到二进制日志文件中.
- 数据库从库通过IO线程去主库中获取二进制文件修改内容. 之后写入到中继日志中
- 数据库从库中的Sql线程读取中继日志中的信息,实现数据的同步. 并且为了降低组件之间的耦合性,采用异步的方式处理.
1. 前提准备
- 两台centos服务器 或 虚拟机, 并且都安装了数据库, mysql或mariadb
- 先手动同步数据库中的数据 (利用sqlyog等工具导出主数据库数据, 导入到从数据库)保证目前两个数据库同步
2. 开启二进制日志
主库可从库都要开启
更改数据库核心配置文件 vim /etc/my.cnf
(版本不同, 配置文件位置也可能不同)
在 [mysqld] 下面加入如下内容
[mysqld]
# 服务id (此id从库和主库都不能重复, 每个数据库有自己的id)
server-id=1
# 配置二进制日志文件名称, 可以任意 (可以和从数据库一致)
log-bin=mysql-bin
我们从配置文件上面的 datadir 属性可以看到mysql的工作目录
即, 生成的二进制日志文件也在改工作目录中
现在重启mysql服务器: systemctl restart mariadb
到工作目录/var/lib/mysql
中查看, 可以看到生成的两个文件
其中mysql-bin.000001文件, 每次数据库重启, 文件后缀就会加1
其他数据库也重复以上操作, 保证数据库的二进制日志文件都开启 (注意mysql核心配置文件中server-id属性不能重复)
3. 实现主从挂载
主从挂载应该由从库向主库进行挂载.由从库远程连接主库,之后读取二进制日志文件信息.
3.1. 确定主库二进制日志信息
确定主库中的二进制日志文件信息命令: 在主数据库中输入: show master status;
其中Position字段相当于是一个指针, 即从数据库读取的时候会从这个指针出开始读取, 而不是把整个文件都要读取, 这大大提升了效率
3.2 实现主从挂载
在所有的从库中连接主库 (所有的从库都要执行)
/*我是从库 默认条件下数据库都是主库host/port/user/password/二进制文件/pos*/
CHANGE MASTER TO MASTER_HOST="192.168.126.129", -- 主库的ip地址(公网/私网)
MASTER_PORT=3306, -- 主库端口号
MASTER_USER="root", -- 主库用户名
MASTER_PASSWORD="123456", -- 主库密码
MASTER_LOG_FILE="mysql-bin.000001", -- 上一步查到的File字段, 日志文件名
MASTER_LOG_POS=245; -- 上一步查到的Position字段
/*启动主从服务*/
START SLAVE;
/*检查主从状态*/
SHOW SLAVE STATUS;
检查主从状态显示如下信息的两个字段为yes, 说明启动成功, 如果没有yes, 状态结果中会有错误信息的字段
错误信息字段
如果信息写错, 先关闭主从服务, 在重复上面的操作
/*关闭主从服务*/
STOP SLAVE;
数据库主从复制/读写分离
Mycat读写分离
Mycat有java语言所编写的一个数据库分库分表中间件
原理图
Mycat介绍
Mycat是数据库分库分表中间件, 是一个活跃的、性能好的开源数据库中间件!
关键特性如下: (可从官网中查看更多)
1. Mycat下载
下载地址: http://dl.mycat.org.cn/
我下载版本为1.7, 不同版本应该大体步骤类似,
可参考使用文档: https://github.com/MyCATApache/Mycat-Server/wiki
2. 安装Mycat
解压
上传到服务器并解压 (使用tar -zxvf 命令解压即可)
3. 配置MyCat
配置文件在 Mycat根目录/conf
下
3.1 配置server.xml
端口: <property name="serverPort">8066</property>
端口一般不需要配置, 默认为8066
在server.xml底部配置用户, 例如:
<user name="root"> <!-- 用户名 -->
<property name="password">123456</property> <!-- 密码 -->
<property name="schemas">jtdb</property> <!-- 数据库 -->
</user>
以上配置对应mysql中的配置如下
# 数据库的IP写MyCat服务所在主机的IP (公网/私网)
spring.datesource.url=jdbc:mysql://xxx.xxx.xxx.xxx:8066/jtdb
# Mycat中配置的用户名
spring.datasource.username=root
# Mycat中配置的密码
spring.datasource.password=123456
3.2 配置schema.xml
dataHost标签内部进行读写配置
例如有两台数据库服务器, ip分别为 192.168.126.129 和 192.168.126.130, 其中前者为主库, 后者为从库, 如下配置
<!-- writeHost标签配置 [写]数据库, 内部的readHost标签配置 [读]数据库 -->
<!-- 下面配置表示主数据库可写,可读. 从数据库只可读 -->
<!-- user属性和password属性分别代表指定ip的数据库用户名和密码 -->
<writeHost host="hostM1" url="192.168.126.129:3306" user="root" password="123456">
<!--读数据库1-->
<readHost host="hostS1" url="192.168.126.130:3306" user="root" password="123456" />
<!--读数据库2-->
<readHost host="hostS2" url="192.168.126.129:3306" user="root" password="123456" />
</writeHost>
因为一台主数据库对应多个从数据库, 上面这种配置就很合理, (一个写对应多个读)
4. Mycat运行命令
进入到Mycat的bin目录, 来启动Mycat, 启动之后最好进行一次检测状态操作, 确保Mycat已经启动
./mycat start 启动命令
./mycat status 检查状态
./mycat restart 重启命令
./mycat stop 停止命令
5. 检测负载均衡
以上配置完成后, 读可以从两个数据库读, 写只能写主库.
我们可以试着改变从库的数据, 这时候主库数据不会发生变化, 在项目中查询这个数据返回到页面, 可以看到两个数据库中不同的结果, 就说明成功了 (但是切记, 测试完成后, 记得改回原来从库中的shuj,使两个数据库中数据保持一致, 防止不必要的崩溃)
数据库的高可用
上面的配置中, 当主数据库发生故障时, 数据库则无法使用, 从数据库不能代替主数据库进行工作
实现数据库的高可用可以进行双向绑定, 即双主模式
双主模式图解
配置2台数据 互为主从. 这样的效果可以保证在主库宕机的之后,用户操作都是从库.当主库重启之后,从库会把数据同步给主库.最终实现了数据的一致性.
1. 实现主从挂载
两台服务器互相挂载 (不是单向挂载), 挂载方法参考 [点击跳转挂载方法]
双向绑定完成后记得重启数据库服务
2. 配置schema.xml
添加一个writeHost
标签, 并且确保dataHost
标签的switchType
属性值为1
dataHost完整配置如下:
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select 1</heartbeat>
<writeHost host="hostM1" url="192.168.126.129:3306" user="root" password="root">
<!--读数据库1-->
<readHost host="hostS1" url="192.168.126.130:3306" user="root" password="root" />
<!--读数据库2-->
<readHost host="hostS2" url="192.168.126.129:3306" user="root" password="root" />
</writeHost>
<writeHost host="hostM2" url="192.168.126.130:3306" user="root" password="root">
<!--读数据库1-->
<readHost host="hostS1" url="192.168.126.130:3306" user="root" password="root" />
<!--读数据库2-->
<readHost host="hostS2" url="192.168.126.129:3306" user="root" password="root" />
</writeHost>
</dataHost>
3. 重启Mycat
在Mycat的bin中
./mycat restart # 重启
./mycat status # 查看运行状态
schema配置解析
完整文件
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!--name属性是自定义的 dataNode表示数据库的节点信息 jtdb表示逻辑库-->
<schema name="jtdb" checkSQLschema="false" sqlMaxLimit="100" dataNode="jtdb"/>
<!--定义节点名称/节点主机/数据名称-->
<dataNode name="jtdb" dataHost="localhost1" database="jtdb" />
<!--参数介绍-->
<!--balance 0表示所有的读操作都会发往writeHost主机 -->
<!--1表示所有的读操作发往readHost和闲置的主节点中-->
<!--writeType=0 所有的写操作都发往第一个writeHost主机-->
<!--writeType=1 所有的写操作随机发往writeHost中-->
<!--dbType 表示数据库类型 mysql/oracle-->
<!--dbDriver="native" 固定参数 不变-->
<!--switchType=-1 表示不自动切换, 主机宕机后不会自动切换从节点-->
<!--switchType=1 表示会自动切换(默认值)如果第一个主节点宕机后,Mycat会进行3次心跳检测,如果3次都没有响应,则会自动切换到第二个主节点-->
<!--并且会更新/conf/dnindex.properties文件的主节点信息 localhost1=0 表示第一个节点.该文件不要随意修改否则会出现大问题-->
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select 1</heartbeat>
<!--配置第一台主机主要进行写库操作,在默认的条件下Mycat主要操作第一台主机在第一台主机中已经实现了读写分离.因为默认写操作会发往137的数据库.读的操作默认发往141.如果从节点比较忙,则主节点分担部分压力.
-->
<writeHost host="hostM1" url="192.168.126.129:3306" user="root" password="root">
<!--读数据库1-->
<readHost host="hostS1" url="192.168.126.130:3306" user="root" password="root" />
<!--读数据库2-->
<readHost host="hostS2" url="192.168.126.129:3306" user="root" password="root" />
</writeHost>
<!--定义第二台主机 由于数据库内部已经实现了双机热备.-->
<!--Mycat实现高可用.当第一个主机137宕机后.mycat会自动发出心跳检测.检测3次.-->
<!--如果主机137没有给Mycat响应则判断主机死亡.则回启东第二台主机继续为用户提供服务.-->
<!--如果137主机恢复之后则处于等待状态.如果141宕机则137再次持续为用户提供服务.-->
<!--前提:实现双机热备.-->
<writeHost host="hostM2" url="192.168.126.130:3306" user="root" password="root">
<!--读数据库1-->
<readHost host="hostS1" url="192.168.126.130:3306" user="root" password="root" />
<!--读数据库2-->
<readHost host="hostS2" url="192.168.126.129:3306" user="root" password="root" />
</writeHost>
</dataHost>
</mycat:schema>
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="nonePasswordLogin">0</property> <!-- 0为需要密码登陆、1为不需要密码登陆 ,默认为0-->
<property name="useHandshakeV10">1</property>
<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 | type 2 NettyBufferPool -->
<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">64k</property>
<!--
单位为k
-->
<property name="spillsFileBufferSize">1k</property>
<property name="useStreamOutput">0</property>
<!--
单位为m
-->
<property name="systemReserveMemorySize">384m</property>
<!--是否采用zookeeper协调切换 -->
<property name="useZKSwitch">true</property>
<!-- XA Recovery Log日志路径 -->
<!--<property name="XARecoveryLogBaseDir">./</property>-->
<!-- XA Recovery Log日志名称 -->
<!--<property name="XARecoveryLogBaseName">tmlog</property>-->
</system>
<!-- 全局SQL防火墙设置 -->
<!--白名单可以使用通配符%或着*-->
<!--例如<host host="127.0.0.*" user="root"/>-->
<!--例如<host host="127.0.*" user="root"/>-->
<!--例如<host host="127.*" user="root"/>-->
<!--例如<host host="1*7.*" user="root"/>-->
<!--这些配置情况下对于127.0.0.1都能以root账户登录-->
<!--
<firewall>
<whitehost>
<host host="1*7.0.0.*" user="root"/>
</whitehost>
<blacklist check="false">
</blacklist>
</firewall>
-->
<user name="root">
<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:server>