Docker复杂安装--最详细的MySQL主从复制与Redis集群安装、主从复制、主从扩容主从缩容实战版

目录

一、前言

二、MySQL的主从复制

MySQL主从复制原理

主从搭建

新建主服务器容器实例3307

配置文件

修改完配置重启容器

进入容器实例内

master容器实例内创建数据同步用户并授权

新建从服务器容器实例3308

配置文件

重启容器

在主数据库中查看主从同步状态

进入mysql-slave容器

在从数据库中配置主从复制

在从数据库中查看主从同步状态

在从数据库中开启主从同步

查看从数据库状态发现已经同步

主从复制测试

三、Redis集群搭建

面试题

3主3从redis集群扩缩容配置案例架构

分别启动6台redis容器

构建主从关系

查看集群状态

查看集群节点信息

Redis集群读写出错

集群信息检查

​编辑主从扩容

启动两台新的容器节点

将6387作为master加入集群

检查当前集群状态

重新分配

分配从节点

检查集群当前状态

主从缩容

首先删除从节点6388

对6387哈希槽分走

删除节点6387

查看集群情况


一、前言

上篇文章中我们已经学习了基本的docker上的安装数据库,对于大部分的安装都是大差不差的,但是上文中我们主要针对的是单机版的数据库安装,在实际生产中我们往往需要的是多台服务器,如MySQL的主从复制和Redis的集群,在本文中我们就来看看多台服务器的安装是什么样子。

二、MySQL的主从复制

MySQL主从复制原理

MySQL主从复制原理

主从搭建

新建主服务器容器实例3307

复制代码
docker run -p 3307:3306 
--name mysql-master 
--privileged=true 
-v /mydata/mysql-master/log:/var/log/mysql 
-v /mydata/mysql-master/data:/var/lib/mysql 
-v /mydata/mysql-master/conf:/etc/mysql/conf.d 
-e MYSQL_ROOT_PASSWORD=root -d mysql:5.7

配置文件

进入**/mydata/mysql-master/conf** 目录下新建my.cnf

cpp 复制代码
[mysqld]
## 设置server_id, 同一个局域网中需要唯一
server_id=101
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能
log-bin=mall-mysql-bin
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
## 二进制日志过期清理时间。默认值为0,表示不自动清理
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062

修改完配置重启容器

cpp 复制代码
docker restart mysql-master

进入容器实例内

cpp 复制代码
docker exec -it mysql-master /bin/bash
mysql -uroot -proot

master容器实例内创建数据同步用户并授权

cpp 复制代码
-- 创建数据同步用户
create user 'slave'@'%' identified by '123456';
-- 授权
grant replication slave, replication client on *.* to 'slave'@'%';
flush privileges;
  • 第一条命令创建了一个名为slave的用户,允许从任何IP地址(用%表示)连接到数据库,并设置密码为123456。
  • 第二条命令授予slave用户REPLICATION SLAVE和REPLICATION CLIENT权限。这些权限是进行主从复制所必需的:
    • REPLICATION SLAVE:允许用户读取主服务器的二进制日志,这是实现数据复制的基础。
    • REPLICATION CLIENT:允许用户查询主服务器的状态,例如查看二进制日志文件和位置。

新建从服务器容器实例3308

cpp 复制代码
docker run -p 3308:3306 
--name mysql-slave 
--privileged=true 
-v /mydata/mysql-slave/log:/var/log/mysql 
-v /mydata/mysql-slave/data:/var/lib/mysql 
-v /mydata/mysql-slave/conf:/etc/mysql/conf.d 
-e MYSQL_ROOT_PASSWORD=root -d mysql:5.7

配置文件

进入/mydata/mysql-slave/conf目录下新建my.cnf

cpp 复制代码
[mysqld]
## 设置server_id, 同一个局域网内需要唯一
server_id=102
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能,以备slave作为其它数据库实例的Master时使用
log-bin=mall-mysql-slave1-bin
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
## 二进制日志过期清理时间。默认值为0,表示不自动清理
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断
## 如:1062错误是指一些主键重复,1032是因为主从数据库数据不一致
slave_skip_errors=1062
## relay_log配置中继日志
relay_log=mall-mysql-relay-bin
## log_slave_updates表示slave将复制事件写进自己的二进制日志
log_slave_updates=1
## slave设置只读(具有super权限的用户除外)
read_only=1

