马哥SRE第六周课程作业

一、 简述DDL,DML,DCL,DQL,并且说明mysql各个关键字查询时候的先后顺序

1.1 简述DDL,DML,DCL,DQL

  • DDL: Data Defination Language 数据定义语言

CREATE,DROP,ALTER

  • DML: Data Manipulation Language 数据操纵语言

INSERT,DELETE,UPDATE
软件开发:CRUD

  • DQL:Data Query Language 数据查询语言

SELECT

  • DCL:Data Control Language 数据控制语言

GRANT,REVOKE

  • TCL:Transaction Control Language 事务控制语言

COMMIT,ROLLBACK,SAVEPOINT

1.2 mysql各个关键字查询时候的先后顺序

关健字Keyword组成子句clause,多条clause组成语句
示例:

SELECT * #SELECT子句
FROM products #FROM子句
WHERE price>666 #WHERE子句

说明:一组SQL语句由三个子句构成,SELECT,FROM和WHERE是关键字
获取SQL 命令使用帮助:
官方帮助:
https://dev.mysql.com/doc/refman/8.0/en/sql-statements.html

范例: 查看SQL帮助

MariaDB [mysql]> help contents
You asked for help about help category: "Contents"
For more information, type 'help ', where <item> is one of the following
categories:
   Account Management
   Administration
   Compound Statements
   Data Definition
   Data Manipulation
   Data Types
   Functions
   Functions and Modifiers for Use with GROUP BY
   Geographic Features
   Help Metadata
   Language Structure
   Plugins
   Procedures
   Table Maintenance
   Transactions
   User-Defined Functions
   Utility
MySQL [(none)]> help Data Types
You asked for help about help category: "Data Types"
For more information, type 'help ', where <item> is one of the following
topics:
   AUTO_INCREMENT
   BIGINT
   BINARY
   BIT
   BLOB
   BLOB DATA TYPE
   
MySQL [(none)]> help bit
Name: 'BIT'
Description:
BIT[(M)]
A bit-value type. M indicates the number of bits per value, from 1 to
64. The default is 1 if M is omitted.
URL: https://dev.mysql.com/doc/refman/5.7/en/numeric-type-syntax.html

查看SQL帮助

mysql> HELP KEYWORD

mysql关键字执行顺序如下:

from
on/using
join
where
group by
having
select
distinct
union
order by
limit

解释关键字执行顺序
Mysql关键字执行顺序-深入解析

Mysql会先执行from,然后根据on关键字去筛选目标表,筛选出的结果再进行join或者using,这样就会形成一个临时表。然后去执行where条件去筛选这个临时表,这样基本就筛选出需要的数据了。然后就可以对数据进行groupby进行分组,同时若是有必要就会再执行having对数据进行进一步筛选,这里执行完数据基本就是一定定型了,下面就需要select去筛选目标列了,完事之后需要使用distinct进行去重这样一个表的查询基本就结束了。若是需要多表查询则还需要使用union或者unionall来进行连接多表的结果。然后就是对数据进行排序的order by ,排完顺序自然就是取分页了。这样就会将一个完整的sql执行完毕了。

会有一些特殊的情况,让我们无法命中索引(即使创建了索引),这也是需要大家在开发中要注意的

  • 类型不一致

    select * from big where name = 123;		-- 未命中
    select * from big where email = 123;	-- 未命中
    
    特殊的主键:
    	select * from big where id = "123";	-- 命中
    
  • 使用不等于

    select * from big where name != "武沛齐";				-- 未命中
    select * from big where email != "[email protected]";  -- 未命中
    
    特殊的主键:
    	select * from big where id != 123;	-- 命中
    
  • or,当or条件中有未建立索引的列才失效。

    select * from big where id = 123 or password="xx";			-- 未命中
    select * from big where name = "wupeiqi" or password="xx";	-- 未命中
    特别的:
    	select * from big where id = 10 or password="xx" and name="xx"; -- 命中
    
  • 排序,当根据索引排序时候,选择的映射如果不是索引,则不走索引。

    select * from big order by name asc;     -- 未命中
    select * from big order by name desc;    -- 未命中
    
    特别的主键:
    	select * from big order by id desc;  -- 命中
    
  • like,模糊匹配时。

    select * from big where name like "%u-12-19999";	-- 未命中
    select * from big where name like "_u-12-19999";	-- 未命中
    select * from big where name like "wu-%-10";		-- 未命中
    
    特别的:
    	select * from big where name like "wu-1111-%";	-- 命中
    	select * from big where name like "wuw-%";		-- 命中
    
  • 使用函数

    select * from big where reverse(name) = "wupeiqi";  -- 未命中
    
    特别的:
    	select * from big where name = reverse("wupeiqi");  -- 命中
    
  • 最左前缀,如果是联合索引,要遵循最左前缀原则。

    如果联合索引为:(name,password)
        name and password       -- 命中
        name                 	-- 命中
        password                -- 未命中
        name or password       	-- 未命中
    

二、自行设计10个sql查询语句,需要用到关键字[GROUP BY/HAVING/ORDER BY/LIMIT],至少同时用到两个。

马哥SRE第六周课程作业_第1张图片

2.1根据上图创建 数据库 & 表结构 并 录入数据

create database day27db default charset utf8 collate utf8_general_ci;
use day27db;
#导出
# 结构+数据
mysqldump -u root -p  day27db > /Users/wupeiqi/day27db2.sql

# 结构
mysqldump -u root -p -d day27db > /Users/wupeiqi/day27db3.sql
create table class(
	cid int not null auto_increment primary key,
    caption varchar(16) not null
)default charset=utf8;

INSERT INTO class VALUES ('1', '三年二班'), ('2', '三年三班'), ('3', '一年二班'), ('4', '二年九班');


create table student(
	 sid int not null auto_increment primary key,
    gender char(1) not null,
    class_id int not null,
    sname varchar(16) not null,
    constraint fk_student_class foreign key (class_id) references class(cid)
)default charset=utf8;

INSERT INTO student VALUES ('1', '男', '1', '理解'), ('2', '女', '1', '钢蛋'), ('3', '男', '1', '张三'), ('4', '男', '1', '张一'), ('5', '女', '1', '张二'), ('6', '男', '1', '张四'), ('7', '女', '2', '铁锤'), ('8', '男', '2', '李三'), ('9', '男', '2', '李一'), ('10', '女', '2', '李二'), ('11', '男', '2', '李四'), ('12', '女', '3', '如花'), ('13', '男', '3', '刘三'), ('14', '男', '3', '刘一'), ('15', '女', '3', '刘二'), ('16', '男', '3', '刘四');


create table teacher(
	 tid int not null auto_increment primary key,
    tname varchar(16) not null
)default charset=utf8;

INSERT INTO `teacher` VALUES ('1', '张磊老师'), ('2', '李平老师'), ('3', '刘海燕老师'), ('4', '朱云海老师'), ('5', '李杰老师');


create table course(
	   cid int not null auto_increment primary key,
    cname varchar(16) not null,
    teacher_id int not null,
    constraint fk_course_teacher foreign key (teacher_id) references teacher(tid)
)default charset=utf8;

INSERT INTO `course` VALUES ('1', '生物', '1'), ('2', '物理', '2'), ('3', '体育', '3'), ('4', '美术', '2');


CREATE TABLE `score` (
  `sid` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `student_id` int NOT NULL,
  `course_id` int NOT NULL,
  `num` int NOT NULL,
  CONSTRAINT `fk_score_course` FOREIGN KEY (`course_id`) REFERENCES `course` (`cid`),
  CONSTRAINT `fk_score_student` FOREIGN KEY (`student_id`) REFERENCES `student` (`sid`)
) DEFAULT CHARSET=utf8;


