前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis系列之Redis集群搭建与讲解

Redis系列之Redis集群搭建与讲解

原创
作者头像
天下之猴
发布2024-09-20 20:20:24
1520
发布2024-09-20 20:20:24
举报
文章被收录于专栏:Redis从入门到精通

Redis中的消息队列

PubSub发布订阅模式

消费者可以订阅有一个或多个channel,消费者为阻塞式等待

  • SUBSCRIBE channel[channel]:订阅一个或多个频道
  • PUBLISH channelmsg:向一个频道发送消息
  • PSUBSCRIBE pattern[pattern]:订阅与pattern格式匹配的所有频道,用通配符表示

优点:

  • 采用发布订阅模型,支持多生产,多消费

缺点

  • 不支持数据持久化
  • 无法避免消息丢失
  • 消息堆积有上限,超出时数据丢

Reids集群

单节点的缺点集群如何解决

  • 数据丢失问题:内存存储,服务重启可能会丢失数据
    • 解决方案:实现Redis数据的持久化,数据存入磁盘
  • 并发能力问题: 即使是内存存储也会在面对更高的并发量时满足不了
    • 搭建主从集群,实现读写分离
  • 故障恢复问题:Redis宕机,则服务就不可以用了
    • 利用Redis哨兵,实现健康检测和自动恢复
  • 存储能力问题:单节点的存储能力满足不了海量的数据需求
    • 搭建分片集群,利用插槽机制实现动态扩容,理论上可以无限扩容

Redis持久化

两者都开启时,AOF优先级高于RDB

RDB-Redis数据备份快照

机制概述

将内存中的所有数据记录到磁盘中,当Redis实例故障重启后,从磁盘中读取快照文件,恢复数据,Redis在停机时会自动执行一次RDB,宕机不会执行RDB

使用
两种存储方式

SAVE:由主进程执行,将数据写进磁盘,由于redis是单线程的,写入磁盘较慢,因此这种方式较少使用,多用于Rdis停机时使用

BGSAVE:开启一个子线程,由子线程执行将数据写入磁盘的操作

相关配置

redis.conf文件中设置

代码语言:javascript
复制
#900秒内,如果至少有1个key被修改,则执行bgsave,如果是save""则表示禁用RDB
save 900 1
save 300 10
save 60 10000

#是否压缩,建议不开启,压缩也会消耗cpu,磁盘的存储不值钱,不建议开
rdbcompression yes

#RDB文件名称
dbfilename dump.rdb

#文件保存的路径目录
dir ./
缺点

即使设置了自动存储,但是如果在自动存储的时间间隔内服务器宕机了,数据会丢失

AOF-追加文件

机制概述

将Redis的所有操作命令记录在AOF文件之中,类似于命令日志

使用
相关配置

redis.conf文件中配置

代码语言:javascript
复制
#是否开启AOF功能,默认是no
appendonly yes
#AOF文件的名称
appendfilename "appendonly.aof"
#表示每执行一次写命令,立即记录到AOF文件
appendfsync always
#写命令执行完先放入AOF缓冲区,然后表示每隔1秒将缓冲区数据写到AOF文件,是默认方案
appendfsync everysec
#写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
appendfsync no
缺点及解决方案

由于AOF记录的是命令而RDB记录的是最后的值,会导致AOF文件体积过大,因此可以使用BGREWRITEAOF命令来重写,该命令会将操作语句简化,只操作最后一次的语句,用最少命令达到相同效果,重写是异步执行的

通过直接在控制台输入BGREWRITEAOF即可重写AOF文件

可在redis.conf中配置自动重写AOF文件

代码语言:javascript
复制
#AOF文件比上次文件增长超过多少百分比则触发重写
auto-aof-rewrite-percentage 100
#AOF文件体积最小多大以上才触发重写
auto-aof-rewrite-min-size 64mb

通过docker搭建Redis主从

Redis写少读多,因此主写从读,

默认端口搭建

注意:需要开启RDB持久化,AOF不行,因为在从节点连接上主节点时,主节点会把自己的RDB文件给从节点

  1. 创建三个容器
  1. 进入到两个从节点内部,设置主节点
  1. 查看容器状态

