文章目录
MySQL主从复制和基于Amoeba读写分离
什么是主从复制?
MySQL主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点。MySQl默认采用异步复制方式(还有多线程复制、半同步复制),这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以在远程连接上进行,从节点可以复制主数据库中的所有数据库或者特定的数据库或者特定的表。
简单理解就是:通过复制(异步、同步等方式)建立一个和主数据库完全一样的从数据库,从数据库会实时同步(复制)主数据库的记录。
为什么要有MySQL主从复制?
一是确保数据安全;做数据的热备,作为后备数据库,主数据库服务器故障后,可切换到从数据库继续工作,避免数据的丢失。
二是读写分离,使数据库能支持更大的并发;在报表中尤其重要。由于部分报表sql语句非常的慢,导致锁表,影响前台服务。如果前台使用master,报表使用slave,那么报表sql将不会造成前台锁,保证了前台速度。
三是提升I/O性能;随着日常生产中业务量越来越大,I/O访问频率越来越高,单机无法满足,此时做多库的存储,实现多个库提供读,有效降低磁盘I/O访问的频率,提高了单个设备的I/O性能。
主从复制从基础来讲,就是实现数据库主节点和从节点的数据同步,实现数据的备份,在主从的基础上可以通过读写分离,主设备写,从设备提供读,实现数据的负载分担(因为数据库写的时候会🔒表,无法读,但从节点是空闲的,所以从节点可以提供读)。这样降低了主节点的I/O访问频率,从而降低了主节点磁盘的I/O的压力。
什么是读写分离?
读写分离是指将数据库的读和写操作分不到不同的数据库节点上。主服务器负责处理写操作和实时性要求较高的读操作,从服务器负责处理读操作。
一、MySQL主从复制原理
MySQL的主从复制就是,主数据库开启二进制日志,从数据库把主数据库的二进制日志复制到本地的一个中继日志中,再通过执行日志中的SQL语句,实现主从的数据同步。其实和二进制日志备份类似,通过二进制日志记录数据库的修改SQL语句,实现对数据库数据的修改,主和从执行相同SQL语句不就是数据同步了。
二、主从复制的工作过程
1、主数据库开启二进制日志,记录修改SQL语句。
2、从数据库手动执行更改主数据库(change master to)语句连接主数据库。
3、从数据库的IO线程和主数据库的dump线程建立连接。
4、从数据库的IO线程向主数据库发出binglog请求,主数据库的dump线程响应请求,将本地的binlog以events事件的方式发送给从数据库的IO线程。
5、从数据库IO线程接收后binlog数据后,存放到Relay log中。
6、从数据库的SQL线程读取Relay log,并且把应用过的记录到relay-log.info中,在默认的情况下,应用过的relay log中的数据会被清理掉,所以relay log因为其消耗小,所以存放在缓存中(binglog存放在磁盘中)。
两个日志:
-
Binglog:用来记录mysql内部增删改查等对mysql数据库有更新的内容的记录。
-
Relay-log:用于存放从主数据库发送过来的Binlog日志的数据,其中存放的是已经解析成各类events的记录。
三个线程:
-
dump线程:当binlog有变动时,log dump线程读取其内容发送个从节点的IO线程。
-
IO线程:负责与主数据库建立连接,并发出请求,以及接收dump发送的binlog并存放到relay log中。
-
SQL线程:会读取relay log中数据,运行其中的SQL语句,实现数据存放到从数据库中。
三、主从复制方式
1、异步复制方式
MySQL异步复制是主从复制过程中默认的复制模式。主从复制涉及三个线程,master I/O线程、slave I/O线程、slave sql线程。因为是异步复制,所以master事务的提交,不需要经过slave的确认,即master I/O线程提交事务后,不需要等待slave I/O线程的回复确认,master并不保证binlog一定写入到了relay log中;而slave I/O把binlog写入relay log后,由slave sql线程异步执行应用到slave mysql中,slave I/O也不需要slave sql的回复确认,并不保证relay log日志完整写入到了mysql中。
2、半同步复制/增强半同步复制
基于传统异步存在的缺陷,mysql在5.5版本推出半同步复制,是对传统异步复制的改进。在master事务commit前,必须确保binlog日志已经写入slave 的relay log日志中,收到slave给master的响应后,才能进行事务的commit。但是后半部分的relay log到sql线程仍然属于异步执行。
增强半同步是在MySQL 5.7引入,其实半同步可以看成是一个过渡功能,因为默认的配置就是增强半同步,所以,大家一般说的半同步复制其实就是增强的半同步复制,也就是无损复制。
增强半同步和半同步不同的是,等待ACK时间不同
rpl_semi_sync_master_wait_point = AFTER_SYNC(默认)
半同步的问题是因为等待ACK的点是Commit之后,此时Master已经完成数据变更,用户已经可以看到最新数据,当Binlog还未同步到Slave时,发生主从切换,那么此时从库是没有这个最新数据的,用户看到的是老数据。
增强半同步将等待ACK的点放在提交Commit之前,此时数据还未被提交,外界看不到数据变更,此时如果发送主从切换,新库依然还是老数据,不存在数据不一致的问题。
3、全同步复制
指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。
4、多线程复制
在MySQL5.7中,带来了全新的多线程复制技术,解决了当master同一个schema下的数据发生了变更,从库不能并发应用的问题,同时也真正将binlog组提交的优势充分发挥出来,保障了从库并发应用Relay Log的能力。
在MySQL8.0中,多线程复制又进行了技术更新,引入了writeset的概念,而在之前的版本中,如果主库的同一个会话顺序执行多个不同相关对象的事务,例如,先执行了Update A表的数据,又执行了Update B表的数据,那么BINLOG在复制到从库后,这两个事务是不能并行执行的,writeset的到来,突破了这个限制。
四、MySQL读写分离原理
1、读写分离存在意义
- 因为数据库的“写”(写10000条数据可能要3分钟)操作是比较耗时的。
- 但是数据库的“读”(读10000条数据可能只要5秒钟)。
- 所以读写分离,解决的是,数据库的写入,影响了查询的效率
2、常见的 MySQL 读写分离分为两种
1、基于程序代码内部实现
- 在代码中根据 select、insert 进行路由分类,这类方法也是目前生产环境应用最广泛的。
- 优点是性能较好,因为在程序代码中实现,不需要增加额外的设备为硬件开支;缺点是需要开发人员来实现,运维人员无从下手。
- 但是并不是所有的应用都适合在程序代码中实现读写分离,像一些大型复杂的Java应用,如果在程序代码中实现读写分离对代码改动就较大。
2、基于中间代理层实现
代理一般位于客户端和服务器之间,代理服务器接到客户端请求后通过判断后转发到后端数据库,有以下代表性程序:
- MySQL-Proxy。MySQL-Proxy 为 MySQL 开源项目,通过其自带的 lua 脚本进行SQL 判断。
- Atlas。是由奇虎360的Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目。它是在mysql-proxy 0.8.2版本的基础上,对其进行了优化,增加了一些新的功能特性。360内部使用Atlas运行的mysql业务,每天承载的读写请求数达几十亿条。支持事物以及存储过程。
- Amoeba。由陈思儒开发,作者曾就职于阿里巴巴。该程序由Java语言进行开发,阿里巴巴将其用于生产环境。但是它不支持事务和存储过程。
五、MySQL主从复制部署
IP地址划分
主机名 | IP地址 | 角色说明 |
---|---|---|
server-test1 | 192.168.10.11 | Master |
server-test2 | 192.168.10.12 | slave1 |
1、关闭防火墙和SELinux增强模块
systemctl stop firewalld
systemctl disable firewalld
setenforce 0
2、设置MySQL主从服务器时钟同步(NTP)
2.1、搭建NTP服务器
将NTP服务器搭建在MySQL主服务器上(192.168.10.11)。
yum -y install ntp
NTP服务配置文件
各项参数详解
————————————————————————————————————————
vi /etc/ntp.conf
#系统时间与BIOS事件的偏差记录
driftfile /var/lib/ntp/drift
restrict default kod nomodify notrap nopeer noquery # 拒绝所有IPv4的client连接此NTP服务器
restrict -6 default kod nomodify notrap nopeer noquery # 拒绝所有IPv6的client连接此NTP服务器
restrict 127.0.0.1 # 放行本机localhost对NTP服务的访问
restrict ::1
# Hosts on local network are less restricted.
#restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap # 放行192.168.1.0网段主机与NTP服务器进行时间同步
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
server 0.centos.pool.ntp.org iburst # 代表的同步时间服务器
server 1.centos.pool.ntp.org iburst
server 2.centos.pool.ntp.org iburst
server 3.centos.pool.ntp.org iburst
#broadcast 192.168.1.255 autokey # broadcast server
#broadcastclient # broadcast client
#broadcast 224.0.1.1 autokey # multicast server
#multicastclient 224.0.1.1 # multicast client
#manycastserver 239.255.254.254 # manycast server
#manycastclient 239.255.254.254 autokey # manycast client
# Enable public key cryptography.
#crypto
includefile /etc/ntp/crypto/pw
# Key file containing the keys and key identifiers used when operating
# with symmetric key cryptography.
keys /etc/ntp/keys
----
各项参数详解
配置NTP配置文件
vim /etc/ntp.conf
在restrict default nomodify notrap nopeer noquery 下添加放行网段。
restrict 192.168.10.0 mask 255.255.255.0 nomodify notrap
# nomodify notrap 表示不允许客户端配置为时间服务器
在末尾添加
server 127.127.1.0 #设置本地是时钟源,注意修改网段
fudge 127.127.1.0 stratum 8 #设置时间层级为8(限制在15内)
systemctl start ntpd
2.2、搭建NTP客户端
yum -y install ntp ntpdate
ntpdate 192.168.10.11 #指定同步NTP服务器
crontab -e
* 1 * * * /usr/sbin/ntpdate 192.168.10.11
3、主服务器的mysql配置
vim /etc/my.cnf
server-id = 1
log-bin=mysql-bin #添加,主服务器开启二进制日志
log-slave-updates=true #添加,允许从服务器更新二进制日志
systemctl restart mysqld
mysql -u root -p
GRANT REPLICATION SLAVE ON *.* TO 'myslave'@'192.168.10.%' IDENTIFIED BY '123456'; #给从服务器授权
FLUSH PRIVILEGES;
show master status;
#File 列显示日志名,Fosition 列显示偏移量
4、从服务器的mysql配置
vim /etc/my.conf
server-id=2
relay-log=relay-log-bin
//开启中继日志
relay-log-index=slave-relay-bin.index
//将中继日志存放至磁盘(中继日志默认存缓存)
relay_log_recovery=1
systemctl restart mysqld
mysql -uroot -p
change master to master_host='192.168.10.11' , master_user='myslave',master_password='123456',master_log_file='mysql-bin.000011',master_log_pos=595;
//在从服务器上指定主服务器 ,偏移量表示主服务器的二进制文件位置变量初始的位置。
start slave; //开启主从复制
show slave status\G //查看主从复制
5、验证
在主服务器上创建一个测试的数据库
create database master_test;
再在从服务器上查看
show databases;
6、在原有主从的基础上再追加部署一台从服务器slave2
设置NTP
yum -y install ntp ntpdate
ntpdate 192.168.10.11 #指定同步NTP服务器
crontab -e
* 1 * * * /usr/sbin/ntpdate 192.168.10.11
配置mysql配置文件
vim /etc/my.conf
server-id=3
relay-log=relay-log-bin
relay-log-index=slave-relay-bin.index
relay_log_recovery=1
//relay_log_recovery,当slave从库宕机后,假如relay-log损坏了,导致一部分中继日志没有处理,则自动放弃所有未执行的relay-log,并且重新从master上获取日志,这样就保证了relay-log的完整性。默认情况下该功能是关闭的,将relay_log_recovery的值设置为 1时,可在slave从库上开启该功能,建议开启;
systemctl restart mysqld
将主服务器数据导入到从服务器中
flush tables with read lock; //锁表防止后续数据写入,导致主从数据不一致
mysqldump -uroot -p -A --master-data=1 > /opt/mysql_all.sql //完全备份
scp -p /opt/mysql_all.sql root@192.168.10.13:/opt //将备份文件发送到slave2
mysql -uroot -p < /opt/mysql_all.sql //slave2同步master数据
配置slave2主从复制配置
查看当前master二级制文件名和偏移量
show master status;
mysql -uroot -p
change master to master_host='192.168.10.11' , master_user='myslave',master_password='123456',master_log_file='mysql-bin.000011',master_log_pos=775;
//在从服务器上指定主服务器 ,偏移量表示主服务器的二进制文件位置变量初始的位置。
start slave; //开启主从复制
show slave status\G //查看主从复制
解锁主服务器
UNLOCK TABLES ;
六、MySQL主从渎职和读写分离部署
服务部署表
应用名 | server-test1 | server-test2 | server-test3 | server-test4 | |
---|---|---|---|---|---|
MySQL | √ | √ | √ | ||
NTP | √ | ||||
Amoeba | √ |
IP地址规划表
主机名 | IP地址 | 说明 |
---|---|---|
server-test1 | 192.168.10.11 | MySQL master |
server-test2 | 192.168.10.12 | MySQL slave1 |
server-test3 | 192.168.10.13 | MySQL slave2 |
server-test4 | 192.168.10.14 | Amoeba |
部署说明
在之前的主从复制的实验中再添加一台MySQL从服务器和Amoeba服务器。
1、关闭防火墙和SELinux增强模块
systemctl stop firewalld
systemctl disable firewalld
setenforce 0
2、安装java环境
//因为 Amoeba 基于是 jdk1.5 开发的,所以官方推荐使用 jdk1.5 或 1.6 版本,高版本不建议使用。
//将jdk-6u14-linux-x64.bin 和 amoeba-mysql-binary-2.2.0.tar.gz.0 上传到/opt目录下。
cd /opt/
cp jdk-6u14-linux-x64.bin /usr/local/
cd /usr/local/
chmod +x jdk-6u14-linux-x64.bin
./jdk-6u14-linux-x64.bin
按空格到最后一行
按yes,按enter
mv jdk1.6.0_14/ /usr/local/jdk1.6
vim /etc/profile
export JAVA_HOME=/usr/local/jdk1.6
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
export PATH=$JAVA_HOME/lib:$JAVA_HOME/jre/bin/:$PATH:$HOME/bin
export AMOEBA_HOME=/usr/local/amoeba
export PATH=$PATH:$AMOEBA_HOME/bin
source /etc/profile
java -version
##安装 Amoeba软件##
mkdir /usr/local/amoeba
tar zxvf /opt/amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba/
chmod -R 755 /usr/local/amoeba/
/usr/local/amoeba/bin/amoeba
//如显示amoeba start|stop 说明安装成功
3、配置Amoeba读写分离
grant all on *.* to test@'192.168.10.%' identified by '123123';
4、配置amoeba配置文件
cd /usr/local/amoeba/conf/
cp amoeba.xml amoeba.xml.bak
vim amoeba.xml #修改amoeba配置文件
30修改
<property name="user">amoeba</property>
32修改
<property name="password">123123</property>
115修改
<property name="defaultPool">master</property>
117去掉注释–
<property name="writePool">master</property>
<property name="readPool">slaves</property>
cp dbServers.xml dbServers.xml.bak
vim dbServers.xml #修改数据库配置文件
23注释掉
作用:默认进入test库 以防mysql中没有test库时,会报错
<!-- mysql schema
<property name="schema">test</property>
-->
26修改
<!-- mysql user -->
<property name="user">test</property>
28-30去掉注释
<property name="password">123.com</property>
45修改,设置主服务器的名Master
<dbServer name="master" parent="abstractServer">
48修改,设置主服务器的地址
<property name="ipAddress">192.168.184.10</property>
52修改,设置从服务器的名slave1
<dbServer name="slave1" parent="abstractServer">
55修改,设置从服务器1的地址
<property name="ipAddress">192.168.184.30</property>
58复制上面6行粘贴,设置从服务器2的名slave2和地址
<dbServer name="slave2" parent="abstractServer">
<property name="ipAddress">192.168.184.40</property>
65修改
<dbServer name="slaves" virtual="true">
71修改
<property name="poolNames">slave1,slave2</property>
/usr/local/amoeba/bin/amoeba start& #启动Amoeba软件,按ctrl+c 返回
netstat -anpt | grep java #查看8066端口是否开启,默认端口为TCP 8066
5、测试读写分离
节省时间,在Amoeba服务器上安装mysql测试
yum install -y mariadb-server.x86_64 mariadb
//MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可 MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品。在存储引擎方面,使用XtraDB来代替MySQL的InnoDB。
mysql -u amoeba -p123123 -h 192.168.10.14 -P8066
在主服务器上
create database test;
use test;
create table test (test varchar(48) not null primary key );
两台从服务器上
stop slave; #关闭同步
use test;
在slave1上
insert into test values('this is slave1');
在slave2上
stop slave;
insert into test values('this is slave2');
在主服务器上
insert into test values('this is master');
在客户端服务器上
use test;
select * from test; //客户端会分别向slave1和slave2读取数据,显示的只有在两个从服务器上添加的数据,没有在主服务器上添加的数据
进行读写测试
//在客户端上
insert into test values('this is write_test'); //只有主服务器上有此数据
再在两个从服务器上执行 start slave; 即可实现同步在主服务器上添加的数据
start slave;
再次查看各服务器test表的内容