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

news2024/11/19 5:51:12

文章目录

  • 前言
    • 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.获取key
 String 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_" + userId
 sadd(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.coloradmin.cn/o/681448.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RabbitMQ学习笔记(尚硅谷)

文章目录 一. 消息队列1. 定义2. 作用2.1 流量消峰2.2 应用解耦2.3 异步处理 3. 分类4. MQ的选择5. RabbitMQ5.1 概念5.2 四大概念5.3 六大模式5.4 RabbitMQ 工作原理5.5 安装 6. 代码实现 二. Hello World (简单模式)1. 生产者代码2. 消费者代码 三. Work Queues (工作队列模式…

OUC编译原理实验报告 实验5:用Yacc设计语法分析器1 实验6:用Yacc设计语法分析器2

编译原理实验报告 实验5&#xff1a;用Yacc设计语法分析器1 实验6&#xff1a;用Yacc设计语法分析器2 中国海洋大学编译原理实验2023春 仅供同学参考思路 请勿直接抄袭 否则可能喜提0分 目录 文章目录 编译原理实验报告目录一.实验目的二.实验内容实验5实验6 三.实验要求实…

RISCV Reader笔记_2 RV32I

RV32I 完整的RV32I指令集可以用下面的式子中出现单词的首字母表示&#xff1a; 比如这一条&#xff1a; set less than {immediate} {unsigned} 也就是slt slti sltu sltiu这4个指令。 RISCV指令格式如下。R 寄存器操作&#xff0c;I 立即数或load访存&#xff0c;S store访…

C51单片机期末复习第八章单片机接口技术

一 总线&#xff1a; 传送同类信息的连线 三总线&#xff1a; 地址总线AB&#xff0c;数据总线DB,控制总线CB 目录(ppt给的没啥用&#xff0c;乱还不全)&#xff1a; 8.1 单片机的系统总线 8.2 简单并行I/O口扩展 8.3 可编程并行I/O口扩展 8.4 D/A转换与DAC0832应用 8…

稀疏表:最大公约数

问题描述 给定一个数组, 每次操作可以选择数组中任意两个相邻的元素 x , y x, y x,y 并将其 中的一个元素替换为 gcd ⁡ ( x , y ) \operatorname{gcd}(x, y) gcd(x,y), 其中 gcd ⁡ ( x , y ) \operatorname{gcd}(x, y) gcd(x,y) 表示 x x x 和 y y y 的最大公约数。 请…

MIT 6.S081 教材第五章内容 -- 中断与设备驱动--下

MIT 6.S081 教材第五章内容 -- 中断与设备驱动--下 引言关于RISC-V特权级架构说明RISC-V特权模式OpenSBI介绍RISC-V启动过程RISC-V中的异常M模式下的异常1. 硬件中断的处理&#xff08;以时钟中断为例&#xff09;2. M模式下的异常相关寄存器3. 同步异常的处理 S模式下的异常1.…

chatgpt赋能python:Python散点图介绍:如何用Python绘制散点图?

Python散点图介绍&#xff1a;如何用Python绘制散点图&#xff1f; Python是一门流行的编程语言&#xff0c;用于解决各种问题和编写各种应用程序。其中&#xff0c;数据可视化是Python应用程序中非常重要的组成部分。散点图是最常用的数据可视化图形之一&#xff0c;它能够清…

拓扑排序:神经网络

题目链接 神经网络 题目大意 在兰兰的模型中&#xff0c;神经网络就是一张有向图&#xff0c;图中的节点称为神经元&#xff0c;而且两个神经 元之间至多有一条边相连&#xff0c;下图是一个神经元的例子&#xff1a; 图中&#xff0c; X 1 — X 3 X_1—X_3 X1​—X3​是信…

从类加载到双亲委派:深入解析类加载机制与 ClassLoader

目录 前言Class 文件介绍如何生成 class 文件观察 Bytecode 方法class 文件到底是什么样的呢&#xff1f; Class 加载、链接、初始化加载、类加载器双亲委派Launcher 核心类ClassLoader 相关源码ClassLoader 相关问题自定义简单 ClassLoader自定义加密 ClassLoader打破双亲委派…

动态ip与静态ip的概念、区别、应用场景

动态ip与静态ip的区别 前言一、介绍IP地址的概念和作用1.1、IP地址的定义1.2、IP地址的作用 二、动态IP和静态IP的区别2.1、动态IP和静态IP的定义2.2、动态IP和静态IP的特点2.3、动态IP和静态IP的优缺点比较 三、动态IP和静态IP的应用场景3.1. 动态IP的应用场景3.2. 静态IP的应…

利用numpy解决解方程组的基本问题

1 问题 进入大学&#xff0c;我们接触了线性代数&#xff0c;利用线性代数解方程组比高中慢慢计算会好了许多&#xff0c;快捷许多&#xff0c;我们作为编程人员&#xff0c;有没有用python解决解方程组的办法呢&#xff1f; 2 方法 我们提出使用python的numpy解方程。 找到用于…

11- C程序的组成结构 (C语言)

一、C程序的基本组成结构 1、源文件: 后缀为.c 的文件2、头文件&#xff1a;后缀为.h的文件 注意&#xff1a; 源文件 功能&#xff1a;实现程序功能头文件 功能&#xff1a;函数的声明、全局变量的声明、宏定义、类型的声明一个由C语言所组成的项目中 只允许有一个main函数 …

离散数学大作业任务书

目 录 实际的练习题目、系统的总功能和各子模块的功能………………………………………………………………………………1 1.1题目及问题描述………………………………………………………………1 1.2功能概述………………………………………………………………………1 1.3技…

02 | 日志系统:一条SQL更新语句是如何执行的?

以下内容出自《MySQL 实战 45 讲》 02 | 日志系统&#xff1a;一条SQL更新语句是如何执行的&#xff1f; 查询语句的那套流程&#xff0c;更新语句也会走一遍。 更新流程中和查询不一样的是&#xff0c;更新流程中涉及了两个重要的日志模块。redo log (重做日志) 和 binglog&a…

如何编写用于Neo-Hookean材料的Abaqus VUMAT Fortran子例程

引言 大家好&#xff0c;我是一个热爱编程、研究有限元分析的普通程序员。我非常感谢你们能够抽出宝贵的时间来阅读我的文章&#xff0c;你们的支持是我前行的动力。今天&#xff0c;我们将讨论一个非常专业的话题&#xff0c;即如何编写用于Neo-Hookean材料的Abaqus VUMAT Fo…

Unreal 5 实现UI制作

这一篇讲解一下unreal engine里面的内置ui插件UMG&#xff0c;虚幻示意图形界面设计器&#xff08;Unreal Motion Graphics UI Designer&#xff09;(UMG) 是虚幻引擎内置的一套ui制作工具&#xff0c;通过它我们能够实现平面ui&#xff0c;场景hud内容 实现背景图片填充整个…

【MySQL数据管理】:插入、修改、删除操作

前言 ✨欢迎来到小K的MySQL专栏&#xff0c;本节将为大家带来MySQL数据插入、修改、删除的讲解✨ 目录 前言一、插入数据二、修改数据三、删除数据四、总结 一、插入数据 使用INSERT INTO语句来向表中插入数据 ✨语法&#xff1a; 给指定字段添加数据 INSERT INTO 表名 (字段…

ctfshow web入门 php特性web98-102

1.web98 get会被post方式覆盖&#xff0c;传入的参数需要等于flag&#xff0c;才能读取到flag值,如果直接传http_flagflag,返回的结果会是一个空数组&#xff0c;因为get变量被覆盖了&#xff0c;而post没有传参 payload: get 11 post HTTP_FLAGflag 2.web99 array_push在数组…

机器视觉初步8:特征提取专题

文章目录 1.角点检测2.纹理特征提取3.特征描述符匹配3.1 Harris角点描述符3.2 SIFT&#xff08;尺度不变特征变换&#xff09;描述符3.3 SURF&#xff08;加速稳健特征&#xff09;描述符 4.基于深度学习的特征提取 在机器视觉中&#xff0c;特征提取是从目标图像中提取有用的视…

C语言:打印菱形(输入菱形上半部分行数)

题目&#xff1a; 用C语言在屏幕上输入以下图案&#xff1a; 思路&#xff1a; 总体思路&#xff1a; &#xff08;一&#xff09;. 输入菱形上半部分行数 -- scanf()函数 &#xff08;二&#xff09;. 使用 for循环 进行 菱形上半部分三角形 的打印&#xff0c; 菱形上半部分…