AB复制又称之为主从复制,用于实现数据同步,实现Mysql的AB复制时,数据库的版本尽可能保持一致,若是不能保持一致,最起码从服务器的版本要高于主服务器,可是就没法实现双向复制技术.java
Mysql AB复制的好处
node
1.解决宕机带来的数据不一致问题,由于Mysql复制能够实时备份数据.python
2.多台服务器的性能通常比单台好,且能够减轻数据库服务器的压力,由于备份等操做能够在从服务器上进行,可是AB复制不适用于大数据量,若是是一个主服务器有多台从服务器,那么主服务器须要同时向多台服务器中写入数据,压力会很大,这个时候就推荐使用集群.mysql
Mysql复制(replication)是一个异步的复制,从一个Mysql实例(Master)复制到另外一个Mysql实例(Slave),整个主从复制须要由Master服务器上的IO进程,Slave服务器上的Sql线程和IO线程共同完成,首先Master端必须打开binary log(bin-log),由于整个Mysql复制过程实际上就是Slave从Master端获取相应的二进制日志,而后在本地彻底顺序的执行日志中所记录的各类操做.linux
传统主从复制基本过程:
sql
# 1. Mysql slave端的ID进程链接上Master,向Master请求指定日志文件的指定位置(或者最开始日志)以后的日志内容; # 2. Master接收到来自Slave的IO进程的请求后,负责复制的IO进程根据Slave的请求信息,读取相应日志内容,返回Slave的IO进程,并将相应日志内容返回给Slave的IO进程,并将本次请求读取的bin-log文件名及位置一块儿返回Slave端. # 3. Slave的IO进程接收到信息后,将接收到的日志内容依次添加到Slave端的relay-log文件的最末端,并将读取到的Master端的 bin-log的文件名和位置记录到master-info文件中,以便在下一次读取的时候可以清楚的告诉Master“我须要从某个bin-log的哪一个位置开始日后的日志内容,请发给我”; # 4. Slave的Sql进程检测到relay-log中新增长了内容后,会立刻解析relay-log的内容成为在Master端真实执行时候的那些可执行的内容,并在自身执行。
从库生成两个线程,一个I/O,一个SQL线程,I/O线程去请求主库的binlog,并将获得的binlog日志写到relay log(中继日志)文件中;
数据库
主库会生成一个Log dump线程,用来给从库I/O线程传binlog;
安全
从库的SQL线程会读取relay log文件的日志,并解析成具体操做,从而实现主从数据一致
bash
# 两个进程一个线程 # IO进程: 负责下载日志,中继日志 # SQL进程: SQL负责将中继日志应用到数据库中,完成AB复制数据同步. # logdump线程:
# 1. 同步复制 # master服务器操做完成,当操做做为时间写入二进制日志,传递给slave,存放到中继日志中,而后再本地执行完成功,即反馈成功. # 2. 半同步复制 # 当有多台slave服务器时,master向离本身最近的slave服务器同步二进制文件后,即为反馈成功,不是Mysql官方提供的,是5.5版本时google研发半同步不定后支持,须要semi插件. # 3. 异步复制: # Master服务器操做完成,当操做做为事件写入二进制日志,即反馈成功(默认) # 4. 基于GTID复制技术(5.6版本才有) # 见下面 # 5. 多源复制(5.7) # 1. 方便备份数据 # 2. 方便对数据进行统一分析
1. 使用GITD技术可让两台服务器自动交换事务ID,通过对比,请求数据,保证服务器之间的数据是同步的;
服务器
2. 提高安全性,多事务并行执行时,也不会形成数据混乱;
3. 多线程复制,从服务器能够启动多个SQL Threfad,并发执行多个库的复制,提高速度
网络问题
# 要注意mysql主库和从库所在服务器间的网络问题,由于是要作数据库的主从,主从之间的网络是要能通的,及从库可经过网络访问到主库,不然没法同步数据. # 若是mysql主从使用的是云服务器,注意去该云服务器的管理平台,开放相应数据库的安全组(如阿里云,青云,腾讯云)
mysql的版本问题
# 主从的数据是要进行同步的,若是数据库版本或者安装方式不一样,会影响数据的同步,产生没法同步或字符集报错的状况 # 主库和从库的服务器,安装mysql数据库时,要选择相应的版本,而且安装方式最好相同
配置文件问题
# mysql或mariadb的关键配置文件是my.cnf,默认位置为etc/my.cnf(因为安装方式的不一样,此配置文件,并不必定在此) # 作主从时,注意要在启动数据库前,修改配置文件my.cnf后,再启动数据库服务 # 注意主从配置时,必需要在my.cnf中添加server-id,主的server-id的数值要小于从的server-id,每个server-id都必须是惟一的 # 注意主从配置时,必需要在my.cnf中添加log-bin,开启二进制文件 # 数据库如配置有调优参数,应使主从的配置文件中参数数值相同,避免因参数不一样致使的失败
受权问题
# 数据库的同步是要经过主库专门建立的一个用户来使从库进行数据的同步的,所以要注意受权的问题 # 注意主库受权时的ip,用户,密码grant replication slave on . to ‘用户’@‘从库的IP’ identified by ‘密码’ # 注意从库链接主库的各项参数 # change master to master_host = ‘主库的IP’, master_user = ‘设置主从时设定的主库的用户’, master_port=主库的端口, master_password=’主库设定的密码’, master_log_file = ‘主库状态的File’, master_log_pos=主库状态的Position;
数据库差异问题
# 咱们在作新的mysql主从的时候,因为主库并无产生较多的数据,从库很容易就进行同步,报错也几乎不会产生 # 可是,当咱们的主库的数据已经有不少了或者是把一个用了好久的数据库来作主从,这时就须要先将主库的数据备份导入从库中,再进行从库的链接到主库的步骤。不然,就会从库就会因数据差异较大,产生各类报错
先在两台机器执行下面脚本,分别安装好数据库,并改好密码
#!/usr/bin/env bash # Author: ZhouJian # Mail: 18621048481@163.com # Time: 2019-9-3 # Describe: CentOS 7 Install Mysql.rpm Script clear echo -ne "\\033[0;33m" cat<<EOT _oo0oo_ 088888880 88" . "88 (| -_- |) 0\\ = /0 ___/'---'\\___ .' \\\\\\\\| |// '. / \\\\\\\\||| : |||// \\\\ /_ ||||| -:- |||||- \\\\ | | \\\\\\\\\\\\ - /// | | | \\_| ''\\---/'' |_/ | \\ .-\\__ '-' __/-. / ___'. .' /--.--\\ '. .'___ ."" '< '.___\\_<|>_/___.' >' "". | | : '- \\'.;'\\ _ /';.'/ - ' : | | \\ \\ '_. \\_ __\\ /__ _/ .-' / / ====='-.____'.___ \\_____/___.-'____.-'===== '=---=' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 建议系统 CentOS7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # PS:请尽可能使用纯净的CentOS7系统,咱们会在服务器安装Mysql5.7, # 将mysql-5.7.23-1.el7.x86_64.rpm-bundle.tar包和脚本放到root目录下执行便可,密码为ZHOUjian.20 EOT echo -ne "\\033[m" init_security() { systemctl stop firewalld systemctl disable firewalld &>/dev/null setenforce 0 sed -i '/^SELINUX=/ s/enforcing/disabled/' /etc/selinux/config sed -i '/^GSSAPIAu/ s/yes/no/' /etc/ssh/sshd_config sed -i '/^#UseDNS/ {s/^#//;s/yes/no/}' /etc/ssh/sshd_config systemctl enable sshd crond &> /dev/null echo -e "\033[32m [安全配置] ==> OK \033[0m" } init_yumsource() { if [ ! -d /etc/yum.repos.d/backup ];then mkdir /etc/yum.repos.d/backup fi mv /etc/yum.repos.d/* /etc/yum.repos.d/backup 2>/dev/null if ! ping -c2 www.baidu.com &>/dev/null then echo "您没法上外网,不能配置yum源" exit fi curl -o /etc/yum.repos.d/163.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo timedatectl set-timezone Asia/Shanghai echo "nameserver 114.114.114.114" > /etc/resolv.conf echo "nameserver 8.8.8.8" >> /etc/resolv.conf chattr +i /etc/resolv.conf echo -e "\033[32m [YUM Source] ==> OK \033[0m" } init_mysql() { rpm -e mariadb-libs --nodeps rm -rf /var/lib/mysql rm -rf /etc/my.cnf tar xvf /root/mysql-5.7.23-1.el7.x86_64.rpm-bundle.tar -C /usr/local/ cd /usr/local rpm -ivh mysql-community-server-5.7.23-1.el7.x86_64.rpm \ mysql-community-client-5.7.23-1.el7.x86_64.rpm \ mysql-community-common-5.7.23-1.el7.x86_64.rpm \ mysql-community-libs-5.7.23-1.el7.x86_64.rpm | rm -rf mysql-community-* } changepass() { sed -i '/\[mysqld]/ a skip-grant-tables' /etc/my.cnf systemctl restart mysqld mysql <<EOF update mysql.user set authentication_string='' where user='root' and Host='localhost'; flush privileges; EOF sed -i '/skip-grant/d' /etc/my.cnf systemctl restart mysqld yum -y install expect ntpdate expect <<-EOF spawn mysqladmin -uroot -p password "ZHOUjian.20" expect { "password" { send "\r" } } expect eof EOF systemctl restart mysqld } main() { init_hostname init_security init_yumsource init_mysql changepass } main
mysql主库配置
[root@mysqlhost ~]# cat /etc/my.cnf [mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock symbolic-links=0 log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid server-id = 1 log-bin=mysql-bin
mysql从库配置
[root@mysql-from ~]# cat /etc/my.cnf [mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock symbolic-links=0 log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid server-id = 2 log-bin = mysql-bin
主从两台服务器分别重启服务
systemctl restart mysqld
# 建立用于同步的用户帐号及密码 grant replication slave on *.* to 'slave'@'192.168.0.%' identified by 'ZHOUjian.200'; # 从新加载权限表,更新权限 flush privileges; # 查看master的状态 #mysql> show master status; #+------------------+----------+--------------+------------------+-------------------+ #| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | #+------------------+----------+--------------+------------------+-------------------+ #| mysql-bin.000001 | 600 | | | | #+------------------+----------+--------------+------------------+-------------------+ #1 row in set (0.00 sec)
change master to master_host='192.168.0.102', master_user='slave', master_password='ZHOUjian.200', master_auto_position=0; mysql> start slave; # 查看从库状态 mysql> show slave status\G; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.0.117 Master_User: slave Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 600 Relay_Log_File: mysql-from-relay-bin.000002 Relay_Log_Pos: 813 Relay_Master_Log_File: mysql-bin.000001 Slave_IO_Running: Yes # 此处两个yes有一个不是就会失败 Slave_SQL_Running: Yes # Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 600 Relay_Log_Space: 1025 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 1 Master_UUID: ff0c0da9-8f72-11ea-9d83-000c29245a7e Master_Info_File: /var/lib/mysql/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: 1 row in set (0.00 sec)
如下操做是基于上面的GTID复制案例喔,请作完GTID再作这里,大佬请无视这句话
[root@mysql-from2 ~]# cat /etc/my.cnf [mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock symbolic-links=0 log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid server-id = 3 log-bin = mysql-bin
修改配置记得重启mysqld服务生效配置
systemctl restart mysqld
# 建立用于同步的用户帐号及密码 grant replication slave on *.* to 'slave'@'192.168.0.%' identified by 'ZHOUjian.200'; # 从新加载权限表,更新权限 flush privileges;
# 先进入主库,进行锁表,此处锁定为只读状态,防止数据写入 (可选,因若有数据库备份,可直接利用备份) flush tables with read lock; mysqldump -uroot -p‘….’ -hlocalhost > mysql.back.sql scp mysql.back.sql 从库IP:/root/(任意位置) # 从库导入数据 mysql -uroot -p... -f < mysql.back.sql # 主库解锁 unlock tables;
# 从库开启slave change master to master_host='192.168.0.102', master_user='slave', master_password='ZHOUjian.200', master_auto_position=0; mysql> start slave; # 查看从库状态 mysql> show slave status\G; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.0.102 Master_User: slave Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 600 Relay_Log_File: mysql-from-relay-bin.000002 Relay_Log_Pos: 813 Relay_Master_Log_File: mysql-bin.000001 Slave_IO_Running: Yes # 此处两个yes有一个不是就会失败 Slave_SQL_Running: Yes # Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 600 Relay_Log_Space: 1025 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 1 Master_UUID: ff0c0da9-8f72-11ea-9d83-000c29245a7e Master_Info_File: /var/lib/mysql/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: 1 row in set (0.00 sec)
解决并发问题,不一样于分表,分表用于解决数据量过大的问题
方式一: 业务层使用不一样的数据库
方式二: 使用负载均衡,判断是什么语句,分配到不一样的数据库
基于应用层和数据层中间件的代理层,主要解决方案以下:
# 1. 开发人员 # 2. 软件 # mysql-proxy # amoeba JAVA 阿里 # Atlas 360 # TDDL # Sharding-JDBC # cobar (MyCAT前身,java) # 这些中间件,统一为多个数据库进行代理,应用只须要链接中间件(分布式数据库系统),执行SQL,中间件就会根据规则,将SQL分配到不一样的数据库中