文章目录
Redis主从、集群
学习一下Redis主从备份和集群的一些概念,动手搭建一个有主从备份的集群。
安装
简单说明一下安装方式,分为tar包安装和docker安装两种。
tar包安装
wget http://download.redis.io/releases/redis-6.0.5.tar.gz
tar xzf redis-6.0.5.tar.gz
cd redis-6.0.5
make
启动
src/redis-server
访问
src/redis-cli
docker 安装
首先我们下载redis镜像:
docker search redis:4.0
docker pull redis:4.0
创建docker容器的本地挂载文件夹,所有数据保存在该文件夹下:
mkdir ~/文档/_04dockervolume/redis/{conf,data} -p
获取 redis 的默认配置模版并进行配置的修改,主要是redis 的 log
、password
、appendonly
:
cd ~/文档/_04dockervolume/redis
wget https://raw.githubusercontent.com/antirez/redis/4.0/redis.conf -O conf/redis.conf
# 修改 config 文件中的以下内容
appendonly yes
dbfilename dump.rdb
appendfilename "appendonly.aof"
logfile "access.log"
requirepass 123456
创建并运行一个名为 myredis 的容器:
cd ~/文档/_04dockervolume/redis
docker run \
-v $PWD/data:/data:rw \
-v $PWD/conf/redis.conf:/etc/redis/redis.conf:rw \
--privileged=true \
--name myredis \
-d redis:4.0 redis-server /etc/redis/redis.conf
访问容器:
docker exec -it myredis redis-cli -a 123456
- 或者进入redis后,直接
auth ${password}
配置管理
# 获取全部config键值
config get *
# 获取某个config键
config get loglevel
# 设置某个config键l
config set loglevel debug
主从实践
Redis虽然具有持久化功能,但是硬盘坏了就没办法了。所以需要主从备份。其中一个磁盘坏了,还有其他机器可用。
主从机制:一主可以多从。从机连接主机后,申请同步,主机先发送rdb,再发送这段实践缓存的命令。
本例设置主从两个redis实例,主机负责写入,从机读取。
起两个容器
- name为:redis-master、redis-slave
- 日志分别为:access_master.log、access_slave.log
- 备份文件分别为:dump_master.rdb、dump_slave.rdb
redis_master
- conf,修改以下内容
#save 900 1
#save 300 10
#save 60 10000
# 可写
appendonly no
appendfilename "appendonly_master.aof"
dbfilename dump_master.rdb
requirepass 123456
#bind 127.0.0.1
protected-mode no
-启动脚本
cd ~/文档/_04dockervolume/redis
docker run \
-p 6380:6379 \
-v $PWD/data:/data:rw \
-v $PWD/conf/redis_master.conf:/etc/redis/redis.conf:ro \
--privileged=true \
--name redis_master \
-d redis redis-server /etc/redis/redis.conf
redis_slave
- conf,修改以下内容
# 备份,n秒内m个key变化,则全局备份
save 900 1
save 300 10
save 60 10000
# 只读
appendonly yes
dbfilename dump_slave.rdb
requirepass 123456
#bind 127.0.0.1
protected-mode no
# 主机信息
slaveof redis_master 6379
masterauth 123456
-启动
cd ~/文档/_04dockervolume/redis
docker run \
-p 6381:6379 \
-v $PWD/data:/data:rw \
-v $PWD/conf/redis_slave.conf:/etc/redis/redis.conf:ro \
--link redis_master:redis_master \
--privileged=true \
--name redis_slave \
-d redis redis-server /etc/redis/redis.conf
主从验证
进入master容器:docker exec -it redis_master redis-cli -a 123456
# 查看全部信息
info
# 查看replication信息,看到connected slave=1
info replication
# 设置一个键
set name master
进入slave容器:docker exec -it redis_slave redis-cli -a 123456
info replication
# 返回master,说明备份起作用了
get name
# 提示 You can't write against a read only replica
set name2 slave
集群分区sharding
单个Redis实例,内存上限可以通过config set maxmemory
改变,但是内存过大会导致持久化速度变慢,并且单台物理机的内存总是有限的。所以我们需要的是多个适当大小Redis实例组成的集群,能将不同的数据,分派到不同的Redis实例上。
Redis集群数据的分配算法,现在都是哈希槽,而以前用的哈希一致性,也可以了解一下原理。
哈希一致性
以前很流行的一种算法,决定某个key分派到哪个Redis实例。大致意思是实现一个算法
- 可以将 Hash(key) 的值保持在 0 ~ 2^32-1内。
- 将每个node的一些属性(比如IP、hostname)拿出来,算出一个Hash(node),也在0 ~ 2^32-1内。
- 计算一个key对应的node:首先,Hash(node)>Hash(key);其次,Hash(node)最小的那个node;再次,若Hash(key)大于所有Hash(node),就取Hash(node)最小的。
上图中,起点坐标0、终点坐标2^32-1、Redis节点(node1、node2、node3)、key值(k1…k10)
node1上key值:k6 k7 k8 k9 k10 k1
node2上key值:k2 k3
node3上key值:k4 k5
哈希一致性的缺点是,每个node负责的区域大小不均匀,或者区域内密度不均匀,导致最终的负载不平衡。
这时就衍生出虚拟节点
的方式,即每一个节点node,会生成多个Hash(node),称为virtualnode
,存在于哈希一致性的环上,通过虚拟节点的庞大的数量,使得每个节点上的key数量趋于平均。
哈希槽
Redis集群现在基本上都是使用hash slot
即哈希槽。
一个Redis集群有16384个哈希槽,会分配到集群的master实例上。不同的key,根据CRC16算法,得到一个值,取模16384后,找到对应的slot。换句话说:key对应slot,slot对应master实例。
hash slot
和哈希一致性中的virtual node
的相同点在于:添加删除master节点,都会导致一部分hash slot
的迁移;区别是:哈希一致性的virtual node
数量变化了,导致key寻址不再是之前的virtual node
,而hash slot
的key和slot是严格绑定的,需要迁移的key更容易计算。
常见命令
help @cluster
实际操作
- 本地创建六个配置文件,在默认的redis.conf内容下,添加以下内容,注意每个文件都要替换序号。
cd ~/文档/_04dockervolume/redis/conf
cat <<EOF >> redis_1.conf
cluster-enabled yes
cluster-config-file "node_1.conf"
dbfilename dump_1.rdb
logfile "access_1.log"
appendfilename "appendonly_1.aof"
appendonly no
EOF
- 创建redis实例,这里使用docker模式,如果你在物理机上起6个实例也差不多多少
cd ~/文档/_04dockervolume/redis
# 子网
docker network create -d bridge --subnet 172.18.0.0/24 --gateway 172.18.0.1 my_net
# 这里简单处理,不再映射物理磁盘,容器关闭后,数据丢失
awk 'BEGIN{for(i=1; i<=6; i++) print "docker run -d -v $PWD/data:/data:rw -v $PWD/conf/redis_"i".conf:/etc/redis/redis.conf:ro --network my_net --name redis_"i" --privileged=true redis:4.0 redis-server /etc/redis/redis.conf"}'|bash
# 如果上一步有什么问题,通过下面的命令,清除容器
awk 'BEGIN{for(i=1; i<=6; i++) print "docker stop redis_"i" && docker rm redis_"i}'|bash
# 进入某个redis实例
docker exec -it redis_1 redis-cli -h redis_1 -a 123456
- 使用
Cluster
命令,连接六个实例,建立集群。
# 查看各个实例地址,172.18.0.2--7
docker inspect redis_1|grep IPAddress
# 以下为redis命令
# 可以看到当前实例所连接的节点
cluster nodes
# 和其他redis实例握手连接,3-7连一遍即可,其他节点会自己互连
cluster meet 172.18.0.3 6379
# 全部握手后,可以看到能互连的节点有6个了。
cluster nodes
# 查看集群状态
cluster info
- 由上图可知,slot尚未分配,cluster状态是failed,同时所有节点都是master。
- 所以我们需要:主从备份、分配slot
- 以下是设置主从实例
# 查看节点信息
cluster nodes
# 将redis456实例作为从节点,redis234作为主节点
cluster replicate 2915edfe805d6d28e5e9812aca23a10a7e296d1a
# 查看节点信息,需要一点时间同步其他节点的信息,最后能看到3个master 3个slave
cluster nodes
配的图是redis2作为从节点的,就不重新截图了。
- 分配
hash slot
,在三台redis实例
# 这个redis指令在我的4.0版本无法运行,欢迎留言告知原因
cluster addslots {
0..5461}
# 改用shell做一下
echo "docker exec redis_1 redis-cli -h redis_1 -a 123456 cluster addslots "$(awk 'BEGIN{
for(i=0; i<=5461; i++) print i}') | bash
echo "docker exec redis_2 redis-cli -h redis_2 -a 123456 cluster addslots "$(awk 'BEGIN{
for(i=5462; i<=10922; i++) print i}') | bash
echo "docker exec redis_3 redis-cli -h redis_3 -a 123456 cluster addslots "$(awk 'BEGIN{
for(i=10923; i<=16383; i++) print i}') | bash
# 查看
cluster nodes
cluster slots
集群验证
# 计算3个key的slot,分别落在哪个节点
cluster keyslot aaaa
cluster keyslot abc
cluster keyslot ab
# 保存key,可以看到如果节点不对,不给保存
set aaaa "should be in 1"
set abc "should be in 2"
set ab "should be in 3"
# 换个正确节点,保存成功。
docker exec -it redis_1 redis-cli -h redis_2 -a 123456 set abc "should in 2"
docker exec -it redis_1 redis-cli -h redis_3 -a 123456 set ab "should in 3"
# 错误节点也无法读取
docker exec -it redis_1 redis-cli -h redis_1 -a 123456 get abc
# 但是加上 -c 参数后,保存和读取都能自动跳转
docker exec -it redis_1 redis-cli -c -h redis_1 -a 123456 get abc
docker exec -it redis_1 redis-cli -c -h redis_1 -a 123456 set ab "should in 3"
# 当然,使用 -c 参数进入redis后,所有操作都自动跳转