INSERT INTO `score` VALUES ('1', '1', '1', '10'), ('2', '1', '2', '9'), ('5', '1', '4', '66'), ('6', '2', '1', '8'), ('8', '2', '3', '68'), ('9', '2', '4', '99'), ('10', '3', '1', '77'), ('11', '3', '2', '66'), ('12', '3', '3', '87'), ('13', '3', '4', '99'), ('14', '4', '1', '79'), ('15', '4', '2', '11'), ('16', '4', '3', '67'), ('17', '4', '4', '100'), ('18', '5', '1', '79'), ('19', '5', '2', '11'), ('20', '5', '3', '67'), ('21', '5', '4', '100'), ('22', '6', '1', '9'), ('23', '6', '2', '100'), ('24', '6', '3', '67'), ('25', '6', '4', '100'), ('26', '7', '1', '9'), ('27', '7', '2', '100'), ('28', '7', '3', '67'), ('29', '7', '4', '88'), ('30', '8', '1', '9'), ('31', '8', '2', '100'), ('32', '8', '3', '67'), ('33', '8', '4', '88'), ('34', '9', '1', '91'), ('35', '9', '2', '88'), ('36', '9', '3', '67'), ('37', '9', '4', '22'), ('38', '10', '1', '90'), ('39', '10', '2', '77'), ('40', '10', '3', '43'), ('41', '10', '4', '87'), ('42', '11', '1', '90'), ('43', '11', '2', '77'), ('44', '11', '3', '43'), ('45', '11', '4', '87'), ('46', '12', '1', '90'), ('47', '12', '2', '77'), ('48', '12', '3', '43'), ('49', '12', '4', '87'), ('52', '13', '3', '87');

2.2 创建用户 luffy 并赋予此数据库的所有权限。

create user 'luffy'@'%' identified by 'root123';
grant all privileges on day27db.* TO 'luffy'@'%';
flush privileges;

查询同名同姓学生名单,并统计同名人数。(group by +having)

select sname,count(1) from student group by sname having count(1) > 1;

查询 “三年二班” 的所有学生

select * from student left join class on student.class_id = class.cid where class.caption="三年二班";

查询成绩小于60分的同学的学号、姓名、成绩、课程名称

select 
	student.sid,
	student.sname,
	score.num,
	course.cname 
from 
	score 
	left join student on score.student_id=student.sid 
	left join course on score.course_id =course.cid 
where num <60;

查询所有同学的学号、姓名、选课数、总成绩

select student_id,student.sname,count(1),sum(num) from score left join student on score.student_id=student.sid group by student_id;

查询各科成绩的平均分,显示:课程ID、课程名称、平均分(按平均分从大到小排序前三门)

select course_id,course.cname,avg(num) as A from score left join course on score.course_id =course.cid group by course_id order by A desc limit 3;

查询选修了所有课程的学生的学号、姓名

SELECT
	student.sid,
	student.sname
FROM
	score
	LEFT JOIN student ON score.student_id = student.sid 
GROUP BY
	student_id 
HAVING
	count( 1 ) = ( SELECT count( 1 ) FROM course );

三、xtrabackup备份和还原数据库练习

3.1 xtrabackup 安装

在EPEL源中

yum install percona-xtrabackup
#centos8没有提供
[root@centos7 ~]#yum info percona-xtrabackup 
Available Packages
Name       : percona-xtrabackup
Arch       : x86_64
Version     : 2.3.6
Release     : 1.el7
Size       : 4.6 M
Repo       : epel/7/x86_64
Summary     : Online backup for InnoDB/XtraDB in MySQL, Percona Server and 
MariaDB
URL         : http://www.percona.com/software/percona-xtrabackup/
License     : GPLv2
Description : Online backup for InnoDB/XtraDB in MySQL, MariaDB and Percona 
Server
范例: 最新版本下载安装:
https://www.percona.com/downloads/XtraBackup/LATEST/

3.2 xtrabackup 用法

xtrabackup工具备份和还原,需要三步实现

  1. 备份:对数据库做完全或增量备份
  2. 预准备: 还原前,先对备份的数据,整理至一个临时目录
  3. 还原:将整理好的数据,复制回数据库目录中

xtrabackup 选项参考
备份

innobackupex [option] BACKUP-ROOT-DIR

选项说明:

–user:#该选项表示备份账号
–password:#该选项表示备份的密码
–host:#该选项表示备份数据库的地址
–databases:#该选项接受的参数为数据库名,如果要指定多个数据库,彼此间需要以空格隔开; 如:“xtra_test dba_test”,同时,在指定某数据库时,也可以只指定其中的某张表。
如:“mydatabase.mytable”。该选项对innodb引擎表无效,还是会备份所有innodb表
–defaults-file:#该选项指定从哪个文件读取MySQL配置,必须放在命令行第一个选项位置
–incremental:#该选项表示创建一个增量备份,需要指定–incremental-basedir
–incremental-basedir:#该选项指定为前一次全备份或增量备份的目录,与–incremental同时使用
–incremental-dir:#该选项表示还原时增量备份的目录
–include=name:#指定表名,格式:databasename.tablename

Prepare预准备:

innobackupex --apply-log [option] BACKUP-DIR

选项说明:

–apply-log:#一般情况下,在备份完成后,数据尚且不能用于恢复操作,因为备份的数据中可能会包含尚 未提交的事务或已经提交但尚未同步至数据文件中的事务。因此,此时数据文件仍处理不一致状态。此选项作
用是通过回滚未提交的事务及同步已经提交的事务至数据文件使数据文件处于一致性状态
–use-memory:#和–apply-log选项一起使用,当prepare 备份时,做crash recovery分配的内存大 小,单位字节,也可1MB,1M,1G,1GB等,推荐1G
–export:#表示开启可导出单独的表之后再导入其他Mysql中
–redo-only:#此选项在prepare base full backup,往其中合并增量备份时候使用,但不包括对最后 一个增量备份的合并

还原:

innobackupex --copy-back [选项] BACKUP-DIR
innobackupex --move-back [选项] [–defaults-group=GROUP-NAME] BACKUP-DIR

选项说明:

–copy-back:#做数据恢复时将备份数据文件拷贝到MySQL服务器的datadir
–move-back:#这个选项与–copy-back相似,唯一的区别是它不拷贝文件,而是移动文件到目的地。这 个选项移除backup文件,用时候必须小心。使用场景:没有足够的磁盘空间同事保留数据文件和Backup副本
–force-non-empty-directories #指定该参数时候,使得innobackupex --copy-back或–move back选项转移文件到非空目录,已存在的文件不会被覆盖。如果–copy-back和–move-back文件需要从备 份目录拷贝一个在datadir已经存在的文件,会报错失败

还原注意事项:

  1. datadir 目录必须为空。除非指定innobackupex --force-non-empty-directorires选项指定,否则–
    copy-back选项不会覆盖
  2. 在restore之前,必须shutdown MySQL实例,不能将一个运行中的实例restore到datadir目录中
  3. 由于文件属性会被保留,大部分情况下需要在启动实例之前将文件的属主改为mysql,这些文件将
    属于创建备份的用户, 执行chown -R mysql:mysql /data/mysql,以上需要在用户调用
    innobackupex之前完成

实战案例:利用 xtrabackup 实现完全备份及还原

注意:目前percona-xtrabackup-24-2.4.18-1.el8.x86_64.rpm不支持CentOS 8上的mariadb-10.3版本
案例: 利用xtrabackup8.0 完全备份和还原MySQL8.0

