Redis的应用场景及类型

目录

一、Redis的应用场景

1、限流

2、分布式锁

3、点赞

4、消息队列

二、Redis类型的命令及用法

1、String类型

2、Hash类型

3、List类型

4、Set类型

 5、Zset类型

 6、Redis工具类


Redis使用缓存的目的就是提升读写性能

实际业务场景下,我们就可以把 Mysql 中的热点数据缓 存到 Redis 中,提升读取性能,同时也减轻了 Mysql 的读取压力

一、Redis的应用场景

Redis除了做缓存以外,还可以用

  • 限流
  • 分布式锁
  • 点赞/排行榜
  • 消息队列

还有其他场景:计数器、互关好友、购物车和商品标签等等

1、限流

利用Redis的过期键和计数器功能,实现API的限流功能,防止服务被滥用

方法一记录IP在某个时间段访问某接口的次数

使用IP作为Key和其他信息作为Key,访问次数作为Value,访问一次Incr增加一次,超过规定次数则返回false

但问题是:限流时间段是固定的

比如:某接口在1分钟内请求次数不超过1000次

就是00:59分,用户已经访问了999次,1:00key值过期,1:01又访问了999次

看起来好像是没问题,但是00:59—1:01的仅2s时间段内,接口被访问了1000+999次,明显错误

方法二滑动窗口

为了避免方法一种由于key过期导致短期内访问量增大的情况,将时间改成动态的

在每次接口访问时,记录当前访问的时间点,并计算前1min内用户访问该接口的总次数,如果总次数大于1000次,则不允许用户访问该接口

以上两种利用redis实现限流的方式基本能满足我们大部分的业务需要,对于部分要求限流粒度更高更准的业务,可以引入Sentinel来满足业务需要

2、分布式锁

为什么使用分布式锁?

在单机部署的时候,可以使用 Java 中提供的 JUC 锁机制避免多线程同时操作一个共享变量产生的安全问题,通过锁(synchronzied 或 lock)来锁住自己的线程资源,从而防止缓存击穿

Redis的缓存问题:缓存穿透、缓存击穿和缓存雪崩-CSDN博客

这是一种本地加锁的方式,在分布式情况下会带来数据不一致的问题

比如:服务 A 获取数据后,更新缓存 key =100,服务 B 不受服务 A 的锁限制,并发去更新缓存 key = 99,最后的结果可能是 99 或 100,但这是一种未知的状态,与期望结果不一致

①基础版

Redis的SET命令有一个NX参数,可以实现「key不存在才插入」,因此可以用它来实现分布式锁:

SetNX(key,value)

redisTemplate.opsForValue().setIfAbsent(“k”, “v”)

也就是 

SET lockKey requestId NX PX expireTime
  • lockKey 表示锁的资源,

  • requestId 全局唯一的业务id,避免存在加锁和释放锁乱掉的情况

  • NX:表示只有 lockKey 不存在的时候才能 SET 成功,从而保证只有一个客户端可以获得锁。

  • PX expireTime设置锁的超时时间,单位是毫秒;也可以使用 EX seconds以秒为单位设置超时时间

伪代码:

try {if (jedis.set(lockKey, requestId, "NX", "PX", expireTime))) {//业务处理return true;}
} finally{//判断是不是当前线程加的锁,是才释放if(requestd.equals.(jedis.get(lockKey))){//释放锁unlock(lockKey,requestId);}
}  
return false;

②Redisson实现

Redisson 是 Redis 的 Java 客户端之一,支持原子性加/解锁、锁重试、可重入锁、RedLock 等功能

// 获取分布式锁
RLock lock = redissonClient.getLock("myLock");
try {// 尝试加锁,最多等待 10 秒,加锁后的锁有效期为 30 秒boolean locked = lock.tryLock(10, 30, TimeUnit.SECONDS);if (locked) {// 成功获取锁,执行业务逻辑System.out.println("获取锁成功,执行业务逻辑...");} else {// 获取锁失败,可能是超时等待或者其他原因System.out.println("获取锁失败...");}
} catch (InterruptedException e) {e.printStackTrace();
} finally {// 释放锁lock.unlock();// 关闭 Redisson 客户端redissonClient.shutdown();
}

Redisson存储分布式锁是通过Hash结构进行存储的,内置的键值对是< 线程标识,重入次数>,其中重入次数便可用于实现可重入机制

3、点赞

点赞就需要用到Redis的Set类型,Set类型是Redis中的一个无序集合,它可以存储一组字符串元素,并且每个元素都是唯一的

【点赞】SADD key member:向集合中添加一个或多个元素

 redisTemplate.opsForSet().add(key, values)

【取消点赞】SREM key:删除元素

redisTemplate.opsForSet().remove(key,value)

【点赞的所有用户】SMEMBERS key:返回集合中的所有元素

 redisTemplate.opsForSet().members(key)

