五、Redis常见问题解决方式

1、主从复制风暴(多个从节点同时复制主节点导致主节点压力过大)

2、缓存穿透

①、什么是缓存穿透

缓存穿透是指查询一个根本不存在的数据, 缓存层和存储层都不会命中, 通常出于容错的考虑, 如果从存储层查不到数据则不写入缓存层。 缓存穿透将导致不存在的数据每次请求都要到存储层去查询,失去了缓存保护后端存储的意义。

造成缓存穿透的基本原因有两个:第一,自身业务代码或者数据出现问题。第二,一些恶意攻击、爬虫等造成大量空命中

②、解决方案

1、缓存空对象。

2、布隆过滤器 对于恶意攻击,向服务器请求大量不存在的数据造成的缓存穿透,还可以用布隆过滤器先做一次过滤,对于不存在的数据布隆过滤器一般都能够过滤掉,不让请求再往后端发送。当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就肯定不存在。注意:布隆过滤器是不能删除数据,如果删除数据只能重新初始化数据

③、布隆过滤器原理

布隆过滤器就是一个大型的位数组和几个不一样的无偏 hash 函数。所谓无偏就是能够把元素的 hash 值算得比较均匀。向布隆过滤器中添加 key 时,会使用多个 hash 函数对 key 进行 hash 算得一个整数索引值然后对位数组长度进行取模运算得到一个位置,每个 hash 函数都会算得一个不同的位置。再把位数组的这几个位置都置为 1 就完成了 add 操作。

向布隆过滤器询问 key 是否存在时,跟 add 一样,也会把 hash 的几个位置都算出来,看看位数组中这几个位置是否都为 1,只要有一个位为 0,那么说明布隆过滤器中这个key 不存在。

如果都是 1,这并不能说明这个key 就一定存在,只是极有可能存在,因为这些位被置为 1 可能是因为其它的 key 存在所致。如果这个位数组比较稀疏,这个概率就会很大,如果这个位数组比较拥挤,这个概率就会降低。这种方法适用于数据命中不高、 数据相对固定、 实时性低(通常是数据集较大) 的应用场景, 代码维护较为复杂, 但是缓存空间占用很少。

注意:布隆过滤器不能删除数据,如果要删除得重新初始化数据。

<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.6.5</version>
</dependency>Config config = new Config();
config.useSingleServer().setAddress("redis://"+ host +":" + port);RedissonClient redissonClient = Redisson.create(config);
RBloomFilter<String> myBloom = redissonClient.getBloomFilter("myBloom");
myBloom.tryInit(100000000L,0.03);
boolean key1 = myBloom.add("key");
boolean key = myBloom.contains("key");

3、缓存失效(击穿)

由于大批量缓存在同一时间失效可能导致大量请求同时穿透缓存直达数据库,可能会造成数据库瞬间压力过大甚至挂掉,对于这种情况我们在批量增加缓存时最好将这一批数据的缓存过期时间设置为一个时间段内的不同时间。

4、缓存雪崩

缓存雪崩指的是缓存层支撑不住或宕掉后,流量会像奔逃的野牛一样,打向后端存储层。由于缓存层承载着大量请求,有效地保护了存储层,但是如果缓存层由于某些原因不能提供服务(比如超大并发过来,缓存层支撑不住,或者由于缓存设计不好,类似大量请求访问bigkey,导致缓存能支撑的并发急剧下降),于是大量请求都会打到存储层,存储层的调用量会暴增,造成存储层也会级联宕机的情况。

预防和解决缓存雪崩问题,可以从以下三个方面进行着手。

①、保证缓存层服务高可用性,比如使用Redis Sentinel或Redis Cluster。

②、依赖隔离组件为后端限流熔断并降级。比如使用Sentinel或Hystrix限流降级组件。比如服务降级,我们可以针对不同的数据采取不同的处理方式。当业务应用访问的是非核心数据(例如电商商品属性,用户信息等)时,暂时停止从缓存中查询这些数据,而是直接返回预定义的默认降级信息、空值或是错误提示信息;当业务应用访问的是核心数据(例如电商商品库存)时,仍然允许查询缓存,如果缓存缺失,也可以继续通过数据库读取。

