redis缓存

一、redis核心数据结构和使用场景

        redis核心的数据结构有5种,基本的命令和参考下面的链接,这边不进行详细说明,本节主要记录常见的使用场景

        

命令地址:Redis 命令_redis教程https://www.redis.net.cn/tutorial/3506.html

1、字符串-string

1.1 单值缓存

SET  key  value 	
GET  key

1.2 对象缓存

1) SET  user:1  value(json格式数据)
//批量操作
2) MSET  user:1:name  zhuge   user:1:balance  1888
   MGET  user:1:name   user:1:balance 

1.3 分布式锁

SETNX  product:10001  true 		//返回1代表获取锁成功
SETNX  product:10001  true 		//返回0代表获取锁失败
// 执行业务操作
DEL  product:10001			//执行完业务释放锁

SET product:10001 true  ex  10  nx	//防止程序意外终止导致死锁

1.4 计数器

INCR article:readcount:{文章id}  	
GET article:readcount:{文章id} 

1.5 分布式系统全局序列号

INCRBY  orderId  1000		//redis批量生成序列号提升性能

2、哈希-hash

2.1 对象缓存

HMSET  user  {userId}:name  zhuge  {userId}:balance  1888

// 下面是用户ID为1 名称为zz 工资为1888的用户
HMSET  user  1:name  zz  1:balance  1888

优点:

1)同类数据归类整合储存,方便数据管理

2)相比string操作消耗内存与cpu更小

3)相比string储存更节省空间

缺点

1)过期功能不能使用在field上,只能用在key上

2)Redis集群架构下不适合大规模使用

3、列表-list

3.1 常用数据结构

Stack(栈) = LPUSH + LPOP
Queue(队列)= LPUSH + RPOP
Blocking MQ(阻塞队列)= LPUSH + BRPOP

 3.2 微信公号消息流

小王关注了MacTalk,备胎说车等大V
1)MacTalk发文章,消息ID为10018
LPUSH  msg:{小王-ID}  10018
2)备胎说车发文章,消息ID为10086
LPUSH  msg:{小王-ID} 10086
3)查看小王的最新消息
LRANGE  msg:{小王ID}  0  4

4、无序集合-set

4.1 微信抽奖小程序

1)点击参与抽奖加入集合
    SADD key {userlD}
2)查看参与抽奖所有用户
    SMEMBERS key	  
3)抽取count名中奖者
    SRANDMEMBER key [count] //抽中的用户下次还会参加抽奖
    SPOP key [count] //抽中的用户不会参加下次抽奖

4.2 微信微博点赞,收藏,标签

1) 点赞
SADD  like:{消息ID}  {用户ID}
2) 取消点赞
SREM like:{消息ID}  {用户ID}
3) 检查用户是否点过赞
SISMEMBER  like:{消息ID}  {用户ID}
4) 获取点赞的用户列表
SMEMBERS like:{消息ID}
5) 获取点赞用户数 
SCARD like:{消息ID}

4.3 集合操作实现微博微信关注模型

1) 我(小王)关注的人: 
小王-> {小张, 小李,小刘}
2) 小张关注的人:
 小张--> {小王, 小刘, 小陈, 小蒋}
3) 小陈关注的人: 
小陈-> {小王, 小张, 小黄, 小刘)
4) 小王和小张共同关注: 
SINTER wang zhang --- liu
5) 我(小王)关注的人也关注他(小张):
SISMEMBER guojiaSet yangguo 
SISMEMBER xushuSet yangguo
6) 我可能认识的人: 
SDIFF wang zhang->  zhang li

4.4 集合操作实现电商商品筛选

SADD  brand:huawei  P40
SADD  brand:xiaomi  mi-10
SADD  brand:iPhone iphone12
SADD os:android  P40  mi-10
SADD cpu:brand:intel  P40  mi-10
SADD ram:8G  P40  mi-10  iphone12

SINTER  os:android  cpu:brand:intel  ram:8G  {P40,mi-10}

 5 有序集合-zset

5.1 Zset集合操作实现排行榜

1)点击新闻
ZINCRBY  hotNews:20190819  1  守护香港
2)展示当日排行前十
ZREVRANGE  hotNews:20190819  0  9  WITHSCORES 
3)七日搜索榜单计算(把7天的集合union到一个新的集合)
ZUNIONSTORE  hotNews:20190813-20190819  7 
hotNews:20190813  hotNews:20190814... hotNews:20190819
4)展示七日排行前十
ZREVRANGE hotNews:20190813-20190819  0  9  WITHSCORES