【是否点赞】SISMEMBER key member:判断元素是否在集合中

redisTemplate.opsForSet().isMember(key, value)

【点赞数】scard(key):元素长度

redisTemplate.opsForSet().size(key)

场景:对活动的相册图片进行点赞且对点赞数量进行计数的功能

public void like(Long activityId) {LzmUserInfo userInfo = UserContextHolder.getLzmUserInfo();String key = ACTIVITY.ACTIVITY_LIKE_KEY + activityId;Boolean member = stringRedisTemplate.opsForSet().isMember(key, userInfo.getUserId().toString());if (BooleanUtil.isFalse(member)) {//未点赞,点赞数+1this.update(Wrappers.<ActivityManageEntity>lambdaUpdate().setSql("like_num = like_num + 1").eq(ActivityManageEntity::getActivityId, activityId).eq(ActivityManageEntity::getIsDelete, IsDeleteEnum.NORMAL.getCode()));redisTemplate.opsForSet().add(key, userInfo.getUserId().toString());} else {//取消点赞,点赞数-1this.update(Wrappers.<ActivityManageEntity>lambdaUpdate().setSql("like_num = like_num - 1").gt(ActivityManageEntity::getLikeNum, 0).eq(ActivityManageEntity::getActivityId, activityId).eq(ActivityManageEntity::getIsDelete, IsDeleteEnum.NORMAL.getCode()));redisTemplate.opsForSet().remove(key, userInfo.getUserId().toString());}}

4、消息队列

Redis可以实现简单的队列。在生产者端,使用LPUSH加入到某个列表中;在消费端,不断的使用RPOP指令取出这些数据,或者使用阻塞的BRPOP指令获取数据,用于处理异步任务,例如邮件发送、后台任务处理,小规模的抢购需求等

场景:邮件发送

生产者发布消息

LPUSH queue msg1

 消费者 拉取消息

RPOP queue

二、Redis类型的命令及用法

1、String类型

操作命令用法
设置set(“k”,“v”)template.opsForValue().set(“k”,“v”)
获取get(“k”)template.opsForValue().get(“k”)
增1incr(“k”)template.boundValueOps(“k”).increment(1)
减1decr(“k”)template.boundValueOps(“k”).increment(-1)
设置时效setex(“k”,seconds,“v”)template.opsForValue().set(“k”,“v”,20, TimeUnit.SECONDS)
key不存在就设置setnx(“k”,“v”)template.opsForValue().setIfAbsent(“k”, “v”)
获取key过期时间ttl(“k”)template.getExpire(“k”)
删除del(“k”)template.delete(“k”)

2、Hash类型

操作命令用法
设置hset(“k1”,“k2”,“k3”)template.opsForHash().put(“k1”,“k2”,“k3”)
获取hget(“k1”,“k2”)template.opsForHash().get(“k1”,“k2”) /template.opsForHash().values(“k1”)
删除hdel(“k1”,“k2”)template.opsForHash().delete(“k1”,“k2”)
是否存在hexists(“k1”,“k2”)template.opsForHash().hasKey(“k1”,“k2”)

3、List类型

操作命令用法
从右侧添加rpush(“k”,“v”)template.opsForList().rightPush(“k”,“v”)
从右侧移除rpop(“list”)template.opsForList().rightPop(“k”)
长度llen(“k”)template.opsForList().size(“k”)
获取指定范围的元素lrange(“list”,0,-1)  -1指全部template.opsForList().range(“list”, 0, -1)

4、Set类型

操作命令用法
添加sadd(“k”,“v”)template.opsForSet().add(“k”,“v”)
值移除srem(“k”,“v”)template.opsForSet().remove(“k”,“v”)
直接移除spop(“k”)template.opsForSet().pop(“k”)
获取所有smembers("k")template.opsForSet().members("k")
是否存在sismember("k")emplate.opsForSet().isMember("k","v")
长度scard(“k”)template.opsForSet().size(“k”)
交集sinter(“k1”,“k2” )template.opsForSet().intersect(“k1”, “k2”)
并集sunion(“k1”,“k2” )template.opsForSet().union(“k1”, “k2”)
差集sdiff(“k1”,“k2” )template.opsForSet().difference(“k1”, “k2”)

 5、Zset类型

操作命令用法
增加zadd(“k”,1,“a”)template.opsForZSet().add(“k”,“1”,a)
排名结果zrevrange(“k”, 0, -1)template.opsForZSet().reverseRange(“k”, 0, -1)
排名分数

zrevrangeByScoreWithScores(“k”, 1, 10);

template.opsForZSet().reverseRangeByScore(“k”, 1, 100)
修改分数zincrby(“k”,20,“a”)template.opsForZSet().incrementScore(“k”,“20”,a)
数量zcard(“k”)template.opsForZSet().zCard(“k”)
获取排名zrank(“k”,“a”)template.opsForZSet().rank(“k”,“a”)

 6、Redis工具类

@Component
public class RedisUtils {@Resourceprivate RedisTemplate<String, Object> redisTemplate;/*** 添加数据*/public void set(String key, Object value) {redisTemplate.opsForValue().set(key, value);}/*** 如果key不存在,则设置key的值为value并返回true,否则返回false*/public boolean setNx(String key, String value) {return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value));}/*** 如果key不存在,则设置key的值为value以及过期时间,并返回true,否则返回false,*/public boolean setNx(String key, String value, long timeout, TimeUnit unit) {return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit));}/*** 根据key获取数据*/public Object get(String key) {return redisTemplate.opsForValue().get(key);}/*** 根据key删除数据*/public void delete(String key) {redisTemplate.delete(key);}/*** 向集合中添加一个或多个元素*/public void add(String key, Object... values) {redisTemplate.opsForSet().add(key, values);}/*** 将 value 插入到 key 对应的列表的头部*/public void leftPush(String key, Object value) {//。redisTemplate.opsForList().leftPush(key, value);}/*** 将 value 插入到 key 对应的列表的尾部*/public void rightPush(String key, Object value) {redisTemplate.opsForList().rightPush(key, value);}/*** 从 key 对应的列表的头部删除并返回一个元素*/public Object leftPop(String key) {return redisTemplate.opsForList().leftPop(key);}/*** 从 key 对应的列表的尾部删除并返回一个元素*/public Object rightPop(String key) {return redisTemplate.opsForList().rightPop(key);}/*** 返回列表中指定范围内的元素*/public List<Object> range(String key, long start, long end) {return redisTemplate.opsForList().range(key, start, end);}/*** 返回集合中的所有元素*/public Set<Object> members(String key) {return redisTemplate.opsForSet().members(key);}/*** 判断元素是否在集合中*/public Boolean isMember(String key, Object value) {return redisTemplate.opsForSet().isMember(key, value);}/*** 向有序集合中添加一个元素并指定分数*/public void add(String key, double score, Object value) {redisTemplate.opsForZSet().add(key, value, score);}/*** 获取指定score范围内元素*/public Set<ZSetOperations.TypedTuple<Object>> rangeWithScores(String key, long start, long end) {return redisTemplate.opsForZSet().rangeWithScores(key, start, end);}
}

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

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