重启容器

cpp 复制代码
docker restart mysql-slave

在主数据库中查看主从同步状态

cpp 复制代码
show master status;

进入mysql-slave容器

cpp 复制代码
docker exec -it mysql-slave /bin/bash
mysql -uroot -proot

在从数据库中配置主从复制

cpp 复制代码
change master to master_host='宿主机ip', master_user='slave', master_password='123456', 
master_port=3307, master_log_file='mall-mysql-bin.000001', master_log_pos=617, master_connect_retry=30;
  • master_host:主数据库的IP地址;
  • master_port:主数据库的运行端口;
  • master_user:在主数据库创建的用于同步数据的用户账号;
  • master_password:在主数据库创建的用于同步数据的用户密码;
  • master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取File参数;
  • master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取Position参数;
  • master_connect_retry:连接失败重试的时间间隔,单位为秒。

在从数据库中查看主从同步状态

cpp 复制代码
show slave status \G;

在从数据库中开启主从同步

cpp 复制代码
start slave;

查看从数据库状态发现已经同步

主从复制测试

  1. 主机新建库-使用库-新建表-插入数据,ok
  2. 从机使用库-查看记录,ok

三、Redis集群搭建

面试题

1~2亿条数据需要缓存,请问如何设计这个存储案例?

回答:单机单台100%不可能,肯定是分布式存储,用redis如何落地?

上述问题阿里P6~P7工程案例和场景设计类必考题目, 一般业界有3种解决方案

  1. 哈希取余分区
  2. 一致性哈希算法分区
  3. 哈希槽分区

这三个分区的原理及其优缺点详见Redis集群https://blog.csdn.net/newbie5277/article/details/150447281?spm=1001.2014.3001.5502

3主3从redis集群扩缩容配置案例架构

本文的集群搭建为三主三从,并演示它的扩容和缩容案例

关闭防火墙,打开docker

复制代码
systemctl stop firewalld
systemctl start docker

分别启动6台redis容器

复制代码
# 启动第1台节点
# --net host 使用宿主机的IP和端口,默认
# --cluster-enabled yes 开启redis集群
# --appendonly yes 开启redis持久化
# --port 6381 配置redis端口号
docker run -d --name redis-node-1 --net host --privileged=true -v /app/redis-cluster/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381

# 启动第2台节点
docker run -d --name redis-node-2 --net host --privileged=true -v /app/redis-cluster/share/redis-node-2:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382

# 启动第3台节点
docker run -d --name redis-node-3 --net host --privileged=true -v /app/redis-cluster/share/redis-node-3:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383

# 启动第4台节点
docker run -d --name redis-node-4 --net host --privileged=true -v /app/redis-cluster/share/redis-node-4:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384

# 启动第5台节点
docker run -d --name redis-node-5 --net host --privileged=true -v /app/redis-cluster/share/redis-node-5:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385

# 启动第6台节点
docker run -d --name redis-node-6 --net host --privileged=true -v /app/redis-cluster/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386

构建主从关系

随便进入一个节点,此次为节点1

复制代码
docker exec -it redis-node-1 /bin/bash

构建主从关系

复制代码
# 宿主机IP:端口
redis-cli --cluster create 192.168.xxx.xxx:6381 192.168.xxx.xxx:6382 192.168.xxx.xxx:6383 192.168.xxx.xxx:6384 192.168.xxx.xxx:6385 192.168.xxx.xxx:6386 --cluster-replicas 1

如果这里不成功,可以使用本地回环地址 127.0.0.1 来代替

查看集群状态

复制代码
//进入容器节点1(或集群中其他节点)
docker exec -it redis-node-1 /bin/bash
//使用redis-cli连接到6381节点:
redis-cli -p 6381
//使用redis的相关命令查看集群状态: 
cluster info

