一、什么是主从复制?
主从复制的原理 : 简而言之,MySQL-A在进行写操作时,都会更新数据库A的二进制sql日志,通过网络传输将二进制sql日志传递给数据库B,B再将二进制sql日志写入B数据库,完成主从复制。
影响MySQL-A数据库的操作,在数据库执行后,都会写入本地的日志系统A中。
假设,实时的将变化了的日志系统中的数据库事件操作,在MYSQL-A的3306端口,通过网络发给MYSQL-B。
MYSQL-B收到后,写入本地日志系统B,然后一条条的将数据库事件在数据库中完成。
那么,MYSQL-A的变化,MYSQL-B也会变化,这样就是所谓的MYSQL的复制,即MYSQL replication。
在上面的模型中,MYSQL-A就是主服务器,即master,MYSQL-B就是从服务器,即slave。
日志系统A,其实它是MYSQL的日志类型中的二进制日志,也就是专门用来保存修改数据库表的所有动作,即bin log。【注意 MYSQL会在执行语句之后,释放锁之前,写入二进制日志,确保事务安全】
日志系统B,并不是二进制日志,由于它是从MYSQL-A的二进制日志复制过来的,并不是自己的数据库变化产生的,有点接力的感觉,称为中继日志,即relay log。
可以发现,通过上面的机制,可以保证MYSQL-A和MYSQL-B的数据库数据一致,但是时间上肯定有延迟,即MYSQL-B的数据是滞后的。
【即便不考虑什么网络的因素,MYSQL-A的数据库操作是可以并发的执行的,但是MYSQL-B只能从relay log中读一条,执行下。因此MYSQL-A的写操作很频繁,MYSQL-B很可能跟不上。】
主从复制解决的问题:
①数据如何不被丢失
②备份
③读写分离
④数据库负载均衡
⑤高可用
关于Mysql主从复制的配置,主从复制是Mysql自带的功能,跟MyCat没有关系!!!
实验环境:
使用一台主服务器(20.0.0.11),一台从服务器(20.0.0.12)
3.1 建立时间同步环境
1.在主机Master搭建时间同步服务器NTP (20.0.0.11)
[root@localhost ~]# yum -y install ntp
[root@localhost ~]# vi/etc/ntp.conf
插入下面两行内容
server 127.127.1.0
fudge 127.127.1.0 stratum 8
重启服务
[root@localhost ~]# service ntpd restart
[root@localhost ~]# systemctl restart ntpd
[root@localhost ~]# systemctl enable ntpd
2.在从服务器上配置NTP同步(20.0.0.12)
[root@localhost ~]# yum -y install ntpdate
[root@localhost ~]# ntpdate 20.0.0.11
3.从服务器(20.0.0.12)添加计划任务
[root@localhost ~]# crontab -e
*/2 * * * * /usr/sbin/ntpdate 20.0.0.11 >>/var/log/ntpdate.log
[root@localhost ~]# systemctl restart crond
[root@localhost ~]# systemctl enable crond
动态查看更新日志文件
[root@localhost~]# tail -f/var/log/ntpdate.log
3.2 编译安装MySQL
1.安装MySQL环境依赖包
yum -y install
gcc
gcc-c++
make
ncurses
ncurses-devel
bison
cmake
2.创建运行用户
useradd -s /sbin/nologin mysql
3.编译安装
上传mysql-boost-5.7.20.tar.gz到opt目录下
cd /opt
tar xf mysql-boost-5.7.20.tar.gz
cd /opt/mysql-5.7.20/
cmake
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql
-DMYSQL_UNIX_ADDR=/usr/local/mysql/mysql.sock
-DSYSCONFDIR=/etc
-DSYSTEMD_PID_DIR=/usr/local/mysql
-DDEFAULT_CHARSET=utf8
-DDEFAULT_COLLATION=utf8_general_ci
-DWITH_INNOBASE_STORAGE_ENGINE=1
-DWITH_ARCHIVE_STORAGE_ENGINE=1
-DWITH_BLACKHOLE_STORAGE_ENGINE=1
-DWITH_PERFSCHEMA_STORAGE_ENGINE=1
-DMYSQL_DATADIR=/usr/local/mysql/data
-DWITH_BOOST=boost
-DWITH_SYSTEMD=1
make &&make install
4.改属主和属组
chown -R mysql:mysql /usr/local/mysql/
5.调整配置文件
vi /etc/my.cnf
[client]
port = 3306
default-character-set=utf8
socket = /usr/local/mysql/mysql.sock
[mysql]
port = 3306
default-character-set=utf8
socket = /usr/local/mysql/mysql.sock
[mysqld]
user = mysql
basedir = /usr/local/mysql
datadir = /usr/local/mysql/data
port = 3306
character_set_server=utf8
pid-file = /usr/local/mysql/mysqld.pid
socket = /usr/local/mysql/mysql.sock
server-id = 1
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_AUTO_VALUE_ON_ZERO,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,PIPES_AS_CONCAT,ANSI_QUOTES
6.改属主和属组
chown mysql:mysql /etc/my.cnf
7.设置环境变量
echo ‘PATH=/usr/local/mysql/bin:/usr/local/mysql/lib:$PATH’ >> /etc/profile
echo ‘export PATH’ >> /etc/profile
刷新一下环境变量,使其生效
[root@localhost ~]# source /etc/profile
8.初始化数据库
cd /usr/local/mysql/
bin/mysqld
–initialize-insecure
–user=mysql
–basedir=/usr/local/mysql
–datadir=/usr/local/mysql/data
cp usr/lib/systemd/system/mysqld.service /usr/lib/systemd/system/
9.数据库开机自启、开启、状态
systemctl enable mysqld
systemctl start mysqld
systemctl status mysqld
10.查看服务是否开启
netstat -anpt | grep 3306
若无此条命令,可执行 yum -y install net-tools命令安装
11.设置数据库密码
mysqladmin -u root -p password
3.3 配置主服务器
1.把server-id = 1改成11
vi /etc/my.cnf
server-id = 11
log_bin = master-bin
log-slave-updates = true
:wq
重启数据库
systemctl restart mysqld
2.登录master数据库,给从服务器授权
mysql> grant replication slave on . to ‘myslave’@‘20.0.0.%’ identified by ‘123’;
Query OK, 0 rows affected, 1 warning (0.06 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> show master status;
±-----------------±---------±-------------±-----------------±------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
±-----------------±---------±-------------±-----------------±------------------+
| mysql-bin.000005 | 599 | | | |
±-----------------±---------±-------------±-----------------±------------------+
1 row in set (0.00 sec)
3.4 配置从服务器
1.安装MySQL数据库,步骤同上。
2.登录从服务器(20.0.0.12),修改/etc/my.cnf配置文件
server-id = 22
relay-log=relay-log-bin
relay-log-index = slave-relay-bin.index
:wq
重启数据库
systemctl restart mysqld
3.登录slave数据库,配置同步(注意要和刚才查看的master数据库信息一致)
mysql> change master to master_host=‘20.0.0.11’,master_user=‘myslave’,master_password=‘123’,master_log_file=‘mysql-bin.000005’,master_log_pos=599;
Query OK, 0 rows affected, 2 warnings (0.07 sec)
mysql> start slave;
确保以下两个值为Yes
mysql> show slave status\G;
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
3.5 验证主从复制效果
1.在主、从服务器上登录MySQL;在主服务器上新建数据库luffy
mysql> create database luffy;
Query OK, 1 row affected (0.00 sec)
mysql> show databases;
±-------------------+
| Database |
±-------------------+
| information_schema |
| luffy |
| mysql |
| performance_schema |
| sys |
±-------------------+
2.登录从服务器MySQL进行查看
mysql> show databases;
±-------------------+
| Database |
±-------------------+
| information_schema |
| luffy |
| mysql |
| performance_schema |
| sys |
±-------------------+
实验成功。
读写分离
1、什么是读写分离?
在数据库集群架构中,让主库负责处理事务性查询,而从库只负责处理select查询,让两者分工明确达到提高数据库整体读写性能。当然,主数据库另外一个功能就是负责将事务性查询导致的数据变更同步到从库中,也就是写操作。
2、读写分离的好处?
1)分摊服务器压力,提高机器的系统处理效率
读写分离适用于读远比写的场景,如果有一台服务器,当select很多时,update和delete会被这些select访问中的数据堵塞,等待select结束,并发性能并不高,而主从只负责各自的写和读,极大程度的缓解X锁和S锁争用;
假如我们有1主3从,不考虑上述1中提到的从库单方面设置,假设现在1分钟内有10条写入,150条读取。那么,1主3从相当于共计40条写入,而读取总数没变,因此平均下来每台服务器承担了10条写入和50条读取(主库不承担读取操作)。因此,虽然写入没变,但是读取大大分摊了,提高了系统性能。另外,当读取被分摊后,又间接提高了写入的性能。所以,总体性能提高了,说白了就是拿机器和带宽换性能;
2)增加冗余,提高服务可用性,当一台数据库服务器宕机后可以调整另外一台从库以最快速度恢复服务
3、主从复制原理
依赖于二进制日志,binary-log. 二进制日志中记录引起数据库发生改变的语句Insert 、delete、update、create table,读写分离需要主从复制的支持。
4、Scale-up与Scale-out区别
Scale Out是指Application可以在水平方向上扩展。一般对数据中心的应用而言,Scale out指的是当添加更多的机器时,应用仍然可以很好的利用这些机器的资源来提升自己的效率从而达到很好的扩展性。
Scale Up是指Application可以在垂直方向上扩展。一般对单台机器而言,Scale Up值得是当某个计算节点(机器)添加更多的CPU Cores,存储设备,使用更大的内存时,应用可以很充分的利用这些资源来提升自己的效率从而达到很好的扩展性。
5、使用Mycat实现读写分离
Mycat是一个开源的分布式数据库系统,但是因为数据库一般都有自己的数据库引擎,而Mycat并没有属于自己的独有数据库引擎,所有严格意义上说并不能算是一个完整的数据库系统,只能说是一个在应用和数据库之间起桥梁作用的中间件。
在Mycat中间件出现之前,MySQL主从复制集群,如果要实现读写分离,一般是在程序段实现,这样就带来了一个问题,即数据段和程序的耦合度太高,如果数据库的地址发生了改变,那么我的程序也要进行相应的修改,如果数据库不小心挂掉了,则同时也意味着程序的不可用,而对于很多应用来说,并不能接受;
引入Mycat中间件能很好地对程序和数据库进行解耦,这样,程序只需关注数据库中间件的地址,而无需知晓底层数据库是如何提供服务的,大量的通用数据聚合、事务、数据源切换等工作都由中间件来处理;
Mycat中间件的原理是对数据进行分片处理,从原有的一个库,被切分为多个分片数据库,所有的分片数据库集群构成完成的数据库存储,有点类似磁盘阵列中的RAID0.
主机 操作系统 IP地址 主要软件
amoeba centos-7.4-X86_64 20.0.0.13 amoeba-mysql-3.0.5-RC-distribution.zip
jdk-8u144-linux-x64.tar.gz
Master centos-7.4-X86_64 20.0.0.11 mysql-boost-5.7.20.tar.gz ntp
Slave1 centos-7.4-X86_64 20.0.0.12 mysql-boost-5.7.20.tar.gz ntpdate
客户机 centos-7.4-X86_64 20.0.0.100 mysql-boost-5.7.20.tar.gz
注意
master、slave1关闭防火墙与核心防护
amoeba服务器所需软件包
jdk-6u14-linux-x64.bin
amoeba-mysql-binary-2.2.0.tar.gz
4.4 amoeba服务器搭建
4.4.1 卸载原有java环境
[root@localhost ~]# java -version #确定java版本 1.8.0_181的 有点高
openjdk version “1.8.0_181”
OpenJDK Runtime Environment (build 1.8.0_181-b13)
OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)
[root@localhost ~]# rpm -qa |grep java
查出openjdk相关的文件并且删除它
[root@localhost ~]# rpm -e --nodeps java-1.8.0-openjdk-headless-1.8.0.181-7.b13.el7.x86_64
[root@localhost ~]# rpm -e --nodeps java-1.8.0-openjdk-1.8.0.181-7.b13.el7.x86_64
[root@localhost ~]# rpm -e --nodeps java-1.7.0-openjdk-1.7.0.191-2.6.15.5.el7.x86_64
[root@localhost ~]# rpm -e --nodeps java-1.7.0-openjdk-headless-1.7.0.191-2.6.15.5.el7.x86_64
4.4.2 安装jdk
上传JDK到opt目录
[root@localhost ~]# cd /opt
[root@localhost opt]# tar xzvf jdk-8u144-linux-x64.tar.gz
[root@localhost opt]# cp -rv jdk1.8.0_144/ /usr/local/java
[root@localhost opt]# vi /etc/profile
export JAVA_HOME=/usr/local/java
export JRE_HOME=/usr/local/java/jre
export PATH=$PATH:/usr/local/java/bin
export CLASSPATH=./:/usr/local/java/lib:/usr/local/java/jre/lib
[root@localhost opt]# source /etc/profile
[root@localhost opt]# java -version java环境变成1.8.0_144
4.4.3 安装amoeba
资源获取地址:(https://sourceforge.net/projects/amoeba/files/)
[root@localhost opt]# yum -y install unzip #如果unzip命令没有,必须装下
[root@localhost opt]# unzip amoeba-mysql-3.0.5-RC-distribution.zip -d /usr/local/
[root@localhost opt]# mv /usr/local/amoeba-mysql-3.0.5-RC/ /usr/local/amoeba
[root@localhost opt]# chmod -R 755 /usr/local/amoeba/
[root@localhost opt]#vi /usr/local/amoeba/jvm.properties
JVM_OPTIONS="-server -Xms256m -Xmx1024m -Xss196k -XX:PermSize=16m -XX:MaxPermSize=96m" #32行修改成如下
JVM_OPTIONS="-server -Xms1024m -Xmx1024m -Xss256k"
4.4.4 制作amoeba管理脚本
[root@localhost opt]# vi /etc/init.d/amoeba
#!/bin/bash
#chkconfig: 35 62 62
#
export JAVA_HOME=/usr/local/java
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
NAME=Amoeba
AMOEBA_BIN=/usr/local/amoeba/bin/launcher
SHUTDOWN_BIN=/usr/local/amoeba/bin/shutdown
PIDFILE=/usr/local/amoeba/Amoeba-MySQL.pid
SCRIPTNAME=/etc/init.d/amoeba
case "$1" in
start)
echo -n "Starting $NAME... "
$AMOEBA_BIN
echo " done"
;;
stop)
echo -n "Stoping $NAME... "
$SHUTDOWN_BIN
echo " done"
;;
restart)
$SHUTDOWN_BIN
sleep 1
$AMOEBA_BIN
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|restart}"
exit 1
;;
esac
:wq
[root@localhost opt]# chmod +x /etc/init.d/amoeba
[root@localhost opt]# chkconfig --add amoeba
[root@localhost opt]# service amoeba start
ctrl + c
[root@localhost opt]# netstat -anpt | grep 8066 //默认监听在8066端口
4.4.5 在两台MySQL数据库中为amoeba授权
登录20.0.0.11终端
[root@localhost ~]# mysql -u root -p #输入密码
mysql> create database test;
Query OK, 1 row affected (0.01 sec)
mysql> GRANT ALL ON . TO test@‘20.0.0.%’ IDENTIFIED BY ‘123’;
mysql> FLUSH PRIVILEGES;
mysql> quit
登录20.0.0.12终端
[root@localhost ~]# mysql -u root -p #输入密码
mysql> GRANT ALL ON . TO test@‘20.0.0.%’ IDENTIFIED BY ‘123’;
mysql> FLUSH PRIVILEGES;
mysql> quit
4.4.6 修改amoeba的两个配置文件
amoeba.xml
dbServers.xml
amoeba.xml:用来控制读写分离
[root@localhost opt]# cd /usr/local/amoeba
[root@localhost amoeba]# vi conf/amoeba.xml
#修改如下参数
amoeba
123
–83-去掉注释-同时把默认的server1改成master,把默认的servers改成 slaves
<property name="defaultPool">master</property>
<property name="writePool">master</property>
<property name="readPool">slaves</property>
dbServers.xml:用来跳转数据库
[root@localhost amoeba]# vi conf/dbServers.xml
<property name="schema">test</property>
<property name="user">test</property>
<property name="password">123</property>
<dbServer name="master" parent="abstractServer">
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">20.0.0.11</property>
</factoryConfig>
</dbServer>
<dbServer name="slave1" parent="abstractServer">
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">20.0.0.12</property>
</factoryConfig>
</dbServer>
<property name="poolNames">slave1</property>
重启服务
[root@localhost amoeba]# service amoeba restart
[root@localhost amoeba]# netstat -anpt | grep java
4.5 登录客户端测试
测试用客户端 20.0.0.100
装上数据库
[root@localhost ~]# mysql -u amoeba -p123 -h 20.0.0.13 -P8066
在主mysql(20.0.0.11)上创建数据库
[root@localhost ~]# mysql -u root -p
mysql> use test;
Database changed
mysql> create table zhang1 (id int(10),name varchar(10),address varchar(20));
在从mysql(20.0.0.12)上关闭同步
[root@localhost ~]# mysql -u root -p
mysql> stop slave;
mysql> use test;
Database changed
mysql> insert into zhang1 values(‘2’,‘zhang’,‘this_is_slave1’);
在主mysql(20.0.0.11)上插入数据
[root@localhost ~]# mysql -u root -p
mysql> use test;
Database changed
mysql> insert into zhang1 values(‘1’,‘zhang’,‘this_is_master’);
登录客户端(20.0.0.100)
[root@localhost ~]# mysql -u amoeba -p123 -h 20.0.0.13 -P8066
MySQL [(none)]> show databases;
±-------------------+
| Database |
±-------------------+
| information_schema |
| db_test |
| mysql |
| performance_schema |
| sys |
| test | 发现数据库test
±-------------------+
在客户机上20.0.0.100继续写数据,按照正常的规则应该是slave1看不见的
MySQL [(none)]> use test;
Database changed
MySQL [test]> insert into zhang1 values(‘4’,‘zhang’,‘write_test’);
Query OK, 1 row affected (0.01 sec)
登录mastar(20.0.0.11)
[root@localhost ~]# mysql -u root -p
mysql> use test;
Database changed
mysql> select * from zhang1;
±-----±------±---------------+
| id | name | address |
±-----±------±---------------+
| 1 | zhang | this_is_master |
| 4 | zhang | write_test |
±-----±------±---------------+
2 rows in set (0.00 sec)
登录slave1(20.0.0.12)
[root@localhost ~]# mysql -u root -p
mysql> use test;
Database changed
mysql> select * from zhang1;
±-----±------±---------------+
| id | name | address |
±-----±------±---------------+
| 2 | zhang | this_is_slave1 |
±-----±------±---------------+
1 row in set (0.00 sec)
验证结果:
在客户端(20.0.0.100)上操作写入数据,数据是往master上写的,在salve1上看不到写的数据