③、多级缓存架构、、、提前演练。 在项目上线前, 演练缓存层宕掉后, 应用以及后端的负载情况以及可能出现的问题, 在此基础上做一些预案设定。

5、热点缓存key重建优化

开发人员使用“缓存+过期时间”的策略既可以加速数据读写,又保证数据的定期更新,这种模式基本能够满足绝大部分需求。但是有两个问题如果同时出现,可能就会对应用造成致命的危害:当前key是一个热点key(例如一个热门的娱乐新闻),并发量非常大。重建缓存不能在短时间完成, 可能是一个复杂计算, 例如复杂的SQL、 多次IO、 多个依赖等。

在缓存失效的瞬间, 有大量线程来重建缓存, 造成后端负载加大, 甚至可能会让应用崩溃。要解决这个问题主要就是要避免大量线程同时重建缓存。我们可以利用互斥锁来解决,此方法只允许一个线程重建缓存, 其他线程等待重建缓存的线程执行完, 重新从缓存获取数据即可。

6、缓存与数据库双写不一致(延时双删)

①、解决方案

1、对于并发几率很小的数据(如个人维度的订单数据、用户数据等),这种几乎不用考虑这个问题,很少会发生缓存不一致,可以给缓存数据加上过期时间,每隔一段时间触发读的主动更新即可。

2、就算并发很高,如果业务上能容忍短时间的缓存数据不一致(如商品名称,商品分类菜单等),缓存加上过期时间依然可以解决大部分业务对于缓存的要求。

3、如果不能容忍缓存数据不一致,可以通过加读写锁保证并发读写或写写的时候按顺序排好队,读读的时候相当于无锁。

4、也可以用阿里开源的canal通过监听数据库的binlog日志及时的去修改缓存,但是引入了新的中间件,增加了系统的复杂度。

总结:

以上我们针对的都是读多写少的情况加入缓存提高性能,如果写多读多的情况又不能容忍缓存数据不一致,那就没必要加缓存了,可以直接操作数据库。放入缓存的数据应该是对实时性、一致性要求不是很高的数据。切记不要为了用缓存,同时又要保证绝对的一致性做大量的过度设计和控制,增加系统复杂性!

7、集群脑裂数据丢失问题(尽量不配置 满足AP)

redis集群没有过半机制会有脑裂问题,网络分区导致脑裂后多个主节点对外提供写服务,一旦网络分区恢复,会将其中一个主节点变为从节点,这时会有大量数据丢失。

规避方法可以在redis配置里加上参数(这种方法不可能百分百避免数据丢失,参考集群leader选举机制):

//写数据成功最少同步的slave数量,这个数量可以模仿大于半数机制配置,比如集群总共三个节点可以配置1,加上leader就是2,超过了半数
min‐slaves‐to‐write 1

注意:这个配置在一定程度上会影响集群的可用性,比如slave要是少于1个,这个集群就算leader正常也不能提供服务了,需要具体场景权衡选择。

8、集群是否完整才能对外提供服务

当redis.conf的配置cluster-require-full-coverage为no时,表示当负责一个插槽的主库下线且没有相应的从库进行故障恢复时,集群仍然可用,如果为yes则集群不可用。

9、Redis集群对批量操作命令的支持

对于类似mset,mget这样的多个key的原生批量操作命令,redis集群只支持所有key落在同一slot的情况,如果有多个key一定要用mset命令在redis集群上操作,则可以在key的前面加上{XX},这样参数数据分片hash计算的只会是大括号里的值,这样能确保不同的key能落到同一slot里去,示例如下:

mset {user1}:name zhuge {user1}:age 18

假设name和age计算的hash slot值不一样,但是这条命令在集群下执行,redis只会用大括号里的 user1 做hash slot计算,所以算出来的slot值肯定相同,最后都能落在同一slot。

10、慢查询分析

参考地址:https://mp.weixin.qq.com/s/mUibP9pYtQ8Af1ztzt0k-A