二、redis持久化

1、RDB持久化

1.1 触发机制

在默认情况下, Redis 将内存数据库快照保存在名字为 dump.rdb 的二进制文件中。

你可以对 Redis 进行设置, 让它在“ N 秒内数据集至少有 M 个改动”这一条件被满足时, 自动保存一次 数据集。
比如说, 以下设置会让 Redis 在满足“
60 秒内有至少有 1000 个键被改动”这一条件时, 自动保存一次
数据集:
# save 60 1000 // 关闭RDB只需要将所有的save保存策略注释掉即可
还可以手动执行命令 生成RDB快照 ,进入redis客户端 执行命令 save bgsave 可以生成dump.rdb文件,
每次命令执行都会将所有redis内存快照 到一个新的rdb文件里,并覆盖原有rdb快照文件

1.2、bgsave的工作流程

后台使用bgsave方式进行快照持久化

1.3、save和bgsave的比较

AOF(append-only file)

2.1 AOF出现的原因和工作机制

快照功能并不是非常耐久(durable): 如果 Redis 因为某些原因而造成故障停机, 那么服务器将丢失 最近写入、且仍未保存到快照中的那些数据。从 1.1 版本开始, Redis 增加了一种完全耐久的持久化方 式: AOF 持久化,将修改的每一条指令记录进文件appendonly.aof中(先写入os cache,每隔一段时间 fsync到磁盘

2.2、AOF开启和持久化方式

开启:

# appendonly yes

配置:

appendfsync always:每次有新命令追加到 AOF 文件时就执行一次 fsync ,非常慢,也非常安全。

2 appendfsync everysec :每秒 fsync 一次,足够快,并且在故障时只会丢失 1 秒钟的数据。(默认,也是推荐的方式)
3 appendfsync no :从不 fsync ,将数据交给操作系统来处理。更快,也更不安全的选

持久化格式:

2.3、AOF重写

重写配置

# autoaofrewriteminsize 64mb //aof文件至少要达到64M才会自动重写,文件太小恢复速度本来就

很快,重写的意义不大
2 # auto aof rewrite percentage 100 //aof 文件自上一次重写后文件大小增长了 100% 则再次触发重写

手动触发重写

bgrewriteaof

2.4 AOF持久化工作流程

2.5 AOF和RDB比较

3、Redis 4.0 混合持久化

3.1 混合持久化产生的原因和开启方式

重启 Redis 时,我们很少使用 RDB来恢复内存状态,因为会丢失大量数据。我们通常使用 AOF 日志重放,但是重放 AOF 日志性能相对 RDB来说要慢很多,这样在 Redis 实例很大的情况下,启动需要花费很长的时间。 Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化。

通过如下配置可以开启混合持久化(必须先开启aof):
# aof‐use‐rdb‐preamble yes

3.2 工作机制

持久化:

如果开启了混合持久化,AOF在重写时,不再是单纯将内存数据转换为RESP命令写入AOF文件,而是将重写这一刻之前的内存做RDB快照处理,并且将RDB快照内容和增量的AOF修改内存数据的命令存在一起,都写入新的AOF文件,新的文件一开始不叫appendonly.aof,等到重写完新的AOF文件才会进行改名,覆盖原有的AOF文件,完成新旧两个AOF文件的替换。

重放:

于是在 Redis 重启的时候,可以先加载 RDB 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,因此重启效率大幅得到提升。

手绘10张图,细谈Redis 持久化,详解RDB和AOF及混合机制

 4、Redis数据备份策略

1. 写crontab定时调度脚本,每小时都copy一份rdb或aof的备份到一个目录中去,仅仅保留最近48小时的备份

2. 每天都保留一份当日的数据备份到一个目录中去,可以保留最近1个月的备份
3. 每次copy备份的时候,都把太旧的备份给删了
4. 每天晚上将当前机器上的备份复制一份到其他机器上,以防机器损坏

三、redis高可用

1、主从复制

1.1 Redis主从工作原理

如果你为master配置了一个slave,不管这个slave是否是第一次连接上Master,它都会发送一个PSYNC命令给master请求复制数据。master收到PSYNC命令后,会在后台进行数据持久化通过bgsave生成最新的rdb快照文件,持久化期间,master会继续接收客户端的请求,它会把这些可能修改数据集的请求缓存在内存中。当持久化进行完毕以后,master会把这份rdb文件数据集发送给slave,slave会把接收到的数据进行持久化生成rdb,然后再加载到内存中。然后,master再将之前缓存在内存中的命令发送给slave。当master与slave之间的连接由于某些原因而断开时,slave能够自动重连Master,如果master收到了多个slave并发连接请求,它只会进行一次持久化,而不是一个连接一次,然后再把这一份持久化的数据发送给多个并发连接的slave

主从复制(全量复制)流程图

 1.2 数据部分复制

当master和slave断开重连后,一般都会对整份数据进行复制。但从redis2.8版本开始,redis改用可以支持部分数据复制的命令PSYNC去master同步数据,slave与master能够在网络连接断开重连后只进行部分数据复制(断点续传)。master会在其内存中创建一个复制数据用的缓存队列,缓存最近一段时间的数据,master和它所有的slave都维护了复制的数据下标offset和master的进程id,因此,当网络连接断开后,slave会请求master继续进行未完成的复制,从所记录的数据下标开始。如果master进程id变化了,或者从节点数据下标offset太旧,已经不在master的缓存队列里了,那么将会进行一次全量数据的复制。

主从复制(部分复制,断点续传)流程图:

1.3 复制风暴

如果有很多从节点,为了缓解主从复制风暴(多个从节点同时复制主节点导致主节点压力过大),可以做如下架构,让部分从节点与从节点(与主节点同步)同步数据

2、哨兵模式

        主从复制只能解决读写分离的功能,但是当master节点挂掉之后集群将无法使用,哨兵模式可以选举master实现高可用。

sentinel哨兵是特殊的redis服务,不提供读写服务,主要用来监控redis实例节点。

哨兵架构下client端第一次从哨兵找出redis的主节点,后续就直接访问redis的主节点,不会每次都通过sentinel代理访问redis的主节点,当redis的主节点发生变化,哨兵会第一时间感知到,并且将新的redis主节点通知给client端(这里面redis的client端一般都实现了订阅功能,订阅sentinel发布的节点变动消息)

2.1 哨兵模式的作用

1)通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器

