MySQL主从复制

MySQL安装和主从复制配置

Posted by 冷小冰 on August 20, 2018

Linux下安装MySQL

环境准备

Linux:Centos7
MySQL:MySQL-5.7.23

一、yum安装

1.1、安装MySQL

创建mysql文件夹

1
2
3
cd /opt
mkdir mysql
cd /mysql

执行下面命令,下载mysql

1
2
wget http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm
rpm -ivh mysql57-community-release-el7-11.noarch.rpm

选择版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#进入软件仓库
cd /etc/yum.repos.d/
#查看文件
ls   
---
mysql-community.repo  mysql-community-source.rep
#修改mysql-community.repo,将需要的版本的enabled设置为1,其他版本设为0
vim mysql-community.repo
#修改内容如下
[mysql57-community]
name=MySQL 5.7 Community Server
baseurl=http://repo.mysql.com/yum/mysql-5.7-community/el/7/$basearch/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql
#开始安装
$ yum install mysql-community-server -y

启动mysql

1
systemctl start mysqld

设置开机启动

1
2
systemctl enable mysqld
systemctl daemon-reload

修改编码格式

1
2
3
4
#查看mysql的编码格式
mysql -u root -p
> show variables like '%character%';
#发现有两个是西文的,需要改成UTF8

img 修改配置文件:

1
2
3
4
5
6
7
8
9
10
11
$ vim /etc/my.cnf
# 找到[mysqld],在下面添加:
character-set-server=utf8
# 最后面添加:
[client]
default-character-set=utf8
#重启mysql:
systemctl restart mysqld.service
#查看mysql的编码格式那两个西文的是否改成UTF8
mysql -u root -p
> show variables like '%character%';

img 至此,MySQL安装完毕。

1.2、修改密码

第一种方式
安装完毕后,会在 /var/log/mysqld.log日志中生成一个默认的密码。

1
2
3
4
5
6
vim /var/log/mysqld.log
#密码在下面这一行
[Note]A temporaty password is generates for root@localhost:xxxxxx

# 查看命令
grep 'temporary password' /var/log/mysqld.log

拿到默认密码,登录mysql 进行密码重新设置。

1
2
3
4
5
6
7
8
9
10
11
#进入mysql
mysql -u root -p
> set password=password(“root”);
#如果密码级别与默认的级别要求不符,会报如下错误:
Your password does not satisfy the current policy requirements
#此时需要修改级别与最小的默认密码位数。
> set global validate_password_policy=0;
#重新设置密码
> set password=password(“root”);
#mysql连接授权
> grant all privileges on *.* to root@'%'identified by 'root';

第二种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#停止mysql服务
systemctl stop mysqld.service
#修改配置文件,无密码登录
vim /etc/my.cnf
#找到[mysqld],在下面添加
skip-grant-tables
#启动mysql
systemctl start mysqld.service
#登录mysql,此时不要在加-p,已经免密登陆了
mysql -u root
#修改密码,mysql5.7用此语法
>use mysql;
>update mysql.user set authentication_string=password('123456') where user='root';
#最后去掉配置文件加上的
skip-grant-tables
#保存 重启mysql就ok了

1.3、修改储存路径

登陆mysql,查看当前存储目录

1
2
3
4
5
6
mysql -u root -p
> show global variables like "%datadir%";
#关闭mysql服务
systemctl stop mysqld.service
#把当前目录复制到新的目录下,例如
cp /var/lib/mysql  /user/

修改/etc/my.cfg文件,将原有文件备份,以防出错回滚。

1
2
3
4
5
6
7
8
9
# 存储路径
datadir=/user/mysql
socket=/user/mysql/mysql.sock
# 日志路径
log-error=/user/mysql/log/mysqld.log
pid-file=/usr/mysql/run/mysqld.pid
#在最后添加
[client]
socket=/user/mysql/mysql.sock

重启mysql服务

1
systemctl rstart mysqld.service

二、源码安装

2.1、卸载旧版本的MySQL

使用命令检查,是否安装有MySQL服务:

1
rpm -qa|grep mysql

有的话通过下面的命令来卸载掉:

1
2
3
4
5
#例如查到安装了mysql-libs-5.1.73-7.el6.x86_64
#普通删除模式
rpm -e mysql-libs   
#强力删除模式,如果使用上面命令删除时,提示有依赖的其它文件,则用该命令可以对其进行强力删除
rpm -e --nodeps mysql-libs  

2.2、安装环境准备

安装编译代码需要的包