1 安装xtrabackup包
wget https://downloads.percona.com/downloads/Percona-XtraBackup-LATEST/Percona-XtraBackup-8.0.29-22/binary/redhat/8/x86_64/percona-xtrabackup-80-8.0.29-22.1.el8.x86_64.rpm
[root@centos8 ~]#yum -y install yum -y install percona-xtrabackup-80-8.0.29-22.1.el8.x86_64.rpm
2 在原主机做完全备份到/backup
[root@centos8 ~]#mkdir /backup
[root@centos8 ~]#xtrabackup -uroot -pmagedu --backup --target-dir=/backup/base
#目标主机无需创建/backup目录,直接复制目录本身
grant BACKUP_ADMIN on *.* to 'root'@'%'; #处理账号没有BACKUP_ADMIN权限
[root@centos8 ~]#scp -r /backup/   目标主机:/
3 在目标主机上还原
注意:恢复主机MySQL服务停止,并且数据目录为空
1)预准备:确保数据一致,提交完成的事务,回滚未完成的事务
[root@centos8 ~]#yum -y install percona-xtrabackup-80-8.0.23-16.1.el8.x86_64.rpm
[root@centos8 ~]#xtrabackup --prepare --target-dir=/backup/base
2)复制到数据库目录
注意:数据库目录必须为空,MySQL服务不能启动
[root@centos8 ~]#xtrabackup --copy-back --target-dir=/backup/base
3)还原属性
[root@centos8 ~]#chown -R mysql:mysql /var/lib/mysql
4)启动服务
[root@centos8 ~]#service mysqld start 

案例:新版 xtrabackup完全备份及还原
本案例基于CentOS 8 的 MySQL5.7 实现,也支持MySQL5.5和Mariadb5.5,和上面案例步骤相同

1 安装xtrabackup包 
#先安装MySQL5.7和xtrabackup包
[root@centos8 ~]#yum -y install percona-xtrabackup-24-2.4.20-1.el8.x86_64.rpm
2 在原主机做完全备份到/backup
[root@centos8 ~]#mkdir /backup
[root@centos8 ~]#xtrabackup -uroot -pmagedu --backup --target-dir=/backup/base
#目标主机无需创建/backup目录,直接复制目录本身
[root@centos8 ~]#scp -r /backup/   目标主机:/
3 在目标主机上还原
1)预准备:确保数据一致,提交完成的事务,回滚未完成的事务
[root@centos8 ~]#yum -y install percona-xtrabackup-24-2.4.20-1.el8.x86_64.rpm
[root@centos8 ~]#xtrabackup --prepare --target-dir=/backup/base
2)复制到数据库目录
注意:数据库目录必须为空,MySQL服务不能启动
[root@centos8 ~]#xtrabackup --copy-back --target-dir=/backup/base
3)还原属性
[root@centos8 ~]#chown -R mysql:mysql /var/lib/mysql
4)启动服务
[root@centos8 ~]#service mysqld start 

实战案例:利用xtrabackup完全,增量备份及还原
案例: 利用xtrabackup8.0 完全,增量备份及还原MySQL8.0

1 备份过程
1)完全备份:
[root@centos8 ~]#yum -y install percona-xtrabackup-24-2.4.20-1.el8.x86_64.rpm
[root@centos8 ~]#mkdir /backup/
[root@centos8 ~]#xtrabackup -uroot -pmagedu --backup --target-dir=/backup/base
2)第一次修改数据
3)第一次增量备份
[root@centos8 ~]#xtrabackup -uroot -pmagedu --backup --target-dir=/backup/inc1 --
incremental-basedir=/backup/base
4)第二次修改数据
5)第二次增量
[root@centos8 ~]#xtrabackup -uroot -pmagedu --backup --target-dir=/backup/inc2 --
incremental-basedir=/backup/inc1
6[root@centos8 ~]#scp -r /backup/* 目标主机:/backup/
#备份过程生成三个备份目录
/backup/{base,inc1,inc2}
2还原过程
1)预准备完成备份,此选项--apply-log-only 阻止回滚未完成的事务
[root@centos8 ~]#yum -y install percona-xtrabackup-24-2.4.20-1.el8.x86_64.rpm
[root@centos8 ~]#xtrabackup --prepare --apply-log-only --target-dir=/backup/base 
2)合并第1次增量备份到完全备份
[root@centos8 ~]#xtrabackup --prepare --apply-log-only --target-dir=/backup/base 
--incremental-dir=/backup/inc1
3)合并第2次增量备份到完全备份:最后一次还原不需要加选项--apply-log-only
[root@centos8 ~]#xtrabackup --prepare --target-dir=/backup/base --incremental
dir=/backup/inc2
4)复制到数据库目录,注意数据库目录必须为空,MySQL服务不能启动
[root@centos8 ~]#xtrabackup --copy-back --target-dir=/backup/base
5)还原属性:
[root@centos8 ~]#chown -R mysql:mysql /var/lib/mysql
6)启动服务:
[root@centos8 ~]#service mysqld start

四、 实现mysql主从复制,主主复制和半同步复制

4.1 mysql主从复制步骤

主节点配置:
(1) 启用二进制日志
[mysqld]
log_bin
(2) 为当前节点设置一个全局惟一的ID号
[mysqld]
server-id=#
log-basename=master  #可选项,设置datadir中日志名称,确保不依赖主机名
server-id的取值范围
1 to 4294967295 (>= MariaDB 10.2.2),默认值为1,MySQL8.0默认值为1
0 to 4294967295 (<= MariaDB 10.2.1),默认值为0,如果从节点为0,所有master都将拒绝此
slave的连接
(3) 查看从二进制日志的文件和位置开始进行复制
SHOW MASTER STATUS;
(4) 创建有复制权限的用户账号
GRANT REPLICATION SLAVE  ON *.* TO 'repluser'@'HOST' IDENTIFIED BY 'replpass';
#MySQL8.0 分成两步实现
mysql> create user repluser@'10.0.0.%' identified by '123456';
mysql> grant replication slave on *.* to repluser@'10.0.0.%'; 
从节点配置:
从节点配置:
(1) 启动中继日志
[mysqld]
server_id=# #为当前节点设置一个全局惟的ID号
log-bin
read_only=ON #设置数据库只读,针对supper user无效
relay_log=relay-log #relay log的文件路径,默认值hostname-relay-bin
relay_log_index=relay-log.index  #默认值hostname-relay-bin.index
(2) 使用有复制权限的用户账号连接至主服务器,并启动复制线程
官方说明
https://dev.mysql.com/doc/refman/8.0/en/change-master-to.html
CHANGE MASTER TO MASTER_HOST='masterhost', 
MASTER_USER='repluser', 
MASTER_PASSWORD='replpass', 
MASTER_LOG_FILE='mariadb-bin.xxxxxx', 
MASTER_LOG_POS=#
MASTER_DELAY = interval; #可指定延迟复制实现访问误操作,单位秒
START SLAVE [IO_THREAD|SQL_THREAD];
SHOW SLAVE STATUS; 
#查看 relaylog 事件
SHOW RELAYLOG EVENTS in 'relay-bin.00000x';

范例:主服务器非新建时,主服务器运行一段时间后,新增从节点服务器
如果主节点已经运行了一段时间,且有大量数据时,如何配置并启动slave节点

 - 通过备份恢复数据至从服务器 
 - 复制起始位置为备份时,二进制日志文件及其POS
