MySQL---约束、主从复制原理、Docker搭建

MySQL(11)---约束

含义: 一种限制,用于限制表中的数据,为了保证表中的数据的准确和可靠性。

先把Mysql几种约束列出来:

主键约束 外键约束 唯一性约束 非空约束 默认值约束 自增约束

MySQL不支持check约束,但可以使用check约束,而没有任何效果。

一、语法

不多说理论,说下语法和示例就好。

1、建表时直接建约束

drop table student;
CREATE TABLE student(
	id INT PRIMARY KEY auto_increment,#主键 自增
	name VARCHAR(20) NOT NULL UNIQUE,#非空 唯一
	xh INT UNIQUE,#唯一
	age INT DEFAULT  18 #默认约束
)ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='学生表';

-- 上面和下面是一样的,只不过是另一种写法
drop table student;
CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `xh` int(11) DEFAULT NULL,
  `age` int(11) DEFAULT '18',
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`),
  UNIQUE KEY `xh` (`xh`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='学生表';

2、查看约束

这里命令是查看索引的命令,因为建立主键约束会自动的建立主键索引。

同样建立唯一约束也会自动建立唯一索引。

-- 这里只能看到主键约束,唯一约束。
SHOW INDEX FROM 表名;

3、单独建约束

上面的约束是建表时候建的,下面是在表建好后独立添加。

-- 1.添加非空约束
ALTER TABLE student MODIFY COLUMN id INT  auto_increment;
-- 2.添加默认约束
ALTER TABLE 表名 MODIFY COLUMN 字段名 INT DEFAULT 16;
-- 3、主键约束
ALTER TABLE 表名 ADD PRIMARY KEY(字段名);
-- 4、唯一约束
ALTER TABLE 表名 ADD UNIQUE(字段名); #字段名可以多个,多个用逗号隔开
-- 5、主键自增
# 注意自增一张表只有一个,同时只能在主键上
ALTER TABLE 表名 MODIFY COLUMN 字段名 INT  auto_increment;

4、删除约束

-- 1、删除非空约束
ALTER TABLE 表名 MODIFY COLUMN 字段名 VARCHAR(20) NULL;
-- 2、删除主键
-- 这里需要注意如果主键设置为自增的情况下是不能删除成功的,因为自增只能设置在主键上,你删主键自增还存在当然不行。
ALTER TABLE 表名 DROP PRIMARY KEY;
-- 3、删除唯一
ALTER TABLE 表名 DROP INDEX 字段名;

这应该是我最短的博客了,哈哈

MYSQL主从复制原理

最近在做项目的时候,因为部署了 MYSQL主从复制 所以在这里记录下整个过程。这里一共会分两篇博客来写:

1、Mysql主从复制原理
2、docker部署Mysql主从复制实战

这篇只写MYSQL主从复制原理。

一、概述

1、什么是主从复制?

概念 主从复制是用来建立一个和 主数据库完全一样的数据库环境称为从数据库;主数据库一般是准实时的业务数据库。

2、主从复制作用

我们来思考如果在企业网站中,后端MYSQL数据库只有一台时候,会有以下问题

1、单点故障服务不可用
2、无法处理大量的并发数据请求
3、数据丢失

所以通过主从复制后,它的优点就很明显

1、如果主节点出现故障,那么我们就直接将服务切到从节点,来保证服务立马可用。
2、如果并发请求特别大的时候,我们可用进行读写分离操作,让主库负责写,从库负责读。
3、如果主库数据丢失,但从库还保存一份,减少数据丢失的风险。

 

二、主从复制原理

1、主从复制原理

这里先放一张图,这张图很好的诠释的主从复制的原理

上面主要分成了三步,下面会详细说明。

(1) Master的更新事件(update、insert、delete)会按照顺序写入bin-log中。当Slave连接到Master的后,Master机器会为Slave开启

binlog dump线程,该线程会去读取bin-log日志

(2) Slave连接到Master后,Slave库有一个I/O线程 通过请求binlog dump thread读取bin-log日志,然后写入从库的relay log日志中。

(3) Slave还有一个 SQL线程,实时监控 relay-log日志内容是否有更新,解析文件中的SQL语句,在Slave数据库中去执行。

总结

(1) 既然是要把事件记录到bin-log日志,那么对于Master就必须开启bin-log功能

(2) 整个Mysql主从复制一共开启了3个线程。Master开启 IO线程,Slave开启 IO线程 和 SQL线程

(3) 这点也很重要那就是Master和Slave交互的时候,记住这里是Slave去请求Master,而不是Master主动推给Slave。Slave通过IO线程

连接Master后发起请求,Master服务器收到Slave IO线程发来的日志请求信息,io线程去将bin-log内容返回给slave IO线程。

2、MySQL主从复制同步方式

(1)异步复制

MySQL主从同步 默认是异步复制的。就是上面三步中,只有第一步是同步的(也就是Mater写入bin log日志),就是主库写入binlog日志后即可成功返回客户端,无须等待binlog

日志传递给从库的过程。Master 不关心 Slave 的数据有没有写入成功。因此如果Master和Slave之间有网络延迟,就会造成暂时的数据不一致的现象;如果Master出故障,而数据

还没有复制过去,则会造成数据丢失;但也有好处,效率较其他两种复制方式最高。

(2)同步复制

对于同步复制而言,Master主机将事件发送给Slave主机后会触发一个等待,直到所有Slave节点(如果有多个Slave)返回数据复制成功的信息给Master。这种复制方式最安

全,但是同时,效率也是最差的。

(3)半同步复制

对于半同步复制而言,Master主机将事件发送给Slave主机后会触发一个等待,直到其中一个Slave节点(如果有多个Slave)返回数据复制成功的信息给Master。由此增强了

数据的一致性,但是因为Master主机的确认开销,会损耗一部分的性能;另外,半同步复制除了不需要等待所有Slave主机确认事件的接收外,半同步数据复制并不要求那些事件

完全地执行,因此,仍有可能看到在Slave主机上数据复制延迟的发生,如果因为网络延迟等原因造成Slave迟迟没有返回复制成功的信息,超过了Master设置的超时时长,半同步

复制就降级为异步复制方式,而后继续数据复制。

 

三、Mysql主从同步延时

上面也说了,Mysql默认采用的异步操作,因为它的效率明显是最高的。因为只要写入bin log后事物就结束返回成功了。但由于从库从主库异步拷贝日志 以及

串行执行 SQL 的特点,所以从库的数据一定会比主库慢一些,是有延时的。所以经常出现,刚写入主库的数据可能是读不到的,要过几十毫秒,甚至几百毫秒才能

读取到。这就是主从同步延时问题。

1、如何查看主从延迟时间

通过监控 show slave status 命令输出的Seconds_Behind_Master参数的值来判断:

mysql> show slave status\G;
    // 状态一
    Seconds_Behind_Master: NULL
    // 状态二
    Seconds_Behind_Master: 0
    // 状态三
    Seconds_Behind_Master: 79

Seconds_Behind_Master=0: 表示主从复制良好;

Seconds_Behind_Master=NULL: 表示io_thread或是sql_thread有任何一个发生故障;

Seconds_Behind_Master=79: 数字越大表示从库延迟越严重。

2、影响延迟因素

这里整理了影响主从复制延迟大致有以下几个原因:

1)主节点如果执行一个很大的事务,那么就会对主从延迟产生较大的影响

2)网络延迟,日志较大,slave数量过多

3)主上多线程写入,从节点只有单线程同步

4)机器性能问题,从节点是否使用了“烂机器”

5)锁冲突问题也可能导致从机的SQL线程执行慢

3、优化主从复制延迟

这个没有说去完全解决,要想解决那么就只能采用同步复制策略。不过,一般不建议使用这种同步模式。显而易见,如果写操作必须等待更新同步完成,肯定会

极大地影响性能,除非你不在乎性能。

1)大事务:将大事务分为小事务,分批更新数据

2)减少Slave的数量,不要超过5个,减少单次事务的大小

3)MySQL 5.7之后,可以使用多线程复制,使用MGR复制架构

4)在磁盘、raid卡、调度策略有问题的情况下可能会出现单个IO延迟很高的情况,可用iostat命令查看DB数据盘的IO情况,再进一步判断

5)针对锁问题可以通过抓去processlist以及查看information_schema下面和锁以及事务相关的表来查看

总结

主机与从机之间的物理延迟是无法避免的,既然无法避免就可以考虑尝试通过缓存等方式,降低新修改数据被立即读取的概率。

Docker搭建MySQL主从复制(一主一从)

上一篇博客写了MYSQL主从复制原理 : MySQL(13)---MYSQL主从复制原理

这篇我们来写 Docker搭建MYSQL主从复制(一主一从)

一、Docker安装MYSQL

说明 系统为阿里云服务器,操作系统为CentOS7.6。MYSQL版本 8.0.22

1、安装Docker

sudo apt-get update
sudo apt install docker.io

2、拉取MySQL的镜像

# 没有指定版本代表拉取最新版本 目前这里最新的是8.0.22。如果想指定版本可以docker pull mysql:5.7 代表下载5.7版本
docker pull mysql

运行完以上命令之后,镜像就已经下载下来了,可以用 docker images 命令查看是否已经下载成功

3、第一次启动MySQL

docker run -p 3306:3306 --name MYSQL8 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:latest

参数说明

-p 3306:3306:  将容器内的3306端口映射到实体机3306端口
--name MYSQL8: 给这个容器取一个容器记住的名字
-e MYSQL_ROOT_PASSWORD=123456: docker的MySQL默认的root密码是随机的,这是改一下默认的root用户密码
-d mysql:latest: 在后台运行mysql:latest镜像产生的容器

之后的第二次启动直接用 docker start MYSQL8 即可。

4、连接navicat

新装了MYSQL8.0后再用navicat连接就会报2059的错误。上网查了发现是8.0之后MYSQL更改了密码的加密规则,只要在命令窗口把加密方法改回去即可。

1) 首先使用以下命令进入MySQL的Docker容器

# MYSQL8是上面启动的时候 为该容器起的名称
docker exec -it MYSQL8 bash

2)然后登录MySQL

#这里的密码就是上面设置的密码
mysql -uroot -p123456

3)最后运行以下SQL即可

alter user 'root'@'%' identified by '123456' password expire never;
alter user 'root'@'%' identified with mysql_native_password by '123456';
flush privileges;

这样就可以通过navicat工具连接当前数据库了。这里顺便看下当前MYSQL的版本,通过 select version();

明显可以看到当前MYSQL的版本是 8.0.22

注意 我这边Master库和Slave库不在同一个服务器,所以Slave安装MYSQL的步骤和Master一样就可以了。一定要记住Msater库和Slave库的MYSQL版本号要一致

 

二、配置Master和Slave

这里假设主从服务器的IP如下

1、配置Master

因为是通过Docker部署的MYSQL,所以要进入Docker内部修改MYSQL配置文件

# MYSQL8是上面启动的时候 为该容器起的名称
docker exec -it MYSQL8 bash

进入容器后,切换到 /etc/mysql 目录下,使用vim命令编辑 my.cnf 文件。

注意 此时用vim 命令会报 vim: command not found,因此我们需要在Docker内部安装vim工具。安装步骤推荐一篇博客:vi: command not found

在my.cnf添加如下配置

## 同一局域网内注意要唯一
server-id=100  
## 开启二进制日志功能,可以随便取(关键)
log-bin=mysql-bin

添加完后保存,同时退出当前Docker容器。因为修改了配置文件,所以要重启下该MYSQL,这里重启下该Docker容器就好了。

#  MYSQL8是上面启动的时候 为该容器起的名称
docker restart MYSQL8

这个时候我们通过工具连接该MYSQL服务器,你可以通过navicat或者Sequel pro等等,连接登上后。

创建用户并授权

--为从库服务器 设置用户名和密码(表明从服务器的ip必须为47.00.00.02,账号为slave 密码123456
CREATE USER 'slave'@'47.00.00.02' IDENTIFIED BY '123456'; 
grant replication slave, replication client on *.* to 'slave'@'47.00.00.02'; --设置权限
flush privileges;  --权限生效

至此,Master配置完成。

2、配置从库

和上面一样进入到 etc/mysql 路径,使用vim命令编辑 my.cnf 文件:

## 设置server_id,注意要唯一 和master也不能一样
server-id=101 
## 开启二进制日志功能,以备Slave作为其它Slave的Master时使用
log-bin=mysql-slave-bin  
## 设置为只读,该项如果不设置,表示slave可读可写
read_only = 1

配置完成后也需要重启Docker容器。

#  MYSQL是上面启动的时候 为该容器起的名称
docker restart MYSQL8

3、开启Master-Slave主从复制

上面两步Master和Slave都配置成功了,而且Master也为Slave读取Master数据专门设置了一个账号,下面就来实现同步。

进入Master库

查看Master状态

--通过该命令可以查看master数据库当前正在使用的二进制日志及当前执行二进制日志位置
show master status

记住File和Position,后面Slave库会在这个文件这个位置进行同步数据。此时一定不要操作Master库,否则将会引起Master状态的变化,File和Position字段也将会进行变化。

进入Slave库

执行SQL

change master to
master_host='47.00.00.01',
master_user='slave',
master_password='123456',
MASTER_LOG_FILE='mysql-bin.000002',
MASTER_LOG_POS=156 ;

命令说明

master_host :Master库的地址,指的是容器的独立ip,可以通过:
master_port :Master的端口号,指的是容器的端口号(默认3306)
master_user :用于数据同步的用户
master_password :用于同步的用户的密码
master_log_file :指定 Slave 从哪个日志文件开始复制数据,即上文中提到的 File 字段的值
master_log_pos :从哪个 Position 开始读,即上文中提到的 Position 字段的值

使用start slave命令开启主从复制过程

start slave;  -- 顺便提供下其它命令 stop slave 停止slave。reset slave重启slave。 reset master重启master。

启动之后我们来看下有没有成功。

show slave status命令

从这张图很明显看出,对于Slave的两个线程都成功了,那就说明整个MYSQL主从搭建成功了。如果有一个为NO,那就需要到后面看错误日志,是什么原因出错了,解决下就好了。

Slave_IO_Running: 从服务器中I/O线程的运行状态,YES为运行正常
Slave_SQL_Running: 从服务器中SQL线程的运行状态,YES为运行正常

 

三、测试

这里简单做一个测试

1、只在Mater 创建一张User表

现在 只在Mater 创建一张User表,如果现在Slave也同样生成这张User表,那就说明成功了。

CREATE TABLE `user` (
  `id` bigint NOT NULL COMMENT '主键',
  `user_name` varchar(11) NOT NULL COMMENT '用户名',
  `password` varchar(11) NOT NULL COMMENT '密码',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='用户表';

实际测试结果是成功的。

注意

这里如果我们先手动在Slave创建这张User表,然后再到Master创建User表那就出事情了。我们按照上面的步骤创建完后,去Slave通过 show slave status 查看

发现 SQL线程都变NO了。原因很简单,错误日志也说明了(Error 'Table 'user' already exists')。因为你在Master创建User表的SQL会记录到bin-log日志中,然后Slave

去读取这个操作,然后写入Slave中的时后发现这个SQL执行失败,因为你Slave已经存在该User表,然后这整个主从复制就卡在这里了。这是个很严重的问题。

所以一旦搭建主从复制成功,只要在Master做更新事件(update、insert、delete),不要在从数据做,否则会出现数据不一致甚至同步失败。

2、Master插入一条数据

INSERT INTO `user` (`id`, `user_name`, `password`, `create_time`)
VALUES
	(0, '张三', '123456', '2020-11-25 04:29:43');

再去Slave数据库查看

发现从数据库已经写入成功了。

总结:在搭建的过程可能还有其它的问题出现 你只要在Slave服务器,通过show slave status,如果两个IO是否为YES就代表是否成功,如果有为NO的,

后面有字段说明是什么原因导致的,你再根据相关错误信息去查询下解决方案,那就可以了。

 

posted @ 2022-02-21 20:25  hanease  阅读(60)  评论(0编辑  收藏  举报