Redis:redis基于各大实战场景下的基本使用

文章目录

  • 前言
    • String 命令实战
      • 1.业务缓存
        • 对应redis中的指令
        • 伪代码
      • 2.分布式锁
        • 对应redis中的指令
        • 伪代码
      • 3.限流
        • 对应redis中的指令
        • 伪代码
    • List 命令实战
      • 1.提醒功能
        • 对应Redis中的指令
        • 伪代码
      • 2.热点列表
        • 对应Redis中的指令
        • 伪代码
    • Hash 命令实战
      • 1.用户资料缓存
        • 对应redis中的指令
        • 伪代码
      • 2.购物车实战
        • 对应redis中的指令
        • 伪代码
    • Set命令实战
      • 1.标签系统
        • 对应redis中的指令
        • 伪代码
      • 2.自适应黑白名单系统
        • 对应redis中的指令
        • 伪代码
      • Sorted Set命令实战
      • 1.积分排名
        • 对应redis中的指令
        • 伪代码
      • 2.延时消息
        • 对应redis中的指令
        • 伪代码
  • 总结

在这里插入图片描述

前言

  • 适用人群:熟悉redis的指令,但不了解使用场景的人群

  • 本文会详细描述各个场景的伪代码和对应的redis指令,至于为什么只是伪代码是因为每个语言操作redis的方式不一致,但是思想是一致的,只需要根据这个思想去找对应的api即可。

String 命令实战

  • String的命令主要是有三大运用场景:分别是分布式锁的运用,限流操作和业务缓存。

1.业务缓存

  • 场景复现:某个活动即将在 11月11日开展。预期数据库的访问压力陡增。

  • 解决方案:利用Redis,提前将要被多次访问的数据放入redis,做到“缓存预热”。让用户进入我们活动页面的时候,先去搜索缓存,不直接访问数据库,做到释放数据库的压力。

对应redis中的指令

set data "data"get data

伪代码

void cacheData(){//1.从数据库中获取热点数据//2.将此类数据序列化//3.将 (data-data的id) 作为key,序列化的data作为value,利用string的set方法,存入redis。将活动的持续时间作为TTL}void getData(id){//1.将data和id拼接作为key,根据key聪redis中根据string的get指令,进行查询。//2.1查询到,直接返回//2.2没有查询到,根据id去数据库中查找,如果有,就直接返回,并存入redis中。
}

2.分布式锁

  • 场景复现:多个服务去抢夺资源,有并发,线程安全问题。

  • 解决方案:利用redis的set … nx命令,实现分布式锁的效果。

  • 为什么它叫分布式锁呢?其实是因为多个服务都可以连接到一个redis中,相当于,水库里的水很多,但是总要从一个管道里流出一样,这个管道就相当于控制,同一时间内,只有一部分水可以流出。

对应redis中的指令

set key value NX

当目标key不存在的时候,才允许写入这个key,如果key已经存在,这个key就写不进去

伪代码

void tryLock(id){//1.不断抢锁直到抢到while(true){//1.1.把 (update+传入的id)作为key,当前线程的名称作为value,使用nx指令,设置5s的过期时间(避免因为系统原因未能释放,则导致锁无法释放,这是兜底措施)//1.2.1.如果1.1步骤失败,说明抢锁失败,进入下一次循环,继续抢锁。//1.2.2.如果成功,就break,结束循环 }//2.执行业务逻辑//3.删除 (update+传入的id)的key的值,相当于释放锁。
}

3.限流

  • 场景复现:高并发场景下,抢购,秒杀等,流量峰值很高,但是后端业务的资源很有限。

  • 解决方案:假如后端资源只够1000qps,那么我们可能就得对高于这个值的qps做限流,高于它的部分可能就得做降级处理了。

对应redis中的指令

set age 25
//返回:OK
INCR age
//返回:26

伪代码

void limit(){//1.取到当前的时间戳Long now = currentTimeMilles()//2.将当前服务名+now做为key,每打过来一个请求,就把这个value利用INCR指令+1。//3.如果当前value > 1000 qps,那么就直接返回“请求限流”//4.如果 value < 1000 qps,那么执行请求。
}

List 命令实战

  • List命令主要是有三大运用场景:消息队列,提醒功能和热点列表。

  • 但是由于消息队列的消息丢失问题很难处理,因此我们主要讲提醒功能和热点列表。

1.提醒功能

  • 虽然说Redis的list可以实现消息队列的效果,但是利用Redis的list实现消息队列时候,在消息弹出,但是消费者没有消费前,消费者如果宕机,此条消息就会直接丢失。所以说,除非你的场景里,消息是可以接受丢失的,例如我们要说的提醒功能,不然尽量不要用它作为消息队列。

  • 场景复现:我是一个掘金作者,当有掘友给我点赞的时候,我需要接收到点赞信息,并且给予反馈。

  • 解决方案:后端在接受点赞消息后,将点赞人push到点赞List中,当我(掘金作者)登录网站的时候,前端给后端请求点赞的list。