指定端口搭建

  1. 在宿主机中创建配置文件内容如下
代码语言:javascript
复制
prot 端口号
slaveof 主节点ip和端口
  1. 通过下面这段命令创捷从节点,启动以上一步创建的配置文件启动
代码语言:javascript
复制
docker run -itd --name redis-slave2 -v /usr/server/redisServer/redisSlave2.conf:/redisConfig/redisSlave2.conf -p 7003:7003 redis:latest redis-server /redisConfig/redisSlave2.conf
  1. docker exec -it 容器名 /bin/bash进入从节点内部
  2. redis-cli -p 从节点端口启动服务即可

数据同步

全量同步

主节如何判断从节点是否是第一次来同步数据:

  • 每个主节点都有一个唯一的Replication Id,字节点会继承主节点的id,如果子节点id和master的id不同则是第一次同步
  • offset:表示同步进度,offset会随着repl_baklog缓冲区中数据增多而增大,从节点会同步主节点的offset,如果从节点的offset小于master的offset,则表示数据落后,需要更新
增量同步

repl_baklog数据结构是一个循环数组,只要两者的数据差距小于数组大小,不会覆盖之前数据,都可进行同步,如果覆盖了只能去做全量同步保持数据一致性了

优化要点

哨兵(Sentinel)机制

当主节点宕机时,选择从节点作为主节点,哨兵机制用于监测节点是否出故障

作用
  • 监控:监控每一个节点是否按预期工作
  • 自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主
  • 通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端,在java中,redistemplate访问的不再是redis集群的地址,而是Sentinel集群的地址,有哨兵告诉redistemplate谁是主节点,谁是从节点
如何判断出现故障

基于心跳机制,每隔一秒哨兵集群中的每个哨兵向需要检测的redis集群ping一下(哨兵之间也会相互检测),如果一个哨兵没有得到响应则认为该节点出现故障被称为主观下线(因为不排除网络问题),如果有多半的哨兵ping不通同一个节点则认为该节点出现了故障,称之为客观下线

选取新的master的依据
  • 首先会判断slave节点与master节点断开时间长短,如果超过指定值(down-after-milliseconds*10)则会排除该slave节点
  • 然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举
  • 如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高
  • 最后是判断slave节点的运行id大小(该id在从节点连接上主节点后由redis自动生成),越小优先级越高。
如何创建新的master
  • sentinel给备选的slave1节点发送slaveof no one命令,让该节点成为master
  • sentinel给所有其它slave发送slave of 新master地址和端口的命令,让这些slave成为新master的从节点,开始从新的master上同步数据。
  • 最后,sentinel将故障节点标记为slave(修改器配置文件,也加上面那段命令),当故障节点恢复后会自动成为新的master的slave节点
搭建
  1. 创建哨兵的配置文件
代码语言:javascript
复制
port 16379//哨兵节点的端口
sentinel monitor master 172.17.0.4 6379 2//这里的2表示有几个哨兵节点
logfile "sentinel1.log"
  1. 修改该目录下的文件权限,应为哨兵会输出日志
代码语言:javascript
复制
chmod -R 777 /usr/server/redisServer
  1. 创建哨兵节点
代码语言:javascript
复制
docker run -itd --name redis-sentinel1 -v /usr/server/redisServer:/redisConfig:z -p 16379:16379 redis:latest redis-server /redisConfig/sentinel1.conf --sentinel
/*
*:z:防止linux中的selinux安全机制阻止哨兵模式的启动,如果该机制关闭可以不加
*这里的启动将文件目录映射,两者文件的改动会互相影响
*--sentinel:表示以哨兵模式启动该节点,妈的吃亏提取文字把l弄成1搞了半天(╯▔皿▔)╯
*/
  1. 查看监测节点的状态info sentinel

Cluster集群/分片集群

概念

基于P2P去中心化架构,采用了槽(Slot)的机制,可以简单理解为n个主从架构组合在一起对外服务。Redis Cluster要求至少需要3个master才能组成一个集群,同时每个master至少需要有一个slave节点。

机制