1
yum -y install gcc* gcc-c++* ncurses-devel* cmake* make* perl* autoconf* automake* zlib* libxml* libgcrypt* libtool* bison* openssl openssl-devel

下载mysql安装包
安装包的种类有很多,不同的安装包安装方法略有不同。比如编译好的二进制包,带boost库的安装包,不带boost库的安装包等。为了方便安装过程中不受boost依赖的影响,直接从官网下载mysql-boost-5.7.23.tar.gz版本。 img

下载编译过的二进制包
img

下载没有编译过的二进制包
img

解压mysql-boost-5.7.23.tar.gz到想存放的目录

1
tar -zxvf mysql-boost-5.7.23.tar.gz -C /usr/mysql

2.3、编译并安装

到mysql的解压目录

1
$ cd /usr/mysql

编译
MySQL从5.5版本开始,取消了./configure行编译配置方式,取而代之的是cmake工具,在安装环境准备时已安装。
Cmake详细参数官网说明:
https://dev.mysql.com/doc/refman/5.7/en/source-configuration-options.html
以下命令不换行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cmake
-DCMAKE_INSTALL_PREFIX=/usr/mysql # MySQL安装目录
-DMYSQL_DATADIR=/usr/mysql/data # 数据库存放目录
-DDEFAULT_CHARSET=utf8 # 使用utf8字符格式
-DDEFAULT_COLLATION=utf8_general_ci # 检验字符
-DMYSQL_TCP_PORT=3306 # MySQL监听端口
-DMYSQL_USER=root # MySQL运行用户
-DWITH_MYISAM_STORAGE_ENGINE=1 # 静态地将MYISAM存储引擎编译到服务器
-DWITH_INNOBASE_STORAGE_ENGINE=1 # 静态地将INNOBASE存储引擎编译到服务器
-DWITH_ARCHIVE_STORAGE_ENGINE=1 # 静态地将ARCHIVE存储引擎编译到服务器
-DWITH_BLACKHOLE_STORAGE_ENGINE=1 # 静态地将BLACKHOLE存储引擎编译到服务器
-DWITH_MEMORY_STORAGE_ENGINE=1 # 静态地将MEMORY存储引擎编译到服务器
-DDOWNLOAD_BOOST=1 # 下载安装boost
-DWITH_BOOST=/usr/mysql/boost # boost的安装路径
-DMYSQL_UNIX_ADDR=/usr/mysql/mysql.sock # unix的socket文件
-DMYSQL_UNIX_ADDR=/usr/mysql/mysql.sock # unix的socket文件
-DMYSQLX_UNIX_ADDR=/usr/mysql/mysqlx.sock # X插件使用的Unix socket文件
-DWITH_SSL=system # 启用系统的ssl库支持(安全套接

:如果编译出错没有通过,检查参数后重新运行配置,需要删除CMakeCache.txt文件

1
rm -f CMakeCache.txt

如下,表示编译成功 img

执行命令

1
make && make install

说明:这个安装时间很长(30分钟左右),耐心等待即可。

2.4、配置MySQL

设置权限 使用下面的命令查看是否有mysql用户及用户组:

1
2
3
4
5
6
7
8
cat /etc/passwd # 查看用户列表 
cat /etc/group  # 查看用户组列表
#如果没有就创建: 
groupadd mysql   # 创建mysql组
useradd -g mysql mysql   # 创建属于mysql组的mysql用户
passwd mysql  # 为mysql用户创建登录密码
#修改/usr/mysql权限:
chown -R mysql:mysql /usr/mysql

初始化
执行初始化配置脚本,创建系统自带的数据库和表:

1
2
cd /usr/mysql/bin/
./mysqld --initialize --user=mysql --basedir=/usr/mysql --datadir=/usr/mysql/data

说明:此条语句执行时容易报错,成功至少要满足以下几个条件

  • /usr/mysql/data目录存在并且一定要为空目录,否则报错;
  • 如果本机已经存在了其余的mysql,请确实/etc/my.cnf文件不存在,否则会按照/etc/my.cnf中的设置进行初始化,datadir会读取另一个mysql实例的路径,从而导致报错。遇到此情况,可以先将已经存在的mysql实例停止,然后将/etc/my.cnf文件剪切到此实例对应的datadir目录中,再启动此实例,然后重新执行初始化命令;
  • 上面语句初始化成功后会在控制台打印临时管理员密码 img

将启动脚本做成服务(选做)

1
2
cp /usr/mysql/support-files/mysql.server  /etc/init.d/mysql
chkconfig mysql on  # 设置服务自动启动