#在主服务器完全备份
[root@master ~]#mysqldump -A -F --single-transaction --master-data=1 > 
/backup/fullbackup_`date +%F_%T`.sql
[root@master ~]#ll /backup/
total 2988
-rw-r--r-- 1 root root 3055918 Nov 27 17:41 fullbackup_2019-11-27_17:41:17.sql
[root@master ~]#scp /backup/fullbackup_2019-11-27_17\:41\:17.sql 
192.168.8.11:/data/
#建议优化主和从节点服务器的性能
MariaDB [hellodb]> set global innodb_flush_log_at_trx_commit=2
MariaDB [hellodb]> set global sync_binlog=0
MariaDB [hellodb]> set global innodb_flush_log_at_trx_commit=2;
Query OK, 0 rows affected (0.001 sec)
MariaDB [hellodb]> show variables like 'sync_binlog';
| Variable_name       | Value |
+---------------------+-------+
| sync_binlog         | 0     |
|---------------------+-------+
5 rows in set (0.001 sec) 
#将完全备份还原到新的从节点
[root@slave ~]#dnf -y install mariadb-server
[root@slave ~]#vim /etc/my.cnf.d/mariadb-server.cnf 
[mysqld]
server-id=11
read-only
[root@slave ~]#systemctl restart mariadb
#配置从节点,从完全备份的位置之后开始复制
[root@slave ~]#grep '^CHANGE MASTER' /data/fullbackup_2019-11-27_17\:41\:17.sql 
CHANGE MASTER TO MASTER_LOG_FILE='mariadb-bin.000003', MASTER_LOG_POS=389; 
[root@slave ~]#vim /data/fullbackup_2019-11-27_17\:41\:17.sql
CHANGE MASTER TO
MASTER_HOST='10.0.0.8',
MASTER_USER='repluser',
MASTER_PASSWORD='magedu',
MASTER_PORT=3306,                                                             
MASTER_LOG_FILE='mariadb-bin.000003', MASTER_LOG_POS=389; 
[root@slave ~]#mysql < /data/fullbackup_2019-11-27_17\:41\:17.sql
[root@slave ~]#mysql 
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 9
Server version: 10.3.11-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: 
                   Master_Host: 10.0.0.8
                   Master_User: repluser
                   Master_Port: 3306
                 Connect_Retry: 60
               Master_Log_File: mariadb-bin.000003
           Read_Master_Log_Pos: 389
               Relay_Log_File: mariadb-relay-bin.000001
                 Relay_Log_Pos: 4
         Relay_Master_Log_File: mariadb-bin.000003
             Slave_IO_Running: No
             Slave_SQL_Running: No

4.1.1主从复制相关注意事项

限制从服务器为只读
read_only=ON
#注意:此限制对拥有SUPER权限的用户均无效
以下命令会阻止所有用户, 包括主服务器复制的更新
FLUSH TABLES WITH READ LOCK;
在从节点清除信息
以下都需要先 STOP SLAVE
RESET SLAVE #从服务器清除master.info ,relay-log.info, relay log ,开始新的relay log
RESET SLAVE  ALL #清除所有从服务器上设置的主服务器同步信息,如HOST,PORT, USER和 PASSWORD 等

复制错误解决方法
可以在从服务器忽略几个主服务器的复制事件,此为global变量,或指定跳过事件的ID
注意: Centos 8.1以上版本上的MariaDB10.3主从节点同时建同名的库和表不会冲突,建主键记录会产生
冲突
#系统变量,指定跳过复制事件的个数
SET GLOBAL sql_slave_skip_counter = N
#服务器选项,只读系统变量,指定跳过事件的ID
[mysqld]
slave_skip_errors=1007|ALL  

4.2 mysql主从复制步骤

主主复制:两个节点,都可以更新数据,并且互为主从
容易产生的问题:数据不一致;因此慎用
考虑要点:自动增长id
配置一个节点使用奇数id
auto_increment_offset=1   #开始点
auto_increment_increment=2 #增长幅度
另一个节点使用偶数id
auto_increment_offset=2
auto_increment_increment=2
操作与mysql主从类同就不详细记录了
主主复制的配置步骤:
 (1) 各节点使用一个惟一server_id
 (2) 都启动binary log和relay log
 (3) 创建拥有复制权限的用户账号
 (4) 定义自动增长id字段的数值范围各为奇偶
 (5) 均把对方指定为主节点,并启动复制线程

4.3 半同步复制

(两个从节点2选一只要有一个同步成功就返回给客户端同步成功,如果主节点网络出现问题同步不了了,也不会干等着有个超时10秒的机制,直接返回结果成功)
默认情况下,MySQL的复制功能是异步的,异步复制可以提供最佳的性能,主库把binlog日志发送给从
库即结束,并不验证从库是否接收完毕。这意味着当主服务器或从服务器端发生故障时,有可能从服务
器没有接收到主服务器发送过来的binlog日志,这就会造成主服务器和从服务器的数据不一致,甚至在
恢复时造成数据的丢失
MySQL5.5版本为了保证主从数据的一致性问题。加入了半同步复制的组件(插件),可以控制从库IO线程是
否将relaylog落盘,一旦落盘通过插件返回ACK给主库ACK_REC。接受到ACK之后,主库的事务才能提交
成功。在默认情况下,如果超过10秒没有返回ACK,此次复制行为会切换为异步复制
在MySQL5.6,5.7 当中也加入了一些比较好的特性,也不能完全保证的数据一致。如果生产业务比较关注
主从最终一致(比如:金融等)。推荐可以使用MGR的架构,或者PXC等一致性架构

半同步复制默认设置
rpl_semi_sync_master_wait_point=after_commit
缺点:
缺点1: 幻读
当用户提交一个事务,该事务已经写入redo日志和binlog日志,但该事务还没写入从库,此时处在waiting 
slave dump处,此时另一个用户可以读取到这条数据,而他自己却不能;
缺点2:数据丢失
一个提交的事务在waiting slave dump处crash后,主库将比从库多一条数据
增强半同步复制(MySQL5.7新增功能)
rpl_semi_rsync_master_wait_point=after_sync
优点
改善1:解决幻读
当用户发起一个事务,该事务先写入二进制后,再向从库进行同步,由于还没有完成提交,此时其他用户无法
读取到该数据,解决了幻读
改善2:解决数据丢失
一个事务在waiting slave dump处crash掉后,可以通过观察从库上是否存在主库的last gtid值,如果
存在,这条数据正常恢复,如果不存在则删除主库的那条多余的GTID值,然后恢复,保证了数据的完整性

半同步复制实现:
官方文档:
https://dev.mysql.com/doc/refman/8.0/en/replication-semisync.html
https://dev.mysql.com/doc/refman/5.7/en/replication-semisync.html
https://mariadb.com/kb/en/library/semisynchronous-replication/

范例: CentOS8 在MySQL8.0 实现半同步复制

#查看插件文件
[root@centos8 ~]#rpm -ql mysql-server |grep semisync
/usr/lib64/mysql/plugin/semisync_master.so
/usr/lib64/mysql/plugin/semisync_slave.so
#master服务器配置
[root@master ~]#vim /etc/my.cnf.d/mysql-server.cnf
[mysqld]
server-id=8
log-bin
rpl_semi_sync_master_enabled=ON     #修改此行,需要先安装semisync_master.so插件后,再重
启,否则无法启动
rpl_semi_sync_master_timeout=3000   #设置3s内无法同步,也将返回成功信息给客户端
#slave服务器配置
[root@slave1 ~]#vim /etc/my.cnf.d/mysql-server.cnf
[mysqld]
server-id=18
rpl_semi_sync_slave_enabled=ON #修改此行,需要先安装semisync_slave.so插件后,再重启,否则
无法启动
[root@slave2 ~]#vim /etc/my.cnf.d/mysql-server.cnf
[mysqld]
server-id=28
rpl_semi_sync_slave_enabled=ON #修改此行,需要先安装semisync_slave.so插件后,再重启,否则
无法启动
#主服务器配置:
mysql>INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so'; #永久安装插
件
mysql>UNINSTALL PLUGIN rpl_semi_sync_master ;
mysql>SHOW PLUGINS; #查看插件
mysql>SET GLOBAL rpl_semi_sync_master_enabled=1; #临时修改变量
mysql>SET GLOBAL rpl_semi_sync_master_timeout = 3000;  #超时长1s,默认值为10s
mysql>SHOW GLOBAL VARIABLES LIKE '%semi%'; +-------------------------------------------+------------+
| Variable_name                             | Value     |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled             | ON         |
| rpl_semi_sync_master_timeout             | 10000     |
| rpl_semi_sync_master_trace_level         | 32         |
| rpl_semi_sync_master_wait_for_slave_count | 1         |
| rpl_semi_sync_master_wait_no_slave       | ON         |
| rpl_semi_sync_master_wait_point           | AFTER_SYNC |
+-------------------------------------------+------------+ 6 rows in set (0.00 sec)
mysql> SHOW GLOBAL STATUS LIKE '%semi%'; +--------------------------------------------+-------+
| Variable_name                             | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 2     |
| Rpl_semi_sync_master_net_avg_wait_time     | 0     |
| Rpl_semi_sync_master_net_wait_time         | 0     |
| Rpl_semi_sync_master_net_waits             | 0     |
| Rpl_semi_sync_master_no_times             | 1     |
| Rpl_semi_sync_master_no_tx                 | 2     |
| Rpl_semi_sync_master_status               | ON   |
| Rpl_semi_sync_master_timefunc_failures     | 0     |
| Rpl_semi_sync_master_tx_avg_wait_time     | 0     |
| Rpl_semi_sync_master_tx_wait_time         | 0     |
| Rpl_semi_sync_master_tx_waits             | 0     |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0     |
| Rpl_semi_sync_master_wait_sessions         | 0     |
| Rpl_semi_sync_master_yes_tx               | 0     |
+--------------------------------------------+-------+
14 rows in set (0.00 sec)
#从服务器配置:
mysql>INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
mysql>SET GLOBAL rpl_semi_sync_slave_enabled=1; #临时修改变量
mysql> SHOW GLOBAL VARIABLES LIKE '%semi%'; +---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled     | ON   |
| rpl_semi_sync_slave_trace_level | 32   |
+---------------------------------+-------+ 2 rows in set (0.00 sec)
#注意:如果已经实现主从复制,需要stop slave;start slave;
mysql> stop slave;
mysql> start slave;
mysql> SHOW GLOBAL STATUS LIKE '%semi%'; +----------------------------+-------+
| Variable_name             | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON   |
+----------------------------+-------+ 1 row in set (0.00 sec)

