`

Redis的n种妙用,不仅仅是缓存

 
阅读更多

介绍

redis是键值对的数据库,常用的五种数据类型为字符串类型(string),散列类型(hash),列表类型(list),集合类型(set),有序集合类型(zset)

 

Redis用作缓存,主要两个用途:高性能,高并发,因为内存天然支持高并发

应用场景

分布式锁(string)

 

setnx key value,当key不存在时,将 key 的值设为 value ,返回1。若给定的 key 已经存在,则setnx不做任何动作,返回0。

 

当setnx返回1时,表示获取锁,做完操作以后del key,表示释放锁,如果setnx返回0表示获取锁失败,整体思路大概就是这样,细节还是比较多的,有时间单开一篇来讲解

 

计数器(string)

 

如知乎每个问题的被浏览器次数

set key 0
incr key // incr readcount::{帖子id} 每阅读一次
get key // get readcount::{帖子id} 获取阅读量

 

分布式全局唯一id(string)

 

分布式全局唯一id的实现方式有很多,这里只介绍用redis实现

 

每次获取userId的时候,对userId加1再获取,可以改进为如下形式

 

直接获取一段userId的最大值,缓存到本地慢慢累加,快到了userId的最大值时,再去获取一段,一个用户服务宕机了,也顶多一小段userId没有用到

 

set userId 0
incr usrId //返回1
incrby userId 1000 //返回10001

 

消息队列(list)

 

在list里面一边进,一边出即可

 

# 实现方式一
# 一直往list左边放
lpush key value 
# key这个list有元素时,直接弹出,没有元素被阻塞,直到等待超时或发现可弹出元素为止,上面例子超时时间为10s
brpop key value 10 

#
 实现方式二
rpush key value
blpop key value 10

新浪/Twitter用户消息列表(list)

 

假如说小编li关注了2个微博a和b,a发了一条微博(编号为100)就执行如下命令

 

lpush msg::li 100

 

b发了一条微博(编号为200)就执行如下命令:

 

lpush msg::li 200

 

假如想拿最近的10条消息就可以执行如下命令(最新的消息一定在list的最左边):

 

# 下标从0开始,[start,stop]是闭区间,都包含
lrange msg::li 0 9 

 

抽奖活动(set)

 

# 参加抽奖活动
sadd key {userId} 

# 获取所有抽奖用户,大转盘转起来
smembers key 

# 抽取count名中奖者,并从抽奖活动中移除
spop key count 

# 抽取count名中奖者,不从抽奖活动中移除
srandmember key count

 

实现点赞,签到,like等功能(set)

 

# 1001用户给8001帖子点赞
sadd like::8001 1001

# 取消点赞
srem like::8001 1001

# 检查用户是否点过赞
sismember like::8001 1001 

# 获取点赞的用户列表
smembers like::8001 

# 获取点赞用户数
scard like::8001 

 

实现关注模型,可能认识的人(set)

 

seven关注的人
sevenSub -> {qing, mic, james}
青山关注的人
qingSub->{seven,jack,mic,james}
Mic关注的人
MicSub->{seven,james,qing,jack,tom}

 

# 返回sevenSub和qingSub的交集,即seven和青山的共同关注
sinter sevenSub qingSub -> {mic,james}

#
 我关注的人也关注他,下面例子中我是seven
# qing在micSub中返回1,否则返回0
sismember micSub qing
sismember jamesSub qing

#
 我可能认识的人,下面例子中我是seven
# 求qingSub和sevenSub的差集,并存在sevenMayKnow集合中
sdiffstore sevenMayKnow qingSub sevenSub -> {seven,jack}

 

电商商品筛选(set)

 

每个商品入库的时候即会建立他的静态标签列表如,品牌,尺寸,处理器,内存

# 将拯救者y700P-001ThinkPad-T480这两个元素放到集合brand::lenovo
sadd brand::lenovo 拯救者y700P-001 ThinkPad-T480
sadd screenSize::15.6 拯救者y700P-001 机械革命Z2AIR
sadd processor::i7 拯救者y700P-001 机械革命X8TIPlus

#
 获取品牌为联想,屏幕尺寸为15.6,并且处理器为i7的电脑品牌(sinter为获取集合的交集)
sinter brand::lenovo screenSize::15.6 processor::i7 -> 拯救者y700P-001

排行版(zset)

redis的zset天生是用来做排行榜的、好友列表, 去重, 历史记录等业务需求

# user1的用户分数为 10
zadd ranking 10 user1
zadd ranking 20 user2

#
 取分数最高的3个用户
zrevrange ranking 0 2 withscores

 

过期策略

定期删除

 

redis 会将每个设置了过期时间的 key 放入到一个独立的字典中,以后会定期遍历这个字典来删除到期的 key。

 

定期删除策略

 

Redis 默认会每秒进行十次过期扫描(100ms一次),过期扫描不会遍历过期字典中所有的 key,而是采用了一种简单的贪心策略。

 

从过期字典中随机 20 个 key;

删除这 20 个 key 中已经过期的 key;

如果过期的 key 比率超过 1/4,那就重复步骤 1;

 

惰性删除

 

除了定期遍历之外,它还会使用惰性策略来删除过期的 key,所谓惰性策略就是在客户端访问这个 key 的时候,redis 对 key 的过期时间进行检查,如果过期了就立即删除,不会给你返回任何东西。

 

定期删除是集中处理,惰性删除是零散处理。

 

为什么要采用定期删除+惰性删除2种策略呢?

 

如果过期就删除。假设redis里放了10万个key,都设置了过期时间,你每隔几百毫秒,就检查10万个key,那redis基本上就死了,cpu负载会很高的,消耗在你的检查过期key上了

 

但是问题是,定期删除可能会导致很多过期key到了时间并没有被删除掉,那咋整呢?所以就是惰性删除了。这就是说,在你获取某个key的时候,redis会检查一下 ,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你返回任何东西。

 

并不是key到时间就被删除掉,而是你查询这个key的时候,redis再懒惰的检查一下

 

通过上述两种手段结合起来,保证过期的key一定会被干掉。

 

所以说用了上述2种策略后,下面这种现象就不难解释了:数据明明都过期了,但是还占有着内存

内存淘汰策略

这个问题可能有小伙伴们遇到过,放到Redis中的数据怎么没了?

 

因为Redis将数据放到内存中,内存是有限的,比如redis就只能用10个G,你要是往里面写了20个G的数据,会咋办?当然会干掉10个G的数据,然后就保留10个G的数据了。那干掉哪些数据?保留哪些数据?当然是干掉不常用的数据,保留常用的数据了

 

Redis提供的内存淘汰策略有如下几种:

 

  1. noeviction 不会继续服务写请求 (DEL 请求可以继续服务),读请求可以继续进行。这样可以保证不会丢失数据,但是会让线上的业务不能持续进行。这是默认的淘汰策略。

  2. volatile-lru 尝试淘汰设置了过期时间的 key,最少使用的 key 优先被淘汰。没有设置过期时间的 key 不会被淘汰,这样可以保证需要持久化的数据不会突然丢失。(这个是使用最多的)

  3. volatile-ttl 跟上面一样,除了淘汰的策略不是 LRU,而是 key 的剩余寿命 ttl 的值,ttl 越小越优先被淘汰。

  4. volatile-random 跟上面一样,不过淘汰的 key 是过期 key 集合中随机的 key。

  5. allkeys-lru 区别于 volatile-lru,这个策略要淘汰的 key 对象是全体的 key 集合,而不只是过期的 key 集合。这意味着没有设置过期时间的 key 也会被淘汰。

  6. allkeys-random 跟上面一样,不过淘汰的策略是随机的 key。allkeys-random 跟上面一样,不过淘汰的策略是随机的 key。

持久化策略

Redis的数据是存在内存中的,如果Redis发生宕机,那么数据会全部丢失,因此必须提供持久化机制。

 

Redis 的持久化机制有两种,第一种是快照(RDB),第二种是 AOF 日志。快照是一次全量备份,AOF 日志是连续的增量备份。快照是内存数据的二进制序列化形式,在存储上非常紧凑,而 AOF 日志记录的是内存数据修改的指令记录文本。AOF 日志在长期的运行过程中会变的无比庞大,数据库重启时需要加载 AOF 日志进行指令重放,这个时间就会无比漫长。所以需要定期进行 AOF 重写,给 AOF 日志进行瘦身。

 

RDB是通过Redis主进程fork子进程,让子进程执行磁盘 IO 操作来进行 RDB 持久化,AOF 日志存储的是 Redis 服务器的顺序指令序列,AOF 日志只记录对内存进行修改的指令记录。即RDB记录的是数据,AOF记录的是指令

 

RDB和AOF到底该如何选择?

 

  1. 不要仅仅使用 RDB,因为那样会导致你丢失很多数据,因为RDB是隔一段时间来备份数据

  2. 也不要仅仅使用 AOF,因为那样有两个问题,第一,通过 AOF 做冷备没有RDB恢复速度快; 第二,RDB 每次简单粗暴生成数据快照,更加健壮,可以避免 AOF 这种复杂的备份和恢复机制的 bug

  3. 用RDB恢复内存状态会丢失很多数据,重放AOP日志又很慢。Redis4.0推出了混合持久化来解决这个问题。将 rdb 文件的内容和增量的 AOF 日志文件存在一起。这里的 AOF 日志不再是全量的日志,而是自持久化开始到持久化结束的这段时间发生的增量 AOF 日志,通常这部分 AOF 日志很小。于是在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,重启效率因此大幅得到提升。

 

缓存雪崩和缓存穿透

缓存雪崩是什么?

 

假设有如下一个系统,高峰期请求为5000次/秒,4000次走了缓存,只有1000次落到了数据库上,数据库每秒1000的并发是一个正常的指标,完全可以正常工作,但如果缓存宕机了,每秒5000次的请求会全部落到数据库上,数据库立马就死掉了,因为数据库一秒最多抗2000个请求,如果DBA重启数据库,立马又会被新的请求打死了,这就是缓存雪崩。

如何解决缓存雪崩

 

事前:redis高可用,主从+哨兵,redis cluster,避免全盘崩溃

事中:本地ehcache缓存 + hystrix限流&降级,避免MySQL被打死

事后:redis持久化,快速恢复缓存数据

 

缓存穿透是什么?

 

假如客户端每秒发送5000个请求,其中4000个为黑客的恶意攻击,即在数据库中也查不到。举个例子,用户id为正数,黑客构造的用户id为负数,

如果黑客每秒一直发送这4000个请求,缓存就不起作用,数据库也很快被打死。

如何解决缓存穿透

 

查询不到的数据也放到缓存,value为空,如set -999 “”

 

总而言之,缓存雪崩就是缓存失效,请求全部全部打到数据库,数据库瞬间被打死。缓存穿透就是查询了一个一定不存在的数据,并且从存储层查不到的数据没有写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义

分享到:
评论

相关推荐

    redis页面缓存html使用redis实现页面缓存.docx

    使用 Redis 实现页面缓存 本文档主要介绍了使用 Redis 实现页面缓存的方法,包括缓存 key 的设计、缓存实现的思路和代码实现。 页面缓存的目的:页面缓存的主要目的是为了提高网站的访问速度和用户体验。通过将...

    redis本地缓存与redis缓存

    在“redis本地缓存与redis缓存”的主题中,我们将深入探讨这两种缓存方式及其各自的特点。 首先,我们要理解什么是本地缓存。本地缓存指的是将数据存储在应用程序的内存中,通常是Java的HashMap、Guava Cache或C#的...

    Redis用作二级缓存

    3. 编写Mybatis的配置:在mybatis-config.xml文件中,启用全局的二级缓存并指定使用Redis作为缓存实现。 ```xml <!-- Redis相关配置 --> ``` 4. 定义Mapper缓存:在每个Mapper接口或XML配置文件...

    清空redis缓存脚本指令

    清理redis缓存bat脚本,清理redis缓存bat脚本,清理redis缓存bat脚本,清理redis缓存bat脚本,清理redis缓存bat脚本,清理redis缓存bat脚本,清理redis缓存bat脚本,清理redis缓存bat脚本,清理redis缓存bat脚本,...

    springMybatis+redis三级缓存框架

    综上所述,"springMybatis+redis三级缓存框架"是一种有效的优化方案,它结合了MyBatis的二级缓存和Redis的分布式缓存能力,能够在保证系统响应速度的同时,降低数据库的负载,提升整体应用性能。在实际应用中,根据...

    mybatis+redis缓存配置

    MyBatis提供了两种级别的缓存支持:一级缓存和二级缓存。 - **一级缓存**:也称为本地会话缓存,它的生命周期是伴随着一次会话(SqlSession)的开始和结束。一级缓存默认开启且无法关闭,主要用于减少同一个会话内...

    redis分布式缓存中间件培训PPT

    Redis分布式缓存中间件培训PPT Redis是完全开源免费的高性能key-value数据库,可以满足高可用、高并发的要求...Redis是一种功能强大且灵活的缓存中间件,可以满足高可用、高并发的要求,并且可以应用于多种应用场景。

    SpringBoot项目 MybatisPlus使用 Redis缓存.zip

    本项目中,我们看到“SpringBoot项目 MybatisPlus使用 Redis缓存.zip”主要涉及了SpringBoot、MybatisPlus和Redis三个核心组件,它们在实际开发中扮演着重要角色。 首先,SpringBoot是Spring框架的一种简化版,它...

    c#使用Redis缓存

    本文将深入探讨如何在C#应用中使用Redis缓存,以提高系统性能和响应速度。 首先,要使用Redis与C#进行交互,我们需要一个客户端库。StackExchange.Redis是.NET社区广泛推荐的Redis客户端,它提供了丰富的API用于...

    redis多级缓存搭建资料

    本资料将详细介绍如何使用Redis搭建多级缓存。 一、缓存基础知识 缓存是一种存储技术,用于临时存储经常访问的数据,以减少对慢速存储(如硬盘)的依赖。在Web应用中,缓存可以显著提升响应速度,降低延迟。多级...

    redis缓存分享,包含redis和redis测试的项目test

    使用Redis缓存时,我们需要注意缓存策略的选择,比如LRU(最近最少使用)或LFU(最不经常使用)算法来决定何时淘汰旧数据。此外,还可能涉及到缓存穿透、缓存雪崩和缓存击穿等问题及其解决方案。 "redis_test"可能...

    springboot 使用spring cache缓存 和 缓存数据落地到redis

    【Spring Boot 使用 Spring Cache 缓存与数据落地到 Redis】\n\n在Spring Boot应用中,Spring Cache是一个强大的工具,可以极大地提升应用的性能,通过缓存非计算性或者昂贵的计算结果。Spring Cache抽象了缓存管理...

    Redis_Redis分布式缓存_

    2. **LRU(Least Recently Used)淘汰策略**: 当内存达到预设限制时,Redis会根据LRU原则淘汰最近最少使用的键,保持缓存容量在合理范围内。 3. **LFU(Least Frequently Used)淘汰策略**: 另一种策略是LFU,淘汰...

    redis缓存服务器

    Redis 是一个高性能的键值对数据存储系统,常被用作数据库、缓存和消息中间件。它支持多种数据结构,如字符串、哈希、列表、集合、有序集合,这使得 Redis 在各种场景下有着广泛的应用。Redis 以其内存高速读写性能...

    PHP+Redis 实例 页面缓存

    Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal...

    仿redis缓存Java版轻量级缓存组件LocalCache

    仿redis缓存Java版轻量级缓存组件LocalCache,基于JVM内存实现数据缓存及过期机制

    spring + ehcache + redis两级缓存

    当我们谈论“Spring + Ehcache + Redis”两级缓存时,我们实际上是在讨论如何在Java环境中利用Spring框架来集成Ehcache作为本地缓存,并利用Redis作为分布式二级缓存,构建一个高效且可扩展的缓存解决方案。...

    Redis分布式缓存安装和使用

    在使用 Redis 作为分布式缓存时,开发者通常会结合编程语言的客户端库进行交互,例如使用 Jedis(Java)、StackExchange.Redis(.NET)或 redis-py(Python)。通过这些客户端,应用程序可以方便地读写缓存,提高...

    什么是redis缓存穿透 雪崩 ,如何应对解决 redis缓存穿透 雪崩 的解决办法

    然而,如果使用不当,可能会遇到两种常见问题:缓存穿透和缓存雪崩。这两者都会对系统的稳定性和性能产生严重影响。 **缓存穿透** 缓存穿透是指用户请求的数据既不在Redis缓存中,也不在数据库中,导致每次请求都...

    Redis缓存服务系统

    使用Redis进行缓存管理时,需要注意以下几点: 1. 数据过期策略:Redis允许设置键的过期时间,可以通过EXPIRE命令实现。也可以使用TTL命令检查键的剩余存活时间。 2. 缓存穿透:避免查询不存在的数据导致对数据库的...

Global site tag (gtag.js) - Google Analytics