其中分配的哈希槽数量 cluster_slots_assigned为16384,集群节点数量cluster_known_nodes为6

查看集群节点信息

到这里我们的三主三从的Redis架构就配置完成了。

Redis集群读写出错

接下来进入容器节点1 并使用使用客户端连接

复制代码
docker exec -it redis-node-1 /bin/bash
redis-cli -p 6381

接下来我们尝试向redis中添加键值对,如下

发现有时候插入成功,有时候报错,这是什么原因呢?

k1经过计算得到的哈希槽为12706,但是当前连接的redis-server为6381(即节点1),它的哈希槽为:[0,5460](在创建构建主从关系时redis有提示,也可以通过 cluster nodes查看),所以会因为存不进去而报错。

执行 set k2 v2可以成功,因为k2计算出的哈希槽在[0-5460]区间中。

这时候我们只需要在连接客户端的时候带上选项 -c,插入的时候,它会自动路由到对应哈希槽

集群信息检查

cpp 复制代码
docker exec -it redis-node-1 /bin/bash
# 输入任意一台主节点地址都可以进行集群检查
redis-cli --cluster check 192.168.xxx.xxx:6381

主从扩容

假如因为业务量激增,需要向当前3主3从的集群中再加入1主1从两个节点。

启动两台新的容器节点

进入6387(节点7)容器内部

cpp 复制代码
docker exec -it redis-node-7 /bin/bash

将6387作为master加入集群

检查当前集群状态

可以发现,6371节点已经作为master加入了集群,但是该节点没有被分配槽位。

重新分配

完成后,可以进行集群信息检查,查看分配结果:

redis经过槽位检查后,会提示需要分配的槽位数量:

例如,我们现在是4台master,我们想要给node7分配4096个槽位,这样每个节点都是4096个槽位。

输入4096后,会让输入要接收这些哈希槽的节点ID,填入node7的节点ID即可。(就是节点信息中很长的一串十六进制串)。

然后会提示,询问要从哪些节点中拨出一部分槽位凑足4096个分给Node7。一般选择 all,即将之前的3个主节点的槽位都均一些给Node7,这样可以使得每个节点的槽位数相等均衡。

输入all之后,redis会列出一个计划,内容是自动从前面的3台master中拨出一部分槽位分给Node7的槽位,需要确认一下分配的计划。

输入yes确认后,redis便会自动重新洗牌,给Node7分配槽位。

可以发现重新洗牌后的槽位分配为:

因为可能有些槽位中已经存储了key,完全的重新洗牌重新分配的成本过高,所以redis选择从前3个节点中匀出来一部分给节点7

分配从节点

为主节点6387分配从节点6388:redis便会向6388发送消息,使其加入集群并成为6387的从节点。

cpp 复制代码
redis-cli --cluster add-node 192.168.xxx.xxx:6388 192.168.xxx.xxx:6387 --cluster-slave --cluster-master-id node7节点的十六进制编号字符串

检查集群当前状态

主从缩容

假如业务高峰期过去,需要将4主4从重新缩容到3主3从。即从集群中移除node8和node7.

首先删除从节点6388

cpp 复制代码
//进入容器节点1 
docker exec -it redis-node-1 /bin/bash
// 检查容器状态,获取6388的节点编号 
redis-cli --cluster check 192.168.xxx.xxx:6381
// 将6388从集群中移除 
redis-cli --cluster del-node 192.168.xxx.xxx:6388 6388节点编号

对6387哈希槽分走

如果我们想直接把node7的4096个哈希槽全部分给某个节点,可以直接输入4096。

输入4096后,会让输入要接收这些哈希槽的节点ID。假如我们想把这4096个槽都分给Node1,直接输入node1节点的编号即可。

然后会提示,询问要从哪些节点中拨出一部分槽位凑足4096个分给Node1。这里我们输入node7的节点编号,回车后输入done。

删除节点6387

查看集群情况

可以看到6387和6388已经没有了,集群又恢复到了三主三从。


感谢阅读!