范例:CentOS 8 在Mariadb-10.3.11上实现 实现半同步复制

#在master实现,启用半同步功能
[root@master ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=8
log-bin
plugin-load-add = semisync_master
rpl_semi_sync_master_enabled=ON
rpl_semi_sync_master_timeout=3000   #设置3s内无法同步,也将返回成功信息给客户端
[root@centos8 ~]#systemctl restart mariadb
MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE '%semi%';
+---------------------------------------+--------------+
| Variable_name                         | Value        |
+---------------------------------------+--------------+
| rpl_semi_sync_master_enabled          | ON           | | rpl_semi_sync_master_timeout          | 3000         | | rpl_semi_sync_master_trace_level      | 32           | | rpl_semi_sync_master_wait_no_slave    | ON           | | rpl_semi_sync_master_wait_point       | AFTER_COMMIT | | rpl_semi_sync_slave_delay_master      | OFF          | | rpl_semi_sync_slave_enabled           | OFF          | | rpl_semi_sync_slave_kill_conn_timeout | 5            | | rpl_semi_sync_slave_trace_level       | 32           |
+---------------------------------------+--------------+
9 rows in set (0.002 sec)
MariaDB [(none)]> SHOW GLOBAL STATUS LIKE '%semi%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 0     | | Rpl_semi_sync_master_get_ack               | 0     | | Rpl_semi_sync_master_net_avg_wait_time     | 0     | | Rpl_semi_sync_master_net_wait_time         | 0     | | Rpl_semi_sync_master_net_waits             | 0     | | Rpl_semi_sync_master_no_times              | 0     | | Rpl_semi_sync_master_no_tx                 | 0     | | Rpl_semi_sync_master_request_ack           | 0     | | Rpl_semi_sync_master_status                | ON    | | Rpl_semi_sync_master_timefunc_failures     | 0     | | Rpl_semi_sync_master_tx_avg_wait_time      | 0     |
| Rpl_semi_sync_master_tx_wait_time          | 0     | | Rpl_semi_sync_master_tx_waits              | 0     | | Rpl_semi_sync_master_wait_pos_backtraverse | 0     | | Rpl_semi_sync_master_wait_sessions         | 0     | | Rpl_semi_sync_master_yes_tx                | 0     | | Rpl_semi_sync_slave_send_ack               | 0     | | Rpl_semi_sync_slave_status                 | OFF   |
+--------------------------------------------+-------+
18 rows in set (0.001 sec) #在其它所有slave节点上都实现,启用半同步功能
[root@slave ~]#vim /etc/my.cnf.d/mariadb-server.cnf 
[mysqld]
server-id=18
plugin_load_add = semisync_slave
rpl_semi_sync_slave_enabled=ON  
[root@slave ~]#systemctl restart mariadb
[root@slave ~]#mysql 
MariaDB [(none)]>  SHOW GLOBAL VARIABLES  LIKE '%semi%';
+---------------------------------------+--------------+
| Variable_name                         | Value        |
+---------------------------------------+--------------+
| rpl_semi_sync_master_enabled          | OFF          | | rpl_semi_sync_master_timeout          | 10000        | | rpl_semi_sync_master_trace_level      | 32           | | rpl_semi_sync_master_wait_no_slave    | ON           | | rpl_semi_sync_master_wait_point       | AFTER_COMMIT | | rpl_semi_sync_slave_delay_master      | OFF          | | rpl_semi_sync_slave_enabled           | ON           | | rpl_semi_sync_slave_kill_conn_timeout | 5            | | rpl_semi_sync_slave_trace_level       | 32           |
+---------------------------------------+--------------+
9 rows in set (0.001 sec)
MariaDB [(none)]>  SHOW GLOBAL STATUS  LIKE '%semi%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 0     | | Rpl_semi_sync_master_get_ack               | 0     | | Rpl_semi_sync_master_net_avg_wait_time     | 0     | | Rpl_semi_sync_master_net_wait_time         | 0     | | Rpl_semi_sync_master_net_waits             | 0     | | Rpl_semi_sync_master_no_times              | 0     | | Rpl_semi_sync_master_no_tx                 | 0     | | Rpl_semi_sync_master_request_ack           | 0     | | Rpl_semi_sync_master_status                | OFF   | | Rpl_semi_sync_master_timefunc_failures     | 0     | | Rpl_semi_sync_master_tx_avg_wait_time      | 0     | | Rpl_semi_sync_master_tx_wait_time          | 0     | | Rpl_semi_sync_master_tx_waits              | 0     | | Rpl_semi_sync_master_wait_pos_backtraverse | 0     | | Rpl_semi_sync_master_wait_sessions         | 0     | | Rpl_semi_sync_master_yes_tx                | 0     | | Rpl_semi_sync_slave_send_ack               | 0     | | Rpl_semi_sync_slave_status                 | ON    |
+--------------------------------------------+-------+
18 rows in set (0.001 sec)
MariaDB [(none)]> #在master上实现
MariaDB [db1]> SHOW GLOBAL STATUS LIKE '%semi%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 2     |  #两个从节点
| Rpl_semi_sync_master_get_ack               | 4     | | Rpl_semi_sync_master_net_avg_wait_time     | 0     | | Rpl_semi_sync_master_net_wait_time         | 0     | | Rpl_semi_sync_master_net_waits             | 4     | | Rpl_semi_sync_master_no_times              | 1     | | Rpl_semi_sync_master_no_tx                 | 1     | | Rpl_semi_sync_master_request_ack           | 3     | | Rpl_semi_sync_master_status                | ON    | | Rpl_semi_sync_master_timefunc_failures     | 0     | | Rpl_semi_sync_master_tx_avg_wait_time      | 1177  | | Rpl_semi_sync_master_tx_wait_time          | 2355  | | Rpl_semi_sync_master_tx_waits              | 2     | | Rpl_semi_sync_master_wait_pos_backtraverse | 0     | | Rpl_semi_sync_master_wait_sessions         | 0     | | Rpl_semi_sync_master_yes_tx                | 2     | | Rpl_semi_sync_slave_send_ack               | 0     | | Rpl_semi_sync_slave_status                 | OFF   |
+--------------------------------------------+-------+
18 rows in set (0.001 sec) #测试
#在master实现,创建数据库,立即成功
MariaDB [db1]> create database db2;
Query OK, 1 row affected (0.004 sec) #在所有slave节点实现,停止复制线程
MariaDB [(none)]> stop slave;
Query OK, 0 rows affected (0.011 sec) #在master实现,创建数据库,等待3s才能成功
MariaDB [db1]> create database db3;
Query OK, 1 row affected (3.003 sec) #在任意一个slave节点实现,恢复复制线程
MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.006 sec) #在master实现,创建数据库,立即成功
MariaDB [db1]> create database db4;
Query OK, 1 row affected (0.002 sec) #在所有从节点停止同步线程,在主节点可以看到以下日志信息
MariaDB [db1]> stop slave; [root@centos8 ~]#tail /var/log/mariadb/mariadb.log
2020-08-29 10:11:19 15 [Warning] IP address '10.0.0.28' could not be resolved: 
Name or service not known
2020-08-29 10:11:19 15 [Note] Start binlog_dump to slave_server(28), 
pos(mariadb-bin.000001, 330)
2020-08-29 10:11:19 15 [Note] Start semi-sync binlog_dump to slave (server_id: 
28), pos(mariadb-bin.000001, 330)
2020-08-29 10:12:34 15 [Note] Stop semi-sync binlog_dump to slave (server_id: 
28)
2020-08-29 10:16:05 17 [Note] Start binlog_dump to slave_server(28), 
pos(mariadb-bin.000002, 27378670)
2020-08-29 10:16:05 17 [Note] Start semi-sync binlog_dump to slave (server_id: 
28), pos(mariadb-bin.000002, 27378670)
2020-08-29 10:16:31 12 [Note] Stop semi-sync binlog_dump to slave (server_id: 
18)
2020-08-29 10:16:37 17 [Note] Stop semi-sync binlog_dump to slave (server_id: 
28)
2020-08-29 10:17:19 14 [Warning] Timeout waiting for reply of binlog (file: 
mariadb-bin.000002, pos: 27378922), semi-sync up to file mariadb-bin.000002, 
position 27378795.
2020-08-29 10:17:19 14 [Note] Semi-sync replication switched OFF.