2)当哨兵监测到Redis主机宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他服务器,修改配置文件,让他们换主机

2.2、哨兵集群

        当一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此可以使用哨兵进行监控, 各个哨兵之间还会进行监控,这就形成了多哨兵模式。

以上过程:假设主服务器宕机,哨兵1先检测到结果,但是系统并不会马上进行failover过程,仅仅是哨兵1主观认为主服务器不可以用,这个现象称为主观下线,当后面的哨兵也检测到主服务器不可用,并且数量达到一定时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover故障转移操作。
操作转移成功后。就会发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这一过程称为客观下线

3、redis集群

3.1 哨兵模式的缺点

        在redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态,如果master节点异常,则会做主从切换,将某一台slave作为master,哨兵的配置略微复杂,并且性能和高可用性等各方面表现一般,特别是在主从切换的瞬间存在访问瞬断的情况,而且哨兵模式只有一个主节点对外提供服务,没法支持高的并发,且单个主节点内存也不宜设置得过大,否则会导致持久化文件过大,影响数据恢复或主从同步的效率

3.2 高可用集群模式

        redis集群是一个由多个主从节点群组成的分布式服务器群,它具有复制、高可用和分片特性。Redis集群不需要sentinel哨兵∙也能完成节点移除和故障转移的功能。需要将每个节点设置成集群模式,这种集群模式没有中心节点,可水平扩展,据官方文档称可以线性扩展到上万个节点(官方推荐不超过1000个节点)。redis集群的性能和高可用性均优于之前版本的哨兵模式,且集群配置非常简单。如果节点A的master挂掉,会通过其他节点的master进行选举,从节点A的slave选取一个重新作为master

3.3 Redis集群原理分析

        Redis Cluster 将所有数据划分为 16384 个 slots(槽位),每个节点负责其中一部分槽位。槽位的信息存储于每 个节点中。当 Redis Cluster 的客户端来连接集群时,它也会得到一份集群的槽位配置信息并将其缓存在客户端本地。这样当客户端要查找某个 key 时,可以直接定位到目标节点。同时因为槽位的信息可能会存在客户端与服务器不一致的情况,还需要纠正机制来实现槽位信息的校验调整。