底层是通过CRC16算法对键进行计算的到一个hash值再通过对16384取余得到需要存储到哪个节点,cluseter集群中的主节点之间会互相监测,当有一个主节点宕机后,他的从节点会成为主节点,该集群等于主从加哨兵

  • 存键的时候会优先计算{}中的键来获取hash值,如果没有则就根据key获取hash值,利用这一机制可以实现将键存到指定槽位,实现一台redis服务器存储一类数据的功能

搭建

  1. cluster集群最少需要六个redis服务,其中三个主节点三个从节点,写好各自的配置信息
代码语言:javascript
复制
port 6379
dir /redisConfig
logfile cluster-m1.log //指定日志名
cluster-enabled yes //开启cluster模式
cluster-config-file nodes-6379.conf //指定生成文件名,该文件会自动生成

port 6380
dir /redisConfig
logfile cluster-m2.log
cluster-enabled yes
cluster-config-file nodes-6380.conf


port 6381
dir /redisConfig
logfile cluster-m3.log
cluster-enabled yes
cluster-config-file nodes-6381.conf

port 16379
dir /redisConfig
logfile cluster-s1.log
cluster-enabled yes
cluster-config-file nodes-16379.conf

port 16380
dir /redisConfig
logfile cluster-s2.log
cluster-enabled yes
cluster-config-file nodes-16380.conf


port 16381
dir /redisConfig
logfile cluster-s3.log
cluster-enabled yes
cluster-config-file nodes-16381.conf
  1. 之后再创建容器
代码语言:javascript
复制
docker run -itd --name redis-m1 -v /usr/server/redisServer:/redisConfig:z -p 6379:6379 redis:latest redis-server /redisConfig/cluster-m1.conf
docker run -itd --name redis-m2 -v /usr/server/redisServer:/redisConfig:z -p 6380:6380 redis:latest redis-server /redisConfig/cluster-m2.conf
docker run -itd --name redis-m3 -v /usr/server/redisServer:/redisConfig:z -p 6381:6381 redis:latest redis-server /redisConfig/cluster-m3.conf
docker run -itd --name redis-s1 -v /usr/server/redisServer:/redisConfig:z -p 16379:16379 redis:latest redis-server /redisConfig/cluster-s1.conf
docker run -itd --name redis-s2 -v /usr/server/redisServer:/redisConfig:z -p 16380:16380 redis:latest redis-server /redisConfig/cluster-s2.conf
docker run -itd --name redis-s3 -v /usr/server/redisServer:/redisConfig:z -p 16381:16381 redis:latest redis-server /redisConfig/cluster-s3.conf
  1. 确定好各自节点的ip地址
  1. 通过cluster info 命令查看节点信息
  1. 进入到主节点中,将其他的各个节点加入到cluster集群中
代码语言:javascript
复制
redis-cli -p 6379 cluster meet 172.17.0.6 6380
redis-cli -p 6379 cluster meet 172.17.0.5 6381
redis-cli -p 6379 cluster meet 172.17.0.4 16379
redis-cli -p 6379 cluster meet 172.17.0.3 16380
redis-cli -p 6379 cluster meet 172.17.0.2 16381
#这里的6379是因为进入到的这个主节点的redis服务端口为6379,这里的命令是将其他的节点与这个节点相连
  1. 编写sh脚本,将16384个槽位平均分给每个主节点
代码语言:javascript
复制
#!/bin/bash  
for i in $(seq 0 5460)  ##给主节点分配的槽位下标
do
/usr/local/bin/redis-cli -h 172.17.0.7 -p 6379 cluster addslots $i ##主节点的ip和端口
done
  1. 在容器内输入bash /redisConfig/setHashSlots.sh命令,执行脚本,有多少个主节点,执行多少次,只要在cluster节点的容器中执行就行
  2. 给主节点分配好槽位之后,接下来就分配从节点了,分配时需要从节点的node_id,输入cluster nodes命令查看cluster集群中所有的节点cluster的id
  1. 之后再进入每个从节点的容器内启动redis服务后通过cluster replicate 主节点的node_id命令指定主节点
  2. 指定完之后,由于cluster是根据键来计算数据写入到哪个槽中去的,因此在一个主节点中写入不属于该主节点的数据会提示应该写入那个节点,为了解决这种情况,重启主节点时加上-c参数让其自动转移到应该写入的主节点即可