配置PATH(选做)

1
2
3
vim /etc/profile
export PATH=$PATH:/usr/mysql/bin  # 把mysql的bin路径加入PATH
source /etc/profile   # 让PATH变量修改立即生效

创建软链接(选做)
由于系统默认会查找/usr/bin下的命令,如果这个命令不在这个目录下,当然会找不到命令,我们需要做的就是映射一个链接到/usr/bin目录下,相当于建立一个链接文件。
解决方法:创建软链接

1
ln -s /usr/mysql/bin/mysql /usr/bin 

远程连接配置(选做)
本操作前需要先修改密码
为root添加远程连接的能力,连接账号为root,连接密码为root

1
2
3
4
./mysql -u root -p
> set password=password("root");
> grant all privileges on *.* to root@'%'identified by 'root';
> exit;

2.5、启动与登录

启动

1
2
cd /usr/mysql/support-files
./mysql.server start

登录

1
2
cd /usr/mysql/bin 
./mysql -u root -p

2.6、修改默认登录密码

MySQL默认给分配了一个默认密码,但当自己在终端上使用默认密码登录的时候,总会提示一个授权失败的错误。 img 解决方法: 进入MySQL免密码模式 官网说明:从5.7.18开始不在二进制包中提供my-default.cnf文件。经过测试,在5.7.18版本中,使用tar.gz安装时,也就是压缩包解压出来安装这种,已经不再需要my.cnf文件也能正常运行。

1
2
3
4
5
6
7
8
9
10
11
#先关掉MySQL服务
service mysqld stop
#进入MySQL的免密码模式
cd /usr/mysql/support-files 
./mysql.server start --skip-grant-tables
#登录修改密码:
cd /usr/mysql/bin
./mysql -u root
> use mysql
> update mysql.user set authentication_string=password('123456') where user='root';
> exit;

重新启动即可正常进去

三、主从复制

3.1、复制原理

MySQL中有一种日志叫做bin日志(二进制日志)。这个日志会记录下所有修改了数据库的SQL语句(insert, update, delete, ALTER TABLE, grant等等)。
主从复制的原理其实就是把主服务器上的bin日志复制到从服务器上执行一遍,这样从服务器上的数据就和主服务器上的数据相同了。 复制流程图: img 复制过程:

  1. 主节点必须启用二进制日志,记录任何修改数据库数据的事件。
  2. 从节点开启一个线程(I/O Thread)把自己扮演成mysql的客户端,通过mysql协议,请求主节点的二进制日志文件中的事件
  3. 主节点启动一个线程(dump Thread),检查自己二进制日志中的事件,跟对方请求的位置对比,如果不带请求位置参数,则主节点就会从第一个日志文件中的第一个事件一个一个发送给从节点。
  4. 从节点接收到主节点发送过来的数据把它放置到中继日志(Relay log)文件中。并记录该次请求到主节点的具哪个二进制日志文件的哪个位置。
  5. 从节点启动另外一个线程(sql Thread ),把replaylog中的事件读取出来,并在本地再执行一次。

复制中线程的作用:
从节点:

  • I/O Thread:从Master请求二进制日志事件,并保存于中继日志中。
  • Sql Thread:从中继日志中读取日志事件,在本地完成重放。

主节点:

  • Dump Thread:为每个Slave的I/O Thread启动一个dump线程,用于向从节点发送二进制文件。

MySQL支持的复制类型

  • 基于语句的复制: 在主服务器上执行的 SQL 语句,在从服务器上执行同样的语句。但是,必须要小心,需要避免用户对主服务器上的表进行的更新,与对从服务器上的表所进行的更新之间的冲突,配置:binlog_format=STATEMENT
  • 基于行的复制:把改变的内容复制过去,而不是把命令在从服务器上执行一遍,从 MySQL 5.0开始支持,配置:binlog_format=ROW
  • 混合类型的复制:默认采用基于语句的复制,一旦发现基于语句的无法精确的复制时,就会采用基于行的复制,配置:binlog_format=MIXED

思考:从节点需要建立二进制日志文件吗?
看情况,如果从节点需要作为其他节点的主节点时,是需要开启二进制日志文件的。这种情况叫做级联复制。如果只是作为从节点,则不需要创建二进制日志文件。

3.2、主从复制配置过程

主节点:

  1. 启用二进制日志。
  2. 为当前节点设置一个全局唯一的server_id。
  3. 创建有复制权限的用户账号REPLIACTION SLAVE ,REPLIATION CLIENT。

