Docker的复杂安装,包括MySQL和Redis集群的搭建
1. Docker复杂安装
1.1. 安装MySQL主从复制
a. 主从复制原理
主要由三个线程:Master主节点binlog dump线程,Salve包括IO线程和SQL线程。
- binlog日志:当数据库启动时就会创建,保存所有对数据库修改的一个文件
- log dump线程:当binlog日志发生变化,log dump线程读取其中的内容并发送给slave节点
- slave IO线程:接受binlog内容,并且写道relay log文件中
- slave SQL线程:读取relay log文件对数据进行重放,保证主从节点的数据一致性
异步同步复制(默认):主数据库将日志发送从库,不关心从库是否已近处理完成,当主库宕机,从库升级为主库时,之前的日志就丢失了
全同步复制:主库写入binlog后强制同步日志到从库,并且从库全部执行完成后才返回给客户端
半同步复制:从库写入日志成功后返回ACK确认给主库,主库收到至少一个从库的确认就可以认为从库的写操作完成
b. 主从搭建步骤
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 \
-e MYSQL_ROOT_PASSWORD=hz1234 \
-d mysql:5.7
- 进入/data/mysql-master/conf目录下新建my.cnf:
[mysqld]
## 设置server_id, 同一局域网需要唯一
server_id=102
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能
log-bin=mall-mysql-bin
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
## 设置使用的二进制日志格式
binlog_format=mixed
## 二进制日志过期清理时间,默认值为0,表示不自动清理
expire_logs_days=7
## 跳过主从复制中的错误类型,避免slave端复制中断
slave_skip_errors=1062
## 设置字符集
collation_server=utf8_general_ci
character_set_server=utf8
[client]
default_character_set=utf8
- 修改完配置后重启master实例:docker restart mysql-master
- 进入mysql-master实例:docker exec -it mysql-master /bin/bash
- master容器实例内创建数据同步用户:
create user 'slave'@'%' identified by 'hz1234'; grant replication slave, replication client on *.* TO 'slave'@'%' ; - 新建从服务器容器实例3308:
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 \
-e MYSQL_ROOT_PASSWORD=hz1234 \
-d mysql:5.7
- 进入/data/mysql-slave/conf目录下新建my.conf:
[mysqld]
## 设置server_id, 同一局域网需要唯一
server_id=102
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能
log-bin=mall-mysql-bin
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
## 设置使用的二进制日志格式
binlog_format=mixed
## 二进制日志过期清理时间,默认值为0,表示不自动清理
expire_logs_days=7
## 跳过主从复制中的错误类型,避免slave端复制中断
slave_skip_errors=1062
## 以下为从机中的增加的配置 config start
## 配置中继日志
relay_log=mall-mysql-relay-bin
## slave将复制事件写进自己的二进制日志
log_slave_updates=1
## slave设置为只读
read_only=1
## config end
## 设置字符集
collation_server=utf8_general_ci
character_set_server=utf8
[client]
default_character_set=utf8
change master to master_host='主机名',master_user='slave',master_password='密码',master_port=3307,master_log_file='mall-mysql-bin.000001',master_log_pos=617,master_connect_retry=30;
- 在从数据库中查看主从同步状态:
show slave status \G; - 在从数据库中开启主从同步:
start slave; - 再次查看从数据库状态发现已经同步:
show slave status \G; - 主从复制测试:
- 主机新建库-使用库-新建表-插入数据
- 从机使用库-查看表数据
1.2. 安装Redis集群
a. 哈希槽分区进行亿级数据存储,如何设计这个存储案例?
需要使用分布式存储,Redis如何实现?三种解决方案:
哈希取余分区
2亿条数据就是2亿个K,V,假设3台机器构成一个集群,用户每次读写操作都是根据公式:hash(key) % N 个机器数,计算出hash值决定数据映射到哪一个节点上
优点:可以让固定的一部分请求落到同一台服务器上,每台服务器可以固定处理一部分请求,并且维护这部分请求的信息,达到负载均衡+分而治之的作用 缺点:当集群中的某台机器宕机或者出现故障,或者扩容之后,原来的取模公式会发生变化,获取的服务器也将变得不可控,会导致hash取余全部数据重新洗牌
一致性哈希算法分区
为了解决分布式缓存数据变动和映射问题,当服务器个数发生变动时,尽量减少影响客户端到服务器的映射关系
步骤:
- 算法构建一致性hash环:不再是对机器个数取模,而是对2^32取模,将整个hash值空间组织成一个虚拟的圆环,因此[0, 2^32-1]个点组成一个圆环
- 服务器IP节点映射:将集群中的每个IP节点映射到环上的某一个位置,可以选择服务器的IP或者主机名作为关键字进行hash,每台机器就能确定在hash环上的位置,关键是hash函数的实现
- key落到服务器的规则:当需要存储一个K-V键值对,首先计算K的hash值,计算出键值对在hash环上的位置,从此位置开始沿着环顺时针旋转,遇到的第一台服务器就是该k-v键值对存储的服务器,将该键值对进行存储
优点:容错性(对于某台服务器宕机)和扩展性(扩容),加入和删除节点只能影响hash环中顺时针方向的相邻的节点,对其他节点无影响 缺点:数据倾斜问题,当服务器节点太少时,容器造成节点分布不均而造成的数据倾斜问题,也就是需要缓存的数据大部分都存储在某一台服务器上,做不到负载均衡。数据的分布和节点的位置有关,由于这些节点不是均匀分布在hash环上的,所以数据在进行存储时达不到均匀分布
哈希槽分区
- 目的:实质就是一个数组,数组[0, 2^14-1]形成hash slot空间(0-16384)
- 解决均匀分布的问题,在数据和节点之间加上一层,称之为hash slot,用于管理节点和数据之间的关系,相当于节点上放的是插槽slot,slot上存放的是数据。slot解决的是粒度问题,相当于粒度变大了,便于数据移动。解决的是映射问题,使用key的hash值计算所在的slot,便于数据分配
- 一个Redis集群默认有16384个slot(2^14-1),编号从0-16383。会分配给集群中的所有主节点,集群会记录节点和slot的对应关系,只需要对key求hash值,再对16383取余,得到的余数即为该数据需要存储的slot编号,slot=CRC16(key)%16384,由于slot的数目是固定的,数据移动问题就很好解决了。
b. 搭建3主3从的redis集群(Docker配置案例)
-
关闭防火墙,启动Docker后台服务 -
新建6个redis容器实例:
docker run -d --name redis-node-1 --net host --privileged=true -v /mydata/redis-cluster/redis-node-1:/data-container redis:6.2.6 --cluster-enabled yes --appendonly yes --port 6381 docker run -d --name redis-node-2 --net host --privileged=true -v /mydata/redis-cluster/redis-node-2:/data-container redis:6.2.6 --cluster-enabled yes --appendonly yes --port 6382 docker run -d --name redis-node-3 --net host --privileged=true -v /mydata/redis-cluster/redis-node-3:/data-container redis:6.2.6 --cluster-enabled yes --appendonly yes --port 6383 docker run -d --name redis-node-4 --net host --privileged=true -v /mydata/redis-cluster/redis-node-4:/data-container redis:6.2.6 --cluster-enabled yes --appendonly yes --port 6384 docker run -d --name redis-node-5 --net host --privileged=true -v /mydata/redis-cluster/redis-node-5:/data-container redis:6.2.6 --cluster-enabled yes --appendonly yes --port 6385 docker run -d --name redis-node-6 --net host --privileged=true -v /mydata/redis-cluster/redis-node-6:/data-container redis:6.2.6 --cluster-enabled yes --appendonly yes --port 6386 - 进入docker容器后才能执行集群的搭建:
docker exec -it redis-node-1 /bin/bash 搭建redis集群 redis-cli --cluster create 192.168.45.128:6381 192.168.45.128:6382 192.168.45.128:6383 192.168.45.128:6384 192.168.45.128:6385 192.168.45.128:6386 --cluster-replicas 1 –cluster-replicas 1(为每个主机配置一个从机) -
进入容器redis-node-1并为6台机器构建集群关系 -
链接到6381作为切入点,查看集群状态:cluster info 和cluster nodes
使用redis-cli -p 6381 进入的是单机环境下的redis客户端 使用redis-cli -p 6381 -c 进入集群环境下的redis客户端,可以重定向到其他的hash slot中(6181 -> 6383), 防止路由失效 查看集群信息 redis-cli --cluster check ip:port
c. 主从容错切换迁移
将主机6381停止,master将会从6381和6382之中来回进行切换,从机6382升级为主机。但是集群状态依旧是正常的,可以运行,之前的值依旧可以获取到 此时6381重新上线,那么6381此时是从机状态
d. 主从扩容案例
新增6387和6388两个节点加入到集群中,6387为主机,6388为从机
- 新增的6387节点作为master节点加入原集群(此时没有slot分配),检查此时集群情况
redis-cli --cluster add-node 192.168.45.128:6387 192.168.45.128:6381
- 重新分派插槽,再次检查集群状况
刚开始加入到集群中,并没有分配slot给6387,使用命令进行分配slot给6387 redis-cli --cluster reshard 192.168.45.128:6381
- 第三次检查集群状况
为主节点6387分配从节点6388 redis-cli --cluster add-node 192.168.45.128:6388 192.168.45.128:6387 --cluster-slave --cluster-master-id 6387容器编号 最后检查集群情况:4主4从的Redis集群
e. 主从缩容案例
删除6387和6388,恢复3主3从
-
首先清除从节点6388 redis-cli --cluster del-node 192.168.45.128:6388 6388节点的容器id -
清理出来的插槽重新分配,将6387节点中的插槽全部分配给6385号机 -
然后删除主节点6387 redis-cli --cluster del-node 192.168.45.128:6387 6387节点的容器id -
恢复成3主3从,查看集群状况
|