3.3.1 槽位定位算法

Cluster 默认会对 key 值使用 crc16 算法进行 hash 得到一个整数值,然后用这个整数值对 16384 进行取模来得到具体槽位。

HASH_SLOT = CRC16(key) mod 1638

3.3.2 重定向

当客户端向一个错误的节点发出了指令,该节点会发现指令的 key 所在的槽位并不归自己管理,这时它会向客 户端发送一个特殊的跳转指令携带目标操作的节点地址,告诉客户端去连这个节点去获取数据。客户端收到指 令后除了跳转到正确的节点上去操作,还会同步更新纠正本地的槽位映射表缓存,后续所有 key 将使用新的槽位映射表。

3.3.3 Redis集群选举原理分析

当slave发现自己的master变为FAIL状态时,便尝试进行Failover,以期成为新的master。由于挂掉的master 可能会有多个slave,从而存在多个slave竞争成为master节点的过程, 其过程如下:

1.slave发现自己的master变为FAIL
2.将自己记录的集群currentEpoch加1,并广播FAILOVER_AUTH_REQUEST 信息
3.其他节点收到该信息,只有master响应,判断请求者的合法性,并发送FAILOVER_AUTH_ACK,对每一个 epoch只发送一次ack
4.尝试failover的slave收集master返回的FAILOVER_AUTH_ACK
5.slave收到 超过半数master的ack 后变成新Master(这里解释了集群为什么至少需要三个主节点,如果只有两 个,当其中一个挂了,只剩一个主节点是不能选举成功的)
6.slave广播Pong消息通知其他集群节点。
从节点并不是在主节点一进入 FAIL 状态就马上尝试发起选举,而是有一定延迟,一定的延迟确保我们等待 FAIL状态在集群中传播,slave如果立即尝试选举,其它masters或许尚未意识到FAIL状态,可能会拒绝投票
•延迟计算公式:
        DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms
•SLAVE_RANK表示此slave已经从master复制数据的总量的rank。Rank越小代表已复制的数据越新。这种方式下,持有最新数据的slave将会首先发起选举(理论上)。

3.3.4、集群脑裂数据丢失问题

redis集群没有过半机制会有脑裂问题,网络分区导致脑裂后多个主节点对外提供写服务,一旦网络分区恢复,会将其中一个主节点变为从节点,这时会有大量数据丢失。

规避方法可以在redis配置里加上参数(这种方法不可能百分百避免数据丢失,参考集群leader选举机制):
min replicas to write 1 // 写数据成功最少同步的 slave 数量,这个数量可以模仿大于半数机制配置,比如:集群总共三个节点可以配置1 ,加上 leader 就是 2 ,超过了半数
 
注意:这个配置在一定程度上会影响集群的可用性,比如slave要是少于1个,这个集群就算leader正常也不能提供服务了,需要具体场景权衡选择

3.3.5 集群是否完整才能对外提供服务

当redis.conf的配置cluster-require-full-coverage为no时,表示当负责一个插槽的主库下线且没有相应的从库进行故障恢复时,集群仍然可用,如果为yes则集群不可用。

3.3.6 Redis集群为什么至少需要三个master节点,并且推荐节点数为奇数

因为新master的选举需要大于半数的集群master节点同意才能选举成功,如果只有两个master节点,当其中一个挂了,是达不到选举新master的条件的。

奇数个master节点可以在满足选举该条件的基础上节省一个节点,比如三个master节点和四个master节点的集群相比,大家如果都挂了一个master节点都能选举新master节点,如果都挂了两个master节点都没法选举新master节点了,所以奇数的master节点更多的是从节省机器资源角度出发 说的。

3.3.7 Redis集群对批量操作命令的支持

对于类似mset,mget这样的多个key的原生批量操作命令,redis集群只支持所有key落在同一slot的情况,如果有多个key一定要用mset命令在redis集群上操作,则可以在key的前面加上{XX},这样参数数据分片hash计算的只会是大括号里的值,这样能确保不同的key能落到同一slot里去,示例如下:

mset {user1}:1:name zhuge {user1}:1:age 18

假设name和age计算的hash slot值不一样,但是这条命令在集群下执行,redis只会用大括号里的 user1 做hash slot计算,所以算出来的slot值肯定相同,最后都能落在同一slot。

四、redis分布式锁

五、redis高并发缓存实战和性能优化

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值