从节点:

  1. 启动中继日志。
  2. 为当前节点设置一个全局唯一的server_id。
  3. 使用有复制权限的用户账号连接至主节点,并启动复制线程。

测试环境:
MySQL:MySQL-5.7.23
Linux:CentOS7
主节点:192.168.3.11
从节点:192.168.3.12

具体步骤
以下配置需要保证主服务器上没有应用数据
1、配置主服务器
启用二进制日志文件

1
2
3
4
5
6
7
8
9
10
vim /etc/my.cnf
#添加如下配置: 
log-bin=mysql-bin # 启用二进制日志
binlog-do-db=master # 需要主从复制的数据库的名字
binlog-ignore-db=mysql  # 忽略mysql数据库
binlog_format=MIXED # 复制类型
server-id=1 # 服务器唯一ID 

#重启mysql
systemctl restart mysqld

查看日志是否开启

1
2
mysql -u root -p
> show global variables like '%log%';

img 查看日志列表

1
> show master logs;

img 查看server id

1
> show global variables like '%server%';

img 查看主节点状态
记录下 FILE 及 Position 的值,在后面进行从服务器操作的时候需要用到。

1
> show master status;

img 在主节点上创建有复制权限的用户

1
2
3
> GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* to 'replacer'@'192.168.3.12' identified by 'replacer';
# 刷新
> flush privileges;

主服务器配置完成。
:确保主服务器的iptables没有阻断3306的访问端口。

2、配置从服务器
开启中继日志

1
2
3
4
5
6
7
8
> vim /etc/my.cnf
#添加如下信息
relay-log=relay-log  # 开启中继日记
relay-log-index=relay-log.index  # 中继日志文件
server-id=2

#重启mysql
systemctl restart mysqld

设置从只读

1
2
mysql -u root -p
>set global read_only=1;

查看日志是否开启

1
2
mysql -u root -p
> show global variables like '%log%';

img 查看server id

1
> show global variables like '%server%';

img 配置访问主节点的参数信息
添加主节点主机,访问主节点的用户名及密码,主节点二进制文件信息。(即上文配置的复制账号和密码,以及记录的FILE 及 Position) 。
:主节点的二进制文件一定要是二进制列表中的最后一个二进制文件。

1
> change master to master_host='192.168.3.11', master_user='replacer', master_password='replacer', master_log_file='mysql-bin.000001', master_log_pos=154;

查看从节点的状态信息
因为没有启动 从节点的复制线程,IO线程 和 SQL 线程都为NO.

1
> show slave status\G  #\G后面不能再加分号";", 因为\G在功能上等同于";"

img 启动复制线程
START SLAVE 可以指定线程类型:IO_THREAD ,SQL_THREAD, 如果不指定,则两个都启动。

1
2
3
4
> start slave;
#再次查看状态
> show slave status\G 
# 其中Slave_IO_Running 与 Slave_SQL_Running 的值都必须为YES,才表明状态正常。

img 至此主从配置完成。

如果主服务器已经存在应用数据,则在进行主从复制时,需要做以下处理:
1.主数据库进行锁表操作,不让数据再进行写入动作

1
> FLUSH TABLES WITH READ LOCK;

2.查看主数据库状态

1
> show master status;

3.记录下 FILE 及 Position 的值
将主服务器的数据文件(整个/usr/mysql/data目录)复制到从服务器,建议通过tar归档压缩后再传到从服务器解压。
4.取消主数据库锁定

1
> UNLOCK TABLES;

验证主从复制效果
主服务器上的操作
在主服务器上创建数据库first_db

1
2
3
4
5
6
> create database first_db;
#在主服务器上创建表first_tb
> use first_db;
\> create table first_tb(id int(3),name char(10));
#在主服务器上的表first_tb中插入记录
> insert into first_tb values (001,’test);

在从服务器上查看

1
2
3
> show databases;
> use first _db;
> select * from first_tb;

查询到数据就说明主从复制配置成功了

注意事项

  • 主库和从库的数据库名必须相同;
  • 主库和从库的复制可以精确到表,但是在需要更改主库或从库的数据结构时需要立刻重启slave;
  • 不能在mysql配置文件里直接写入master的配置信息,需要用change master命令来完成;
  • 指定replicate_do_db必须在my.cnf里配置,不能用change master命令来完成;
  • 如果不及时清理,日积月累二进制日志文件可能会把磁盘空间占满,可以在配置文件里加上expire_logs_days=7,只保留最近7天的日志,建议当slave不再使用时,通过reset slave来取消relaylog;
  • 写一个监控脚本,用来监控 Slave 中的两个”yes”,如果只有一个”yes”或者零个,就表明主从有问题。