对应Redis中的指令

//从右侧push
RPUSH 集合名称 集合元素
//从左侧遍历 下标1到下标2的所有元素
LRANGE 集合名称 下标1 下标2
//从左侧截断,下标1之前的所有元素,返回下标1到下标2的所有元素
LTRIM 集合名称 下标1 下标2

伪代码

void likeList(){String listName = "like-" + articleId
//开启一个线程,模拟用户端点赞,此时有10000人for(int i=0;i<10000;i++){//将listName作为list的key,用户id作为value,利用rpush指令,加入list} //再开启一个线程,模拟掘金作者端while(true){//1.利用LRANGE指令,拉取前1000个人的点赞。//2.读取,并且展示。//3.展示完成后,利用LTRIM指令,把第一步返回的userId的size大小作为下标1,-1作为下标2,执行该指令。相当于把前1000个userIds截断掉}}

2.热点列表

  • 其实上述的提醒功能的本质就是对list里面的消息进行消费,就是消息队列里的生产者和消费者模式。

  • List还有一个常见的模式就是热点列表,或者是微博上的话题列表等。

对应Redis中的指令

//从右侧push
RPUSH 集合名称 集合元素
//从左侧数下标,设置该下标对应的值
LSET 集合名称 下标 值
//从左侧遍历 下标1到下标2的所有元素
LRANGE 集合名称 下标1 下标2

伪代码

//定时任务更新热点列表
void updateHotList(){//1.从数据库中计算得出最火热的20条数据//2.利用lset命令,根据下标更新当前李彪数据
}//客户端拉取热点列表//1.根据lrange命令找到所有的热点,返回

Hash 命令实战

  • hash的数据结构我们知道,适用于存储键值对比较多的集合。下面我们以两个实战来讲解,分别是用户资料缓存和购物车的存储。

1.用户资料缓存

  • 场景复现:我们知道,在复杂的系统中,c端用户的信息是非常多的,可能有几十个字段用来描述这个用户。且该信息访问的次数也是很多。

  • 解决方案:放弃将用户信息序列化成字符串的方式,该用Hash方式进行存储。我们用手机电话作为key,用户信息对象作为value进行存储。并且对活跃用户进redis缓存,非活跃用户留在mysql中。

对应redis中的指令

//获取key下的所有hash键值对
hgetall key
//设置key ,hash的键值对
hset key k1 v1 k2 v2 k3 v3

伪代码

void login(mobile){//1.获取keyString key = "login:" + mobile//2.根据hgetall指令获取该用户的所有信息//3.1.如果返回的信息不为空//3.1.1.如果value里没有标识符,直接返回脱敏后的用户信息//3.1.2.如果value里有标识符,说明这个人没有注册却一直在登录,有想让我们缓存击穿的嫌疑,直接返回“未注册”即可//3.2.如果为空//3.2.1.从数据库中获取登录对象//3.2.1.1.如果数据库返回是空,说明没有注册,将该key存入redis,value给一个标识符,标识它未注册(防止缓存击穿)。//3.2.1.2.如果数据库返回不是空,就把这个用户数据利用Hallset指令,存入redis,说明他是热点用户。返回当前用户数据}

什么是缓存击穿?

大量数据打入热点key,此时key失效,数据直接打入数据库,让数据库压力剧增

2.购物车实战

  • 场景复现:相比大家都用过淘宝吧,淘宝里有购物车功能。就是当用户选好商品,会先放入购物车,可以达到一起支付的效果。

  • 问题解决:其实这个场景有两种解决思路。第一是购物车的数据存入前端。但前端做不到在用户选择商品到购物车的时候,就做好了库存检查的此类操作,需要提交购物车的时候,后端返回。用户体验有缺失的。因此,我们可以用后端对购物车进行存储。这个需要根据场景进行衡量。

对应redis中的指令

//获取key下的所有hash键值对
hgetall key
//设置key ,hash的键值对
hset key k1 v1 k2 v2 k3 v3
//删除该key对应的hash结构里的k1 k2 k3
hdel key k1 k2 k3

伪代码

static CART_PREFIX = "cart:"
void add(userId,productId,prodNum){String key = CART_PREFIX + userId//利用hset把CART_PREFIX + userId作为key,productId作为k1,prodNum作为value进行存储
}
void remove(userId,productId){String key = CART_PREFIX + userId//利用hdel把CART_PREFIX + userId作为key,productId作为k1进行删除
}
void submitOrder(userId){String key = CART_PREFIX + userId//利用hgetall进行购物车内容的获取
}

Set命令实战

  • Set命令的对应实战场景主要有俩,分别是标签系统和自适应黑白名单系统。

1.标签系统

  • 场景复现:在掘金文章发表的过程中,需要给文章贴上标签【“java”,“后端”】。你的个人资料里可能也有标签,比如说,你是学什么的,你的能力等,这些都是你的标签。我们可能需要根据你的个人信息里的标签,给你推荐适合你的文章。

对应redis中的指令

//将set1中添加"a"元素
SADD set1 "a"
//从set1,set2,set3中找到交集并返回
SINTER set1 set2 set3

伪代码

productTag(){String articleTagKey = "tag_a_" + articleId//将这几个标签加入这个文章中sadd(articleTagKey,"java","后端","设计模式","数据库")String userTagKey = "tag_u_" + userIdsadd(userTagKey,"程序员","java");//将用户标签集合和所有的文章标签集合,利用sinter指令做交集,如果交集数量大于一个值,就做推荐。
}
  • 除了掘金这种最基本的标签匹配的推荐系统之外。像微博会有共同关注的功能,底层也是基于这个思想的推荐系统。例如张三和我有类似的标签,如果他喜欢的东西,关注的东西,可能也会推荐给我,因为我们是一类人。

  • 包括像qq里面的好友推荐功能,有的陌生好友,下方显示,和你有多少相同的好友,也基本是可以基于sinter指令来实现的。

2.自适应黑白名单系统

  • 场景复现:某个用户异地登录,或者账户被盗,或者突然下单大量不感兴趣的商品,被风控检测。

  • 问题解决:可以在检测到之后,把userId放入set黑名单中,利用一些安全框架,对这些黑名单做接口限制,前端也需要限制,除非他同意做人脸识别或者短信验证的安全认证,做完之后,可以从黑名单中移除。

对应redis中的指令

//将set1中添加"a"元素
SADD set1 "a"
//检查a是否在set1中
SISMEMBER set1 "a"
//将a从set1中删除
SREM set1 "a"

伪代码

boolean addProduct(userId,productId){//1.利用SISMEMBER指令检测是否在黑名单中,如果是就直接如人脸验证,或者短信验证//2.如果没有就允许请求
}
void faceCheck(userId){//1.人脸检测//2.检测完成//3.利用HREM指令删除黑名单
}

Sorted Set命令实战

  • Sorted Set又叫Zset。主要有两种运用场景,分别是积分排名和延时消息。

1.积分排名

  • 场景复现:比如,lol中的rank排行榜,在峡谷之巅第一名是恶魔波刚,第二名是jjking,第三名是菠萝剑姬。这样的系统如何实现呢?

  • 问题解决:利用Sorted Set解决。

对应redis中的指令

//往myzset加入两个值。分数-玩家名的键值对
ZADD myzset 100 jjking 90 恶魔波冈
//查询目标的score值
ZSCORE myzset jjking
//批量查询目标的score值
ZSCORE myzset jjking 恶魔波刚
//增加指定元素的score值
ZINCREBY myzset 20 jjking
返回:"120"
//将myzset中140分-80分的数据带着score逆序且限制2条返回
ZRANGE myzset 140 80 BYSCORE REV WITHSCORES limit 2

伪代码

//玩家胜利后,加分
addScore(){String rankKey = "rank_"//给指定玩家加分,利用ZINCREBY指令zaddIncr(rankKey,point,playerId)
}
//取前2名
getRankList(){//根据上述对应redis指令:ZRANGE myzset BYSCORE REV WITHSCORES limit 2
}

2.延时消息

  • 场景复现:有些分布式任务系统中,任务是有优先级的,系统需要触发高优先级的任务,再触发低优先级的任务。

对应redis中的指令

//往myzset加入两个值。分数-玩家名的键值对
ZADD myzset 100 jjking 90 恶魔波冈
//计数数某个范围内的值
ZCOUNT myzset 70 110
返回:2
//将最小元素pop出来,数字是pop出来的数量
ZPOPMIN myzset 1

伪代码

//添加延时信息
addDelayMessage(){//获取当前时间int current = currentTimeMillis()//在10000之后开始int startTime = current + 10000//利用zadd命令添加            zadd("delayMsgCenter",startTime ,"task_" + taskId);}//消费延时消息
consumeDelayMessage(){//1.利用zcount和 0到current的范围进行搜索返回。//2.1如果返回的数值小于0,说明没有延时消息。//2.2如果返回的数值大于0,说明有延时消息,那就把这个延时队列里的最小值,利用ZPOPMIN的方式,弹出,消费//2.2.1执行消费
}

总结

  • 原文链接:https://juejin.cn/post/7225139862223405114

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/4524.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt实现拖拽功能(支持拖放文件、拖放操作)

目录 拖放Qt程序接受其他程序的拖拽部件/控件之间相互拖放总结 拖放 拖放是在一个应用程序内或者多个应用程序之间传递信息的一种直观的现代操作方式。除了为剪贴板提供支持外,通常它还提供数据移动和复制的功能。 拖放操作包括两个截然不同的动作:拖动和放下。Qt窗口部件可以…

MATLAB 之 Simulink 子系统及其封装

这里写目录标题 一、子系统及其封装1. 子系统的创建1.1 通过 Subsystem 模块建立子系统1.2 通过已有的模块建立子系统 2. 子系统的条件执行2.1 使能子系统2.2 触发子系统2.3 使能加触发子系统 3. 子系统的封装3.1 lcon & Ports 选项卡的参数设置3.2 Parameters & Dialo…

控制请求来源的HTML Meta标签 - Referrer详解

83. 控制请求来源的HTML Meta标签 - Referrer详解 在Web开发中&#xff0c;为了保护用户的隐私和安全&#xff0c;控制请求的来源信息是至关重要的。HTML中的<meta>标签提供了一种简单而有效的方式来控制请求的来源&#xff0c;其中包括Referrer&#xff08;引荐者&…

SpringMVC原理分析 | Controller配置、RestFul风格

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; Controller配置 控制器Controller 控制器复杂提供访问应用程序的行为&#xff0c;通常通过接口定义或注释定义的两种方法实现控制器负责解析用户的请求并将其转换为一…

SpringBoot整合定时任务技术Quartz

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ RequestMapping注解 &#x1f680;Quartz应用场…

在教育领域中使用ChatGPT有哪些优点?

人工智能在教育领域的应用正在迅速增加。OpenAI于2022年11月开发的聊天机器人ChatGPT在全球范围内广受欢迎。 由于其受欢迎程度以及生成类似人类问题的回答的能力&#xff0c;ChatGPT正在成为许多学习者和教育工作者值得信赖的伴侣。然而&#xff0c;与任何新兴技术一样&#x…

2019年全国硕士研究生入学统一考试管理类专业学位联考逻辑试题——纯享题目版

&#x1f3e0;个人主页&#xff1a;fo安方的博客✨ &#x1f482;个人简历&#xff1a;大家好&#xff0c;我是fo安方&#xff0c;考取过HCIE Cloud Computing、CCIE Security、CISP等证书。&#x1f433; &#x1f495;兴趣爱好&#xff1a;b站天天刷&#xff0c;题目常常看&a…

原码的表示

原码表示 定点整数源码与定点小数源码 源码表示例题 正数与负数转换直接将高位变为1即可 原码的性质 原码的优缺点 乘除法直接符号位异或&#xff0c;数值相乘除即可加法与减法需要先判断两个数值的大小然后确定符号位

2.SpringBoot运维实用篇

SpringBoot运维实用篇 ​ ​ 下面就从运维实用篇开始讲&#xff0c;在运维实用篇中&#xff0c;我给学习者的定位是玩转配置&#xff0c;为开发实用篇中做各种技术的整合做好准备工作。 主要分为以下内容&#xff1a; SpringBoot程序的打包与运行配置高级多环境开发日志 ​…

【需求实现】Tensorflow2的曲线拟合(二):进度条简化

文章目录 导读普通的输出方式上下求索TensorBoard是个不错的切入点与Callback参数对应的Callback方法官方的内置Callback官方进度条简单的猜测与简单的验证拼图凑齐了&#xff01; 导读 在训练模型的过程中往往会有日志一堆一堆的困扰。我并不想知道&#xff0c;因为最后我会在…

【域名详解】网络杂谈(13)之深入简出了解什么是域名

涉及知识点 什么是域名&#xff0c;域名的概念&#xff0c;域名的结构&#xff0c;域名地址的寻址过程&#xff0c;深入了解域名的寻址机制。 原创于&#xff1a;CSDN博主-《拄杖盲学轻声码》&#xff0c;更多内容可去其主页关注下哈&#xff0c;不胜感激 文章目录 涉及知识点…

基于Tars高并发IM系统的设计与实现-基础篇1

基于Tars高并发IM系统的设计与实现–基础篇1 作者简介 兰怀玉 毕业于中央民族大学计算机专业 先后供职国内外多家公司软件研发设计岗位&#xff0c;有丰富的软件研发经验。 从事IM领域设计研发十余年&#xff0c;先后领衔多个IM通讯系统设计与研发发&#xff0c;拥有丰富的IM…