范例:CentOS 7 实现Mariadb 5.5.65 的半同步复制

#主服务器配置:
MariaDB [(none)]>INSTALL PLUGIN rpl_semi_sync_master SONAME
'semisync_master.so';
MariaDB [(none)]>UNINSTALL PLUGIN rpl_semi_sync_master ;
MariaDB [(none)]>SHOW PLUGINS; #查看插件
MariaDB [(none)]>SET GLOBAL rpl_semi_sync_master_enabled=1;
MariaDB [(none)]>SET GLOBAL rpl_semi_sync_master_timeout = 1000;  #超时长1s,默认值
为10s
MariaDB [(none)]>SHOW GLOBAL VARIABLES LIKE '%semi%';
MariaDB [(none)]>SHOW GLOBAL STATUS LIKE '%semi%'; #从服务器配置:
MariaDB [(none)]>INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
MariaDB [(none)]>SET GLOBAL rpl_semi_sync_slave_enabled=1;

五、 用mycat实现mysql的读写分离

Mycat 安装

下载安装JDK
yum -y install java
#确认安装成功
java -version
openjdk version "1.8.0_201"
OpenJDK Runtime Environment (build 1.8.0_201-b09)
OpenJDK 64-Bit Server VM (build 25.201-b09, mixed mode)

下载安装mycat

wget http://dl.mycat.org.cn/1.6.7.4/Mycat-server-1.6.7.4-release/Mycat-server-
1.6.7.4-release-20200105164103-linux.tar.gz
mkdir /apps
tar xvf Mycat-server-1.6.7.4-release-20200105164103-linux.tar.gz  -C /apps
ls /apps/mycat/bin
 catlet conf lib logs version.txt

mycat安装目录结构:

bin mycat命令,启动、重启、停止等
catlet catlet为Mycat的一个扩展功能
conf Mycat 配置信息,重点关注
lib Mycat引用的jar包,Mycat是java开发的
logs 日志文件,包括Mycat启动的日志和运行的日志
version.txt mycat版本说明
logs目录:
wrapper.log mycat启动日志
mycat.log mycat详细工作日志
Mycat的配置文件都在conf目录里面,这里介绍几个常用的文件:
server.xml Mycat软件本身相关的配置文件,设置账号、参数等
schema.xml Mycat对应的物理数据库和数据库表的配置,读写分离、高可用、分布式策略定制、
节点控制
rule.xml Mycat分片(分库分表)规则配置文件,记录分片规则列表、使用方法等

启动和连接

#配置环境变量
vim /etc/profile.d/mycat.sh
PATH=/apps/mycat/bin:$PATH
source /etc/profile.d/mycat.sh
#启动
mycat start
#查看日志,确定成功
cat /app/mycat/logs/wrapper.log 
...省略...
INFO   | jvm 1   | 2019/11/01 21:41:02 | MyCAT Server startup successfully. see 
logs in logs/mycat.log
#连接mycat:
mysql -uroot -p123456 -h 127.0.0.1 -P8066

Mycat 主要配置文件说明

server.xml
存放Mycat软件本身相关的配置文件,比如:连接Mycat的用户,密码,数据库名称等
server.xml文件中配置的参数解释说明:
参数 说明
user 用户配置节点
name 客户端登录MyCAT的用户名,也就是客户端用来连接Mycat的用户名。
password 客户端登录MyCAT的密码
schemas 数据库名,这里会和schema.xml中的配置关联,多个用逗号分开,例如:db1,db2
privileges 配置用户针对表的增删改查的权限
readOnly mycat逻辑库所具有的权限。true为只读,false为读写都有,默认为false
注意:
server.xml文件里登录mycat的用户名和密码可以任意定义,这个账号和密码是为客户机登录
mycat时使用的账号信息
逻辑库名(如上面的TESTDB,也就是登录mycat后显示的库名,切换这个库之后,显示的就是代理
的真实mysql数据库的表)要在schema.xml里面也定义,否则会导致mycat服务启动失败!
这里只定义了一个标签,所以把多余的都注释了。如果定义多个标签,即设置多个连接mycat的用
户名和密码,那么就需要在schema.xml文件中定义多个对应的库!
schema.xml
是最主要的配置项,此文件关联mysql读写分离策略,读写分离、分库分表策略、分片节点都是在此文
件中配置的.MyCat作为中间件,它只是一个代理,本身并不进行数据存储,需要连接后端的MySQL物理
服务器,此文件就是用来连接MySQL服务器的
schema.xml文件中配置的参数解释说明:
参数 说明
schema 数据库设置,此数据库为逻辑数据库,name与server.xml中schema对应
dataNode 分片信息,也就是分库相关配置
dataHost 物理数据库,真正存储数据的数据库
配置说明
name属性唯一标识dataHost标签,供上层的标签使用。
maxCon属性指定每个读写实例连接池的最大连接。也就是说,标签内嵌套的writeHost、readHost标
签都会使用这个属性的值来实例化出连接池的最大连接数
minCon属性指定每个读写实例连接池的最小连接,初始化连接池的大小
每个节点的属性逐一说明
schema:
属性 说明
name 逻辑数据库名,与server.xml中的schema对应
checkSQLschema 数据库前缀相关设置,这里为false
sqlMaxLimit select 时默认的limit,避免查询全表
table
属性 说明
name 表名,物理数据库中表名
dataNode 表存储到哪些节点,多个节点用逗号分隔。节点为下文dataNode设置的name
primaryKey 主键字段名,自动生成主键时需要设置
autoIncrement 是否自增
rule 分片规则名,具体规则下文rule详细介绍
dataNode
属性 说明
name 节点名,与table中dataNode对应
datahost 物理数据库名,与datahost中name对应
database 物理数据库中数据库名
dataHost
属性 说明
name 物理数据库名,与dataNode中dataHost对应
balance 均衡负载的方式
writeType 写入方式
dbType 数据库类型
heartbeat 心跳检测语句,注意语句结尾的分号要加
schema.xml文件中有三点需要注意:balance="1",writeType="0" ,switchType="1" 
schema.xml中的balance的取值决定了负载均衡对非事务内的读操作的处理。balance 属性负载均衡类
型,目前的取值有 4 种:
balance="0":不开启读写分离机制,所有读操作都发送到当前可用的writeHost上,即读请求仅发送到
writeHost上
balance="1":一般用此模式,读请求随机分发到当前writeHost对应的readHost和standby的
writeHost上。即全部的readHost与stand by writeHost 参与 select 语句的负载均衡,简单的说,当双
主双从模式(M1 ->S1 , M2->S2,并且 M1 与 M2 互为主备),正常情况下, M2,S1, S2 都参与 select 语句的负载均衡
balance="2":读请求随机分发到当前dataHost内所有的writeHost和readHost上。即所有读操作都随
机的在writeHost、 readhost 上分发
balance="3":读请求随机分发到当前writeHost对应的readHost上。即所有读请求随机的分发到
wiriterHost 对应的 readhost 执行, writerHost 不负担读压力,注意 balance=3 只在 1.4 及其以后版本
有,1.3 没有
writeHost和readHost 标签
这两个标签都指定后端数据库的相关配置给mycat,用于实例化后端连接池。
唯一不同的是:writeHost指定写实例、readHost指定读实例,组着这些读写实例来满足系统的要求。
在一个dataHost内可以定义多个writeHost和readHost。但是,如果writeHost指定的后端数据库宕机,
那么这个writeHost绑定的所有readHost都将不可用。另一方面,由于这个writeHost宕机系统会自动的
检测到,并切换到备用的writeHost上去
注意:
Mycat主从分离只是在读的时候做了处理,写入数据的时候,只会写入到writehost,需要通过mycat的
主从复制将数据复制到readhost