3.3、主从一致性检查

本文选用的是percona-toolkit工具。
建议:master端和slave端都安装percona-toolkit工具
安装依赖包

1
yum install perl-IO-Socket-SSL perl-DBD-MySQL perl-Time-HiRes perl perl-DBI -y

安装percona-toolkit
下载地址:https://www.percona.com/downloads/percona-release/redhat/0.1-6/

1
2
3
wget https://www.percona.com/redir/downloads/percona-release/redhat/0.1-6/percona-release-0.1-6.noarch.rpm
yum install percona-release-0.1-6.noarch.rpm
yum list | grep percona-toolkit

img 开始安装

1
yum install percona-toolkit -y

验证安装是否成功

1
2
pt-table-checksum --help
pt-query-digest --help

pt-table-checksum的使用(检查数据一致性)
在主库执行授权:一定要对主库ip授权,授权的用户名和密码可以自行定义,要保证这个权限能同时登陆主库和从库

1
2
3
>grant select,process,super,replication slave,create,delete,insert,update on *.* to 
'checker'@'192.168.3.11' identified by 'checker';
> flush privileges;

在从库上执行授权

1
2
> grant select,process,super,replication slave on *.* to 'checker'@'192.168.3.11' identified by 'checker';
> flush privileges;

在主库上执行的一个检查主从数据一致性的命令
(以下列出常用的命令,所用参数可根据需要选择)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pt-table-checksum 
--nocheck-replication-filters # 不检查复制过滤器,建议启用
--no-check-binlog-format # 不检查复制的binlog模式,要是binlog模式是row,则会报错
--replicate-check-only # 只显示不同步的信息。
--replicate=first_db.checksums # 把checksum的信息写入到指定表中
--create-replicate-table # 创建checksum表,第一次需要创建,之后就不需要了
--databases=first_db # 指定需要被检查的数据库,多个则用逗号隔开
--tables= first_table # 指定需要被检查的表,多个用逗号隔开
--quiet # 安静模式,最小化打印,只打印错误行
--recursion-method=hosts # 查找Slave的方式,有三种, processlist, dsn, hosts
h=192.168.3.11, # Master的地址
P=3306, # Master的端口号 
u=checker, # Master的用户名
p=checker # Master的密码 

  • 根据测试,需要一个即能登录主库,也能登录从库的账号
  • 只能指定一个host,必须为主库的IP
  • 在检查时会向表加S锁
  • 运行之前需要从库的同步IO和SQL进程是YES状态,如果不是则会报错

运行结果: img 参数说明:

  • TS: 完成检查的时间
  • ERRORS:检查时发生错误和警告的数量
  • DIFFS:0 表示一致,1表示不一致,当指定 –no-replicate-check 时,会一直为0,当指定–replicate-check-only 则会显示不同步的信息
  • ROWS:表的行数。
  • CHUNKS:被划分到表中的块的数目
  • SKIPPED:由于错误或警告过大,则跳过块的数目。
  • TIME:执行的时间。
  • TABLE:被检查的表名

:如果出现不一致的情况,就需要进行修复了。

pt-table-sync的使用(修复数据)
高效的同步MySQL表之间的数据,可以做单向和双向的同步表数据。可以同步单个表,也可以同步整个库。不同步表的结构、索引、或任何其他模式对象。所以在修复一致性之前需要保证表存在。
(以下列出常用的命令,所用参数可根据需要选择)

1
2
3
4
5
6
7
8
9
pt-table-sync 
--print # 打印修复的sql语句, 只打印不执行
--execute # 执行修复的sql语句,和print不能同时运行,二选一
--charset=utf8 # 指定默认字符集
--replicate=first_db.checksums # 指定通过pt-table-checksum得到的表
--databases=first_db # 指定执行同步的数据库
--tables=first_table # 指定需要被修复的表,多个用逗号隔开
h=192.168.3.11,u=checker,p=checker # Master的账号密码
h=192.168.3.12,u=checker,p=checker # Slave的账号密码

:

  • 校验修复工作每月定期开展;
  • 主从复制架构在割接操作前后均需执行数据校验和修复工作;
  • 主从复制出现故障后要开展数据校验和修复工作;
  • 校验修复需在业务低谷期进行,CPU利用率超过60%时不建议做数据校验和修复;
  • 校验和修复必须在主库进行;
  • 数据库的表要有主键,否则校验效率极差,并且修复不成功。