作者简介:小明java问道之路,2022博客之星全国TOP3,专注于后端、中间件、计算机底层、架构设计演进与稳定性建工设优化。
文章内容兼具广度深度、大厂技术方案,对待技术喜欢推理加验证,就职于知名金融公司后端高级工程师。
热衷分享,喜欢原创~ 关注我会给你带来一些不一样的认知和成长。
2022博客之星全国TOP3 | CSDN博客专家 | 后端领域优质创作者 | CSDN内容合伙人
InfoQ(极客邦)签约作者、阿里云专家 | 签约博主、51CTO专家 | TOP红人、华为云享专家
如果此文还不错的话,还请关注、点赞、收藏三连支持一下博主~
文末获取联系 精彩专栏推荐订阅收藏
专栏系列(点击解锁)
学习路线(点击解锁)
知识定位
Redis从入门到精通与实战
Redis从入门到精通与实战
围绕原理源码讲解Redis面试知识点与实战
MySQL从入门到精通
MySQL从入门到精通
全面讲解MySQL知识与企业级MySQL实战 计算机底层原理
深入理解计算机系统CSAPP
以深入理解计算机系统为基石,构件计算机体系和计算机思维
Linux内核源码解析
围绕Linux内核讲解计算机底层原理与并发
数据结构与企业题库精讲
数据结构与企业题库精讲
结合工作经验深入浅出,适合各层次,笔试面试算法题精讲
互联网架构分析与实战
企业系统架构分析实践与落地
行业最前沿视角,专注于技术架构升级路线、架构实践
互联网企业防资损实践
互联网金融公司的防资损方法论、代码与实践
Java全栈白宝书
精通Java8与函数式编程
本专栏以实战为基础,逐步深入Java8以及未来的编程模式
深入理解JVM
详细介绍内存区域、字节码、方法底层,类加载和GC等知识
深入理解高并发编程
深入Liunx内核、汇编、C++全方位理解并发编程
Spring源码分析
Spring核心七IOC/AOP等源码分析
MyBatis源码分析
MyBatis核心源码分析
Java核心技术
只讲Java核心技术
本文目录
本文目录
本文导读
一、Redis接入指南
1、Redis接入集群模式(推荐)
2、Redis接入哨兵模式(仅做了解,不推荐)
二、Redis使用案例
1、Redis增删改查多种数据结构实现
2、Redis缓存穿透、雪崩、击穿与解决办法
2.1、Redis缓存穿透
2.2、Redis缓存雪崩
2.3、Redis缓存击穿
3、Redis实现限流
3.1、基于Redis的incr
3.2、基于Redis的List、zset等数据结构
4、Redis分布式锁
5、测试环境测试
总结
本文导读
本文提供了两种 Redis 的接入指南,集群模式接入Redis、哨兵模式接入Redis,避免工作中的小伙伴只会背不会用。
Redis使用案例模块主要是为了能够快速开发与使用,给出了一个百万QPS写法的Redis增删改查多种数据结构实现,Redis缓存穿透、雪崩、击穿与解决办法,Redis实现简单的限流策略以及Redis分布式锁, Redis 测试和管理工具Redis Desktop Manager
文章兼具广度深度,让许多读者对大厂技术方案有进一步了解,在底层原理方面配合推荐的的博客,使用效果更佳!
一、Redis接入指南
Redis 接入分为哨兵模式和集群模式。
哨兵模式,基于哨兵集群实现主从切换,可以看作是简单主从模式的扩展(哨兵模式主要用于Redis主从同步架构,主节点宕机需要哨兵节点监控、通知,选举);
集群模式下需要注意的在哨兵模式下,多个服务器在Redis中存储相同的数据,这是浪费。集群模式可以看作是Redis的分布式存储。
1、Redis接入集群模式(推荐)
Jedis 、Redisson、spring-data-redis三者的比较
Jedis 是 Redis 官方推荐的面向 Java 的操作Redis 的客户端,通过jedis我们可以实现连接Redis,以及操作 Redis 。,如果想在 Java 环境下操作 Redis ,需要安装相应的 Redis 驱动程序,也就 jedis.jar 包,然后将该驱动添加至 Java 的 classpath 中。
spring-data-redis是spring-data模块的一部分,RedisTemplate方式是SpringBoot集成Redis的客户端方式,专门用来支持在spring管理项目对redis的操作,使用java操作redis最常用的是使用jedis,但并不是只有jedis可以使用,spring-data-redis提供了redis的java客户端的抽象(org.springframework.data.redis.core.RedisTemplate)并且本身就属于spring的一部分,比起单纯的使用Jedis,更加稳定,管理起来更加自动化.。
Redisson 是一个在Redis的基础上实现的Java驻内存数据网格。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。支持的主要功能:分布式锁、分布式服务、数据序列化、分布式对象处理
org.springframework.data spring-data-redis ${redis.version} redis.clients jedis ${redis.client.version} org.redisson redisson ${redisson.version}
通用Spring配置:${}中的“”字符串为配置
!-- JedisPool连接池 -->
2、Redis接入哨兵模式(仅做了解,不推荐)
redis.properties ${redis.hostAndPort1} ${redis.hostAndPort2} ${redis.hostAndPort3}
二、Redis使用案例
1、Redis增删改查多种数据结构实现
以下类是使用RedisTemplate构件一个完整的Redis缓存操作类。
实现了很多操作 Redis 的功能,包括不同数据结构的增删改查、限流、异步添加、对存储在指定key的数值加num操作等等
推荐文章:Redis安装步骤和特性以及支持的10种数据类型、Redis跳表与实现源码解析、Redis事务工作原理解析与分布式事务实战、Redis过期删除策略和内存淘汰策略剖析、Redis布隆过滤器工作原理与实战
import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.scheduling.annotation.Async;import org.springframework.stereotype.Component;import java.util.List;import java.util.Map;import java.util.Objects;import java.util.concurrent.TimeUnit;import java.util.stream.Collectors;/** * Redis缓存操作类封装 */@Componentpublic class RedisExecutorImpl implements CacheExecutor {private static final Log logger = LogFactory.getLog(RedisExecutorImpl.class);@Value("${redis.systemPrefix}")private String systemPrefix;@Autowiredprivate RedisTemplate redisTemplate;@Autowiredprivate RedisTemplate redisTemplate4Num;@Overridepublic void set(String key, int timeout, Object value) {String redisKey = systemPrefix + key;logger.info("RedisExecutorImpl set redisKey=" + redisKey + ",value=" + value + ",timeout=" + timeout);redisTemplate.opsForValue().set(redisKey, value, timeout, TimeUnit.SECONDS);}@Overridepublic Object getData(String key) {logger.info("RedisExecutorImpl getData key=" + key);return redisTemplate.opsForValue().get(key);}@Overridepublic void setData(String key, long timeout, Object value) {logger.info("RedisExecutorImpl setData key=" + key + ",value=" + value + ",timeout=" + timeout);redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.MILLISECONDS);}@Overridepublic Object get(String key) {logger.info("RedisExecutorImpl get key=" + key);return redisTemplate.opsForValue().get(systemPrefix + key);}@Overridepublic Object get4Num(String key) {logger.info("RedisExecutorImpl get key=" + key);return redisTemplate4Num.opsForValue().get(systemPrefix + key);}@Overridepublic Object hGet(String key, Object field) {return redisTemplate.opsForHash().get(systemPrefix + key, field);}@Override@Async(value = "redisExecutor")public void hSet(String key, String hKey, Object value, Long timeout) {redisTemplate.opsForHash().put(systemPrefix + key, hKey, value);redisTemplate.expire(systemPrefix + key, timeout, TimeUnit.SECONDS);}/** * hDel方法 * * @param hKey * @param key */@Overridepublic void hDel(String key, String hKey) {redisTemplate.opsForHash().delete(systemPrefix + key, hKey);}@SuppressWarnings("static-access")@Overridepublic boolean delete(String key) {try {redisTemplate.delete(systemPrefix + key);return true;} catch (Exception e) {logger.error("redis delete failed, key =" + systemPrefix + key + ", e=", e);return false;}}@Overridepublic List
2、Redis缓存穿透、雪崩、击穿与解决办法
推荐文章:【Redis】Redis缓存穿透、缓存雪崩、缓存击穿详解与解决办法(Redis专栏启动)
2.1、Redis缓存穿透
缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
缓存穿透通常发生在以下两种情况下:缓存中的数据和数据库中的数据被错误删除,导致缓存和数据库中没有数据;黑客恶意攻击并故意访问大量读取不存在数据的企业;
解决方案:
1、非法请求的限制:在接收参数时过滤业务接口中的非法值、空值、负值和空值
2、布隆过滤器:一种类似于哈希表的算法。它使用所有可能的查询条件来生成位图,该位图将用于在数据库查询之前进行过滤。如果没有,它将被直接过滤,以减轻数据库级别的压力;
3、缓存空值:一个相对简单的解决方案。在第一次查询不存在的数据后,密钥和相应的空值也被放入缓存,但设置为较短的过期时间
2.2、Redis缓存雪崩
缓存服务挂掉或者热点缓存失效,所有请求都去查数据库,导致数据库连接不够或者数据库处理不过来,从而导致整个系统不可用。
缓存雪崩两个原因:
1、大量(热点)数据同时过期,导致本应请求缓存的数据,需要从数据库中检索;
解决方案:1、随机、微调甚至设置来设置过期时间;2、添加一个互斥锁,构建缓存后,释放锁,返回空值或默认值;3、双 key 策略,主key是原始缓存, 备key是副本缓存。当主key失败时,可以访问备份key;4、后台更新缓存策略,用定时任务或者消息队列更新或删除Redis缓存。
2、Redis故障宕机(服务挂掉),无法处理请求,再次请求数据库。
解决方案:1、服务熔断或请求限流机制;2、使用主从节点来构建集群
2.3、Redis缓存击穿
缓存击穿是指缓存中没有数据,但数据库中有数据(通常缓存时间到期)。此时,由于并发用户太多,读取缓存并不能读取数据,同时又去数据库检索数据,数据库压力瞬间增加,导致压力过大。击穿和雪崩的区别在于,击穿是针对特定的热点数据,而雪崩是所有数据。
解决方案:
1、缓存设置不过期,并且后台异步更新缓存
2、添加一个互斥锁,构建缓存后,释放锁,返回空值或默认值
3、Redis实现限流
推荐文章:Redis分布式限流与Redis实现限流的四种方式(Redis专栏启动)
在生产中的限流包括网关层的限流与Redis实现的限流策略,主要有基于Redis的increment方法作为vaule实现次数的递增,然后设置缓存过期时间来实现固定时间窗口、List、zset实现的滑动窗口,以及Redis的Lua脚本实现分布式限流。
3.1、基于Redis的incr
@SuppressWarnings("rawtypes")private RedisTemplate redisTemplate;// key自增Long count = redisTemplate.opsForValue().increment(key, 1);// 设置时间窗口boolean expire = redisTemplate.expire(key, cacheTimeSecond, TimeUnit.SECONDS);
3.2、基于Redis的List、zset等数据结构
// 获取令牌,返回 null 代表当前令牌桶中无令牌,则拒绝请求Object result = redisTemplate.opsForList().leftPop("limit_list");// 在令牌桶中添加令牌(令牌需要唯一)redisTemplate.opsForList().rightPush("limit_list",UUID.randomUUID().toString());
4、Redis分布式锁
推荐文章:Redis实现分布式锁解析与应用(Redis专栏启动)
Redis分布式锁被广泛使用。本质上,分布式锁的目标是在Redis中占据一把“钥匙”。当其他进程想要占用一个密钥时,它们必须放弃,或者在发现已经存在密钥时重试。
@SuppressWarnings("rawtypes")private RedisTemplate redisTemplate;// 加锁boolean isGetLock = redisTemplate.opsForValue().setIfAbsent(key, value, timeout, TimeUnit.MILLISECONDS);// 锁是自己的,才释放if (isGetLock) redisTemplate.delete(key);
5、测试环境测试
Redis缓存数据库工具:Redis Desktop Manager
Redis Desktop Manager 类似于 Navicat 的 Redis缓存数据库管理工具,点击进入后和 Navicat 一样首先是连接数据库服务器,输入名字/地址/端口号等等。
连接成功后就可以看到服务器中的数据库,在Redis中我们的数据都是存在一个键里面,就可以操作,鼠标停留在小图标上即可显示功能,使用起来很简单,建议对照官网操作一遍。
总结
本文提供了两种 Redis 的接入指南,集群模式接入Redis、哨兵模式接入Redis,避免工作中的小伙伴只会背不会用。
Redis使用案例模块主要是为了能够快速开发与使用,给出了一个百万QPS写法的Redis增删改查多种数据结构实现,Redis缓存穿透、雪崩、击穿与解决办法,Redis实现简单的限流策略以及Redis分布式锁, Redis 测试和管理工具Redis Desktop Manager
文章兼具广度深度,让许多读者对大厂技术方案有进一步了解,在底层原理方面配合推荐的的博客,使用效果更佳!
如果此文还不错的话,还请关注、点赞、收藏三连支持一下博主~
文末获取联系 精彩专栏推荐订阅收藏