5.1实战案例:利用 Mycat 实现 MySQL 的读写分离

所有主机的系统环境

cat /etc/centos-release
CentOS Linux release 8.0.1905 (Core) 
mycat-server 10.0.0.8 #内存建议2G以上
mysql-master 10.0.0.18 MySQL 8.0 或者Mariadb 10.3.17
mysql-slave  10.0.0.28 MySQL 8.0 或者Mariadb 10.3.17

关闭SELinux和防火墙

systemctl stop firewalld
setenforce 0
时间同步

1、创建 MySQL 主从数据库

[root@centos8 ~]#yum -y install mysql-server
#或者
[root@centos8 ~]#yum -y install mariadb-server 
  1. 修改master和slave上的配置文件
#master上的my.cnf
[root@centos8 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id = 1
log-bin
#slave上的my.cnf
[mysqld]
server-id = 2 
[root@centos8 ~]#systemctl start mariadb
  1. Master上创建复制用户
[root@centos8 ~]#mysql -uroot -p
MariaDB [(none)]>GRANT REPLICATION SLAVE ON *.* TO 'repluser'@'10.0.0.%' 
IDENTIFIED BY 'replpass';
mysql> FLUSH PRIVILEGES;    
mysql> show master status;
+------------------+----------+--------------+------------------+----------------
---+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
Executed_Gtid_Set |
+------------------+----------+--------------+------------------+----------------
---+
|mariadb-bin.000001|      403 |              |                  |               
    |
+------------------+----------+--------------+------------------+----------------
---+
1 row in set (0.00 sec)
  1. Slave上执行
[root@centos8 ~]#mysql -uroot -p
mysql> CHANGE MASTER TO
->     MASTER_HOST='10.0.0.%',
->     MASTER_USER='repluser',
->     MASTER_PASSWORD='replpass',
->     MASTER_LOG_FILE='mariadb-bin.000001',
->     MASTER_LOG_POS=403;
mysql> start slave;

2、在MySQL代理服务器10.0.0.8安装mycat并启动

root@centos8 ~]#yum -y install java 
#确认安装成功
[root@centos8 ~]#java -version
openjdk version "1.8.0_201"
OpenJDK Runtime Environment (build 1.8.0_201-b09)
OpenJDK 64-Bit Server VM (build 25.201-b09, mixed mode)
#下载并安装
[root@centos8 ~]#wget http://dl.mycat.org.cn/1.6.7.6/20210303094759/Mycat-server-
1.6.7.6-release-20210303094759-linux.tar.gz
#wget http://dl.mycat.org.cn/1.6.7.4/Mycat-server-1.6.7.4-release/Mycat-server-
1.6.7.4-release-20200105164103-linux.tar.gz
[root@centos8 ~]#mkdir /apps
[root@centos8 ~]#tar xvf Mycat-server-1.6.7.6-release-20210303094759-linux.tar.gz
-C /apps/
#tar xvf Mycat-server-1.6.7.4-release-20200105164103-linux.tar.gz -C /apps
#配置环境变量
[root@centos8 ~]#echo 'PATH=/apps/mycat/bin:$PATH' > /etc/profile.d/mycat.sh
[root@centos8 ~]#source /etc/profile.d/mycat.sh
#查看端口
[root@centos8 ~]#ss -ntl
State         Recv-Q       Send-Q     Local Address:Port     Peer Address:Port   
              
LISTEN        0             128              0.0.0.0:22            0.0.0.0:*     
               
LISTEN        0             128                 [::]:22               [::]:*  
#启动mycat
[root@mycat ~]#file /apps/mycat/bin/mycat 
/apps/mycat/bin/mycat: POSIX shell script, ASCII text executable
[root@mycat ~]#mycat
Usage: /apps/mycat/bin/mycat { console | start | stop | restart | status | dump 
}
#注意: 此步启动较慢,需要等一会儿,另外如果内存太小,会导致无法启动
[root@centos8 ~]#mycat start
Starting Mycat-server...
#可以看到打开多个端口,其中8066端口用于连接MyCAT
[root@centos8 ~]#ss -ntlp
State           Recv-Q           Send-Q Local Address:Port   Peer Address:Port   
                            
LISTEN          0                128          0.0.0.0:22          0.0.0.0:*     
          users:(("sshd",pid=791,fd=5))             
LISTEN          0                1          127.0.0.1:32000       0.0.0.0:*     
          users:(("java",pid=4640,fd=4))            
LISTEN          0                128             [::]:22             [::]:*     
          users:(("sshd",pid=791,fd=7))             
LISTEN          0                50                 *:1984             *:*     
          users:(("java",pid=4640,fd=57))           
LISTEN          0                100               *:8066             *:*     
          users:(("java",pid=4640,fd=87))           
LISTEN          0                50                 *:43465             *:*     
          users:(("java",pid=4640,fd=58))           
LISTEN          0                100               *:9066             *:*     
          users:(("java",pid=4640,fd=83))           
LISTEN          0                50                 *:45259             *:*     
          users:(("java",pid=4640,fd=56))