--- 配置slowlog(微妙)
config set slowlog-log-slower-than 5000
config set slowlog-max-len 500--- 获取慢查询日志10记录
slowlog get 10--- 60s内最大响应延迟
redis-cli -h 127.0.0.1 -p 6379 --intrinsic-latency 60--- 查看一段时间内redis的最小、最大、平均访问延迟
redis-cli -h 127.0.0.1 -p 6379 --intrinsic-latency -i 1 ---
redis-cli -h 127.0.0.1 -p 6379 --bigkeys -i 0.01

六、Redis对应RedisTemplate命令

del key rt.delete(“key”) rt.opsForValue().set(“key”,“value”)
strlen key rt.opsForValue().size(“key”) rt.opsForValue().get(“key”)
getset key value rt.opsForValue().getAndSet(“key”,“value”)
getrange key start end rt.opsForValue().get(“key”,start,end)
append key value rt.opsForValue().append(“key”,“value”)
hmset key field1 value1 field2 value2… rt.opsForHash().putAll(“key”,map) //map是一 个集合对象
hset key field value rt.opsForHash().put(“key”,“field”,“value”)
hexists key field rt.opsForHash().hasKey(“key”,“field”)
hgetall key rt.opsForHash().entries(“key”) //返回Map对象
hvals key rt.opsForHash().values(“key”) //返回List对象
hkeys key rt.opsForHash().keys(“key”) //返回List对象
hmget key field1 field2… rt.opsForHash().multiGet(“key”,keyList)
hsetnx key field value rt.opsForHash().putIfAbsent(“key”,“field”,“value”
hdel key field1 field2 rt.opsForHash().delete(“key”,“field1”,“field2”)
hget key field rt.opsForHash().get(“key”,“field”)
List结构
lpush list node1 node2 node3… rt.opsForList().leftPush(“list”,“node”)
rt.opsForList().leftPushAll(“list”,list) //list是集合对象
rpush list node1 node2 node3… rt.opsForList().rightPush(“list”,“node”)
rt.opsForList().rightPushAll(“list”,list) //list是集合对象
lindex key index rt.opsForList().index(“list”, index)
llen key rt.opsForList().size(“key”)
lpop key rt.opsForList().leftPop(“key”)
rpop key rt.opsForList().rightPop(“key”)
lpushx list node rt.opsForList().leftPushIfPresent(“list”,“node”)
rpushx list node rt.opsForList().rightPushIfPresent(“list”,“node”)
lrange list start end rt.opsForList().range(“list”,start,end)
lrem list count value rt.opsForList().remove(“list”,count,“value”)
lset key index value rt.opsForList().set(“list”,index,“value”)
Set结构
sadd key member1 member2… rt.boundSetOps(“key”).add(“member1”,“member2”,…)
rt.opsForSet().add(“key”, set) //set是一个集合对象
scard key rt.opsForSet().size(“key”)
sidff key1 key2 rt.opsForSet().difference(“key1”,“key2”) //返回一个集合对象
sinter key1 key2 rt.opsForSet().intersect(“key1”,“key2”)//同上
sunion key1 key2 rt.opsForSet().union(“key1”,“key2”)//同上
sdiffstore des key1 key2 rt.opsForSet().differenceAndStore(“key1”,“key2”,“des”)
sinter des key1 key2 rt.opsForSet().intersectAndStore(“key1”,“key2”,“des”)
sunionstore des key1 key2 rt.opsForSet().unionAndStore(“key1”,“key2”,“des”)
sismember key member rt.opsForSet().isMember(“key”,“member”)
smembers key rt.opsForSet().members(“key”)
spop key rt.opsForSet().pop(“key”)
srandmember key count rt.opsForSet().randomMember(“key”,count)
srem key member1 member2… rt.opsForSet().remove(“key”,“member1”,“member2”,…)

Redis篇-03-常见问题解决方式RedisTemplate的命令相关推荐

  1. 海康录像机识别不到硬盘_海康威视硬盘录像机常见问题解决方式

    海康威视客户端 4.01 使用配置相关注意事项 1. 安装客户端软件选择单机版还是网络版? 目前 4.01 客户端分成 2 个版本,分别是单机版和网络版. 单机版即以前的互相独立的分控模式,每个安装客 ...

  2. MySQL 异常:这一篇就够了,MySQL 抛出异常的几种常见解决方式小结

    Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException: Connectio ...

  3. python对excel表统计视频_列表常见统计方式2_【曾贤志】用Python处理Excel数据 - 第1季 基础篇_Excel视频-51CTO学院...

    ---------------------------------------------------------------- 学完本课程可继续巩固篇:https://edu.51cto.com/c ...

  4. Ubuntu常见系统问题解决方式

    Ubuntu常见系统问题解决方式 Ubuntu每次开机后提示检测到系统程序出现问题的解决方法 Ubuntu循环登陆问题 问题描述 原因 解决方法 文件夹打开缓慢 Ubuntu启动后GUI界面卡住不动 ...

  5. DKhadoop安装配置教程与常见问题解决方法

    上周分别就DKHadoop的安装准备工作以及服务器操作系统配置写了两篇分享的文章,这是个人第一次尝试写一个系统性的分享文章,必然会有很多疏漏的地方,还望见谅吧.今天分享的是DKHadoop安装以及常见 ...

  6. java面试题之-Redis篇(持续更新)

    文章目录 Redis基础 01.Redis里有哪些数据类型? 02.Redis为什么能够快速执行? 03.那Redis怎样防止异常数据不丢失的(Redis的如何持久化)? 04.缓存穿透.缓存击穿.缓 ...

  7. Fortify SCA快速入门以及常见问题解决方法

    本篇将透过HP_Fortify_SCA_and_Apps_3.80从实用主义的角度入手,使读者能够快速的对该工具进行使用和对一些可能出现的常见问题进行处理,从而完成一个完整流程的源代码安全性静态扫描测 ...

  8. 全网搜集面食题系列专题(Redis篇)

    网络搜集整理,有些匆忙,未整理出处,请见谅.因作者水平有限,文中不当之处,烦请批评指证~ redis宕机如何解决?如果是项目上线的宕机呢? 宕机:服务器停止服务 如果只有一台redis,肯定会造成数据 ...

  9. 寻仙手游服务器无响应,寻仙手游游戏中常见问题解决方法介绍

    寻仙手游游戏中常见问题解决方法介绍九游小编已经整理好了,现第一时间把寻仙手游游戏中常见问题解决方法介绍分享给大家.希望由九游小编所提供的这篇攻略玩家朋友们喜欢,也希望能对大家有所帮助,下面就请大家一起 ...

最新文章

  1. mysql 优先队列_深入浅出 MySQL 优先队列(你一定会踩到的order by limit 问题)
  2. 安装JAVA内部错误61003_JDK1.8 安装报内部错误:61003
  3. 蓝卡获得地_德国蓝卡究竟是什么?为什么这么多人都想移民德国?
  4. 关于过往与未来的思考
  5. 李开复:数位革命——创新创业的黄金时代
  6. PowerDesigner逆向工程从SqlServer数据库生成PDM(图文教程)
  7. 目标文件里面到底有什么(1)?
  8. 输入3个字符串,按由小到大顺序输出
  9. 自定义权限 android,Android权限控制之自定义权限
  10. goland 方法注释_goland 设置注释模板的过程图文详解
  11. mysql常规使用(建立,增删改查,视图索引)
  12. mysql数据库迁徙_Mysql数据迁徙方法工具解析
  13. 卷积神经网络(CNN)结尾篇:可视化跟踪(Visualize)
  14. 可更新聚集列存储索引幻想
  15. 排序算法1:最快最简单的排序——桶排序(C++版本)
  16. 聊聊如何从零开始自学编程
  17. NBSI2内部功能实现大揭谜
  18. could not find Fragment constructor
  19. Mac小白——如何查看网速
  20. 雷允上药业百年老店回春

热门文章

  1. Linux中POSIX文件锁的实现
  2. Ubuntu下的Kitematic安装启动出现无法使用的问题
  3. mac docker kitematic 安装 rabbitMQ
  4. H5知识点大总结勾起你的欲望
  5. html语言中标记h1代表什么,HTML h1标签是什么标签?如何设置html h1标签的位置?...
  6. Atlas500------模型转换(二)
  7. 资本爱上智能健身镜?
  8. 用js实现滚动加载动画效果
  9. php 403_403错误怎么解决?
  10. 计算机技术基础:计算机基本结构、运行内存、数据存储、文件系统、软件、操作系统