扩容

  1. 写好新的主节点和从节点的配置信息
  2. 通过docker run创建启动容器
  3. 查看该主节点和从节点的ip地址
  4. 通过meet命令,将这两个节点加入cluter集群中
  5. 查看cluster集群中新增的两个节点的node_id
  6. 进入到新的从节点中通过cluster replicate 新主节点设置其为主节点
  7. 再次重新分配哈希槽,进入到主节点的容器中通过以下命令
代码语言:javascript
复制
redis-cli --cluster reshard 172.17.0.2:6379 --cluster-from 主节点1,主节点2,主节点3 --cluster-to 新的主节点--cluster-slots 1024

#从主节点1、2、3中每个给新主节点分配1024个哈希槽
#172.17.0.2:6379表示由这个主节点分配,这里随便写一个主节点的IP都可以

手动宕机

通过cluster failover命令手动让cluser集群中的某哥master宕机,其子节点会成为新的master,当服务器需要维护时可以这样做,宕机过程中写操作将阻塞

集群配置

  • Cluster集群中,当有一个插槽出现问题时会导致整个集群不可用,只需要在redis.cnf中修改成cluster-require-full-coverage false即可,但仍保证不了数据完整性,只能保证可用性
  • 心跳机制设置cluster-node-timeout来及时监测节点

进阶应用场景

亿级访问下的处理策略

多级缓存

  • 传统的redis服务是在tomcat中的,tomacat的读写速度不是很快,成为高流量访问下的短板,因此通过nginx来从redis读取数据
  • 两台nginx虽然多用于反向代理,也可以用作缓存,nginx服务器可以通过lua脚本来读取redis中的数据
  • tomcat可以通过jvm进程缓存来存数据,进一步防止缓存穿透
  • 要注意数据库和各级缓存之间的同步

Redis使用技巧与规范

  • 键值命名时采用,业务名:数据名:id的格式,业务就是这是是实现什么功能的,数据名就是这个id时来源于代码中的哪个实体,id就是实体对应的id
  • string类型的长度最好不超过44位(因为底层编码会影响内存存储空间,44位以下采用embstr编码方式,这种方式同长度数据下比int,raw更省空间),通过object encoding 键名 查看编码方式
  • 一个key中储存的数据不宜过多过大,不然可能会导致网络阻塞,导致redis集群数据倾斜,redis进程阻塞,cpu压力加大,但一个键中有多个数据需要存储时,可以通过分组存储的方式
  • 能用批量操作就尽量用批量操作,极大的省去了网络传输时间,string类型用mset,hash类型用hmset,如果有其他类型有多条数据需要进行操作的话,将命令放入Pipeline,再统一传送给Redis,spring boot中redi依赖通过multiSet()和multiGet()两个方法提供了管道的批处理,并行执行,尤其在集群的情况下,批处理的key必须落在同一个key中不然会报错,如果有海量数据的话先根据key分组再进行批处理
  • 持久化
  • redis安全问题https://www.bilibili.com/video/BV1cr4y1671t?p=142&spm_id_from=pageDriver&vd_source=568045caf8e6c5a69368ef315c54c0bd
  • 集群中要避免多节点,可以多集群,节点越多,监测时数据越多,会阻塞网络

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Redis中的消息队列
    • PubSub发布订阅模式
    • Reids集群
      • 单节点的缺点集群如何解决
        • Redis持久化
          • RDB-Redis数据备份快照
          • AOF-追加文件
        • 通过docker搭建Redis主从
          • 默认端口搭建
          • 指定端口搭建
          • 数据同步
        • 哨兵(Sentinel)机制
          • Cluster集群/分片集群
            • 概念
            • 机制
            • 搭建
            • 扩容
            • 手动宕机
            • 集群配置
        • 进阶应用场景
          • 亿级访问下的处理策略
            • 多级缓存
        • Redis使用技巧与规范
        相关产品与服务
        云数据库 Redis
        腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档