相关文章

Mysql数据库第四次作业

mysql> create table student(sno int primary key auto_increment,sname varchar(30) not null unique,Ssex varchar(2) check (Ssex男 or Ssex女) not null,Sage int not null,Sdept varchar(10) default计算机 not null); mysql> create table Course(Con int primar…

pytest的安装和介绍和 Exit Code 含义

pytest 准备工作&#xff08;在cmd里&#xff09;&#xff1a; 1安装 pip install -U pytest2验证安装 pytest --version # 会展示当前已安装版本3其他的 显示可用的内置函数参数 pytest --fixtures通过命令行查看帮助信息及配置文件选项 pytest --help一、pytets框架中的…

Air780EP-AT开发-HTTP应用指南

简介 关联文档和使用工具&#xff1a; AT固件获取AT指令手册 概述 4G模块支持HTTP和HTTPS协议&#xff0c; HTTP应用的基本流程如下&#xff1a; 1、激活PDP&#xff08;参考&#xff1a;http://oldask.openluat.com/article/937&#xff09;2、初始化HTTP服务3、设置HTTP会话…

从0到1使用Docker部署java项目详解

Docker部署Java项目相比传统部署方式&#xff0c;在环境一致性、配置管理、可扩展性和安全性等方面具有显著优势。然而&#xff0c;它也带来了学习成本、资源消耗和复杂度增加等挑战。 云服务器 白嫖阿里云服务 通过免费试用方式获取自己的阿里云服务器。当然&#xff0c;如…

ElasticSearch(四)— 数据检索与查询

一、基本查询语法 所有的 REST 搜索请求使用_search 接口&#xff0c;既可以是 GET 请求&#xff0c;也可以是 POST请求&#xff0c;也可以通过在搜索 URL 中指定索引来限制范围。 _search 接口有两种请求方法&#xff0c;一种是基于 URI 的请求方式&#xff0c;另一种是基于…

S71200 - 笔记

1 S71200 0 ProfiNet - 2 PLC编程 01.如何零基础快速上手S7-1200_哔哩哔哩_bilibili 西门子S7-1200PLC编程设计学习视频&#xff0c;从入门开始讲解_哔哩哔哩_bilibili

python:本机摄像头目标检测实时推理(使用YOLOv8n模型)

本文将介绍如何使用本机摄像头进行目标检测实时推理的python代码。 文章目录 一、下载YOLO权重文件二、环境配置三、完整代码 一、下载YOLO权重文件 https://github.com/ultralytics/ultralytics?tabreadme-ov-file 拉到网页最下面&#xff0c;选择适合的模型&#xff0c;下…

linux禁用root

linux禁用root 1. 禁止普通用户切换到root1.1 sudo -i和sudo -s的区别1.2 sudo -i和直接登录root账号的区别1.3 禁止sudo -i切换root1.4 禁止su - root切换root 2. 禁止root远程登录2.1 ssh禁止root登录2.2 禁止远程桌面登录 本文主要介绍&#xff1a; 如何禁止普通用户切换到r…

python-docx 如何将列表中的值提取到段落中的run以及保存为多个文档?

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…

如何定位Milvus性能瓶颈并优化

假设您拥有一台强大的计算机系统或一个应用&#xff0c;用于快速执行各种任务。但是&#xff0c;系统中有一个组件的速度跟不上其他部分&#xff0c;这个性能不佳的组件拉低了系统的整体性能&#xff0c;成为了整个系统的瓶颈。在软件领域中&#xff0c;瓶颈是指整个路径中吞吐…

前端网页打开PC端本地的应用程序实现方案

最近开发有一个需求&#xff0c;网页端有个入口需要跳转三维大屏&#xff0c;而这个大屏是一个exe应用程序。产品需要点击这个入口&#xff0c;并打开这个应用程序。这个就类似于百度网盘网页跳转到PC端应用程序中。 这里我们采用添加自定义协议的方式打开该应用程序。一开始可…

吴恩达深度学习笔记1 Neural Networks and Deep Learning

参考视频&#xff1a;(超爽中英!) 2024公认最好的【吴恩达深度学习】教程&#xff01;附课件代码 Professionalization of Deep Learning_哔哩哔哩_bilibili Neural Networks and Deep Learning 1. 深度学习引言(Introduction to Deep Learning) 2. 神 经 网 络 的 编 程 基 础…

大型语言模型的生物医学知识图优化提示生成

大型语言模型的生物医学知识图优化提示生成 https://arxiv.org/abs/2311.17330 https://github.com/BaranziniLab/KG_RAG 大型语言模型的生物医学知识图优化提示生成 摘要 KG-RAG框架&#xff0c;较好的结合了生物医学知识图谱SPOKE和LLM的优势。SPOKE是一个开放知识图谱&…

【云原生】Kubernetes中的DaemonSet介绍、原理、用法及实战应用案例分析

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

59、mysql存储过程

存储过程 一、存储过程&#xff1a; 1.1、存储过程的概念 概念&#xff1a;完成特定功能的sql语句的集合。把定义好的sql集合在一个特定的sql的函数当中 每次执行调用函数即可。还可以实现传参的调用。 1.2、存储过程的语法&#xff1a; delimiter $$ ##delimiter开始和结…

Visual Studio 2022新建 cmake 工程测试 tensorRT 自带样例 sampleOnnxMNIST

1. 新建 cmake 工程 vs2022_cmake_sampleOnnxMNIST_test( 如何新建 cmake 工程&#xff0c;请参考博客&#xff1a;Visual Studio 2022新建 cmake 工程测试 opencv helloworld ) 2. 删除默认生成的 vs2022_cmake_sampleOnnxMNIST_test.h 头文件 3. 修改默认生成的 vs2022_cma…

Docker简单快速入门

1. 安装Docker 基于 Ubuntu 24.04 LTS 安装Docker 。 # 更新包索引并安装依赖包 sudo apt-get update sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common# 添加Docker的官方GPG密钥并存储在正确的位置 curl -fsSL https://mirror…

叮!2024 龙蜥操作系统大会议题征集正式启动

定啦&#xff01;2024 龙蜥操作系统大会&#xff08;OpenAnolis Conference&#xff0c;以下简称“龙蜥大会”&#xff09;将于 2024 年 8 月 30 日在北京中关村国家自主创新示范区会议中心盛大召开。 2024 龙蜥大会由中关村科学城管委会、海淀区委网信办、中国开源软件推进联…

Python从0到100(四十三):数据库与Django ORM 精讲

前言&#xff1a; 零基础学Python&#xff1a;Python从0到100最新最全教程。 想做这件事情很久了&#xff0c;这次我更新了自己所写过的所有博客&#xff0c;汇集成了Python从0到100&#xff0c;共一百节课&#xff0c;帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…

Arduino学习笔记1——IDE安装与起步

一、IDE安装 去浏览器直接搜索Arduino官网&#xff0c;点击Software栏进入下载界面&#xff0c;选择Windows操作系统&#xff1a; 新版IDE下载不需要提前勾选所下载的拓展包&#xff0c;下载好后直接点击安装即可。 安装好后打开Arduino IDE&#xff0c;会自动开始下载所需的…