#查看日志,确定成功,可能需要等一会儿才能看到成功的提示
[root@centos8 ~]#tail /apps/mycat/logs/wrapper.log 
ERROR | wrapper | 2020/02/28 15:21:48 | Startup failed: Timed out waiting for
a signal from the JVM.
ERROR | wrapper | 2020/02/28 15:21:48 | JVM did not exit on request, 
terminated
INFO   | wrapper | 2020/02/28 15:21:48 | JVM exited on its own while waiting to 
kill the application.
STATUS | wrapper | 2020/02/28 15:21:48 | JVM exited in response to signal 
SIGKILL (9).
STATUS | wrapper | 2020/02/28 15:21:52 | Launching a JVM...
INFO   | jvm 2   | 2020/02/28 15:21:52 | OpenJDK 64-Bit Server VM warning: 
ignoring option MaxPermSize=64M; support was removed in 8.0
INFO   | jvm 2   | 2020/02/28 15:22:13 | Wrapper (Version 3.2.3) 
http://wrapper.tanukisoftware.org
INFO   | jvm 2   | 2020/02/28 15:22:13 |   Copyright 1999-2006 Tanuki Software, 
Inc. All Rights Reserved.
INFO   | jvm 2   | 2020/02/28 15:22:13 | 
INFO   | jvm 2   | 2020/02/28 15:22:31 | MyCAT Server startup successfully. see 
logs in logs/mycat.log
#用默认密码123456来连接mycat
[root@centos8 ~]#mysql -uroot -p123456 -h 10.0.0.8 -P8066
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.29-mycat-1.6-RELEASE-20161028204710 MyCat Server 
(OpenCloundDB)
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MySQL [(none)]> show databases;
+----------+
| DATABASE |
+----------+
| TESTDB   |
+----------+ 
1 row in set (0.01 sec)
MySQL [TESTDB]> show tables;
+------------------+
| Tables in TESTDB |
+------------------+
| address         |
| travelrecord     |
+------------------+ 
2 rows in set (0.01 sec)
MySQL [TESTDB]> select * from travelrecord ;
ERROR 1105 (HY000): backend connect: java.lang.IllegalArgumentException: Invalid 
DataSource:0
MySQL [TESTDB]>

4、在mycat 服务器上修改server.xml文件配置Mycat的连接信息

[root@centos8 ~]#vim /apps/mycat/conf/server.xml
...省略...
#修改下面行的8066改为3306复制到到独立非注释行
<property name="serverPort">3306</property>
<property name="handlelDistributedTransactions">0</property> #将上面行放在此行前面
#或者删除注释,并修改下面行的8066改为3306
<property name="serverPort">3306</property>
<property name="managerPort">9066</property>
<property name="idleTimeout">300000</property>
<property name="authTimeout">15000</property>
<property name="bindIp">0.0.0.0</property>
<property name="dataNodeIdleCheckPeriod">300000</property> #5 * 60 * 1000L; //连
接空闲检查 删除#后面此部分
<property name="frontWriteQueueSize">4096</property> <property 
name="processors">32</property> #--> 删除#后面此部分
 .....
<user name="root">                                       #连接Mycat的用户名
   <property name="password">magedu</property>          #连接Mycat的密码
   <property name="schemas">TESTDB</property>           #数据库名要和schema.xml相
对应
</user>
</mycat:server>

马哥SRE第六周课程作业_第2张图片
这里使用的是root,密码为magedu,逻辑数据库为TESTDB,这些信息都可以自己随意定义,读写权限都
有,没有针对表做任何特殊的权限。重点关注上面这段配置,其他默认即可。
5、修改schema.xml实现读写分离策略

[root@centos8 ~]#vim /apps/mycat/conf/schema.xml                                 
      
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="***false***" sqlMaxLimit="100"
dataNode="***dn1***"></schema>
<dataNode name="dn1" dataHost="localhost1" database="***mycat***" />  #其中mycat表
示后端服务器实际的数据库名称
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="***1***"
writeType="0" dbType="mysql" dbDriver="native" switchType="1"
slaveThreshold="100">
<heartbeat>select user()</heartbeat>
***<writeHost host="host1" url="10.0.0.18:3306" user="root"
password="123456">***
***<readHost host="host2" url="10.0.0.28:3306" user="root" password="123456"
/>***
</writeHost>
</dataHost>
</mycat:schema>
#以上***部分表示原配置文件中需要修改的内容
#注意大小写
#最终文件内容
[root@mycat ~]#cat /apps/mycat/conf/schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
 <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100"
dataNode="dn1">
 </schema>
 <dataNode name="dn1" dataHost="localhost1" database="hellodb" />
 <dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
  writeType="0" dbType="mysql" dbDriver="native" switchType="1"
slaveThreshold="100">
 <heartbeat>select user()</heartbeat>
 <writeHost host="host1" url="10.0.0.18:3306" user="root"
   password="123456">
         <readHost host="host2" url="10.0.0.28:3306" user="root"
password="123456" />
 </writeHost>
   </dataHost>
</mycat:schema>
#重新启动mycat
[root@centos8 ~]#mycat restart

上面配置中,balance改为1,表示读写分离。以上配置达到的效果就是10.0.0.18为主库,10.0.0.28为
从库
注意:要保证能使用root/123456权限成功登录10.0.0.18和10.0.0.28机器上面的mysql数据库。同时,
也一定要授权mycat机器能使用root/123456权限成功登录这两台机器的mysql数据库!!这很重要,否
则会导致登录mycat后,对库和表操作失败!
范例:schema.xml
马哥SRE第六周课程作业_第3张图片
6、在后端主服务器创建用户并对mycat授权

[root@centos8 ~]#mysql -uroot -p
mysql> create database mycat;
mysql>GRANT ALL ON *.* TO 'root'@'10.0.0.%' IDENTIFIED BY '123456' ;
mysql> flush privileges; 

7、在Mycat服务器上连接并测试

[root@centos8 ~]#mysql -uroot -pmagedu -h127.0.0.1 TESTDB
mysql> show databases;
+----------+
| DATABASE |
+----------+
| TESTDB   |   //只能看一个虚拟数据库
+----------+
mysql> use TESTDB;
mysql> create table t1(id int);
MySQL> select @@server_id;
MySQL> select @@hostname; 

8、通过通用日志确认实现读写分离

在mysql中查看通用日志
show variables like 'general_log';  #查看日志是否开启
set global general_log=on;    #开启日志功能
show variables like 'general_log_file'; #查看日志文件保存位置
set global general_log_file='tmp/general.log'; #设置日志文件保存位置
在主和从服务器分别启用通用日志,查看读写分离
[root@centos8 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
general_log=ON
[root@centos8 ~]#systemctl restart mariadb
[root@centos8 ~]#tail -f /var/lib/mysql/centos8.log 

9、停止从节点,MyCAT自动调度读请求至主节点

[root@slave ~]#systemctl stop mariadb
[root@client ~]#mysql -uroot -pmagedu -h10.0.0.8 -P8066
MySQL [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|          1 |
+-------------+ 
1 row in set (0.00 sec)
MySQL [(none)]> 
#停止主节点,MyCAT不会自动调度写请求至从节点
MySQL [TESTDB]> insert teachers values(5,'wang',30,'M');
ERROR 1184 (HY000): java.net.ConnectException: Connection refused

10、MyCAT对后端服务器的健康性检查方法select user()

#开启通用日志
[root@master ~]#mysql
mysql> set global  general_log=1;
[root@slave ~]#mysql
mysql> set global  general_log=1; 
#查看通用日志
[root@master ~]#tail -f /var/lib/mysql/master.log 
/usr/libexec/mysqld, Version: 8.0.17 (Source distribution). started with:
Tcp port: 3306 Unix socket: /var/lib/mysql/mysql.sock
Time                 Id Command   Argument
2021-02-22T08:52:57.086198Z   17 Query select user()
2021-02-22T08:53:07.086340Z   24 Query select user()
2021-02-22T08:53:17.086095Z   16 Query select user()
2021-02-22T08:53:27.086629Z   18 Query select user()
[root@slave ~]#tail -f /var/lib/mysql/slave.log 
/usr/libexec/mysqld, Version: 8.0.17 (Source distribution). started with:
Tcp port: 3306 Unix socket: /var/lib/mysql/mysql.sock
Time                 Id Command   Argument
2021-02-22T08:46:01.437376Z   10 Query select user()
2021-02-22T08:46:11.438172Z   11 Query select user()
2021-02-22T08:46:21.437458Z   12 Query select user()
2021-02-22T08:46:31.437742Z   13 Query select user()

六、实现open部署,并且测试通过,输出博客或者自己的文档存档。

你可能感兴趣的:(马哥SRE作业,linux,数据库,sql,mysql)