ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

redis方案设计

2022-02-21 15:02:23  阅读:184  来源: 互联网

标签:方案设计 缓存 设置 过期 数据库 redis 更新 key


jedisCluster.incr,key值+1并返回,将 key 中储存的数字值增一,没有的先设为0再+1并返回,如果 key不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作
jedisCluster.expire,设置过期时间
jedisCluster.llen,列表长度
jedisCluster.hincrBy,把对象属性+对应数值
jedisCluster.ttl,当key不存在时,返回 -2 。 当 key 存在但没有设置剩余生存时间时,返回 -1 。否则,以秒为单位,返回 key的剩余生存时间
jedisCluster.setex,为指定的key设置值及其过期时间。如果 key 已经存在, SETEX 命令将会替换旧的值
jedis.eval,执行lua脚本,redis服务器内置lua解释器
hdel 被成功删除字段的数量,可以和hset结合作为请求锁
加解锁最好使用lua脚本,能保证原子性,通过设置key标记值,再设置过期时间的方式没有原子性,一旦中间出问题没有设置成功过期时间,锁有可能永久不会释放了,详情参考LockImpl
1.lpush,从左往右添加元素,在key 对应 list的头部添加字符串元素 rpop右取
2.rpush,从右到左添加元素,在key 对应 list 的尾部添加字符串元素 lpop左取

redis5.0以上支持string hash list set zset geo hyperloglog stream等数据类型
redis模式:主从、哨兵、集群
使用场景:
String:
计数器(incr、decr)、分布式锁(setnx)、存储对象(对象转换为json字符串)

hash:
购物车,以用户id为key,商品id为field,商品数量为value,恰好构成了购物车的3个要素,使用hincrby添加/减少商品个数,hgetall获取列表,hdel删除商品,hlen获取商品数量
较多fields(比如表很多字段,只挑选有用的一些字段存在redis)/序列化消耗较大/只需要获取少量fields的场景,大JSON对象序列化/反序列化比较耗费资源,尤其是在仅需要少量fields时,使用hash结构,可以减少性能和网络传输损耗
比如最好不要存储对象,因为存取需要序列化、反序列化比较耗时,只存有用字段,hmset/hmget很有用

list:
1.简单发布/订阅。list类型的lpop和rpush(或者反过来,lpush和rpop)能实现队列的功能,可以实现简单的点对点消息队列。但是一般不建议使用,因为当前PH-MQ、MQCP的功能已经很完善了
2. 时序相关的列表缓存
  通过lrange等命令可以批量获取list内容,可用于缓存用户发表的朋友圈列表、评论等时序相关数据,但是针对删除、更新等操作支持不佳

set:
黑名单/白名单/好友/关注集合,全量操作成本较高,redis提供了一些很实用的命令用于直接操作这些集合,如:
a. sinter命令可以获得并集
b. sismember命令可以判断集合中是否存在某值
c. scard命令可以获取sets数量

zset:
1. 排行榜,支持score传入票数等排行依据进行排序
2. 延时队列(带有延时功能的消息队列),比如用户下单30分钟后未付款自动关闭订单或者用户下单后延时短信提醒
score作为时间戳,自动按照时间最近的进行排序,启一个线程持续poll并设置park时间,完成延迟队列的设计,可参考Executors.newScheduledThreadPool中的DelayedWorkQueue
3. 滑动窗口限流(指定时间T内,只允许发生N次。我们可以将这个指定时间T,看成一个滑动时间窗口(定宽))
  score作为时间戳,可统计最近一段时间内内的成员数量,实现滑动窗口限流

Geo:
1. 查找附近的人,需要传入坐标信息
  获取方圆20km的10个人,按距离排序:georadiusbymember keyname ireader 20 km count 10 asc

HyperLogLog:
1. 带有一定精度损失的去重统计计数
  海量数据处理,存在精度缺失问题,最高损失0.81%精度,适用场景:
  a. 统计注册 IP 数
  b. 统计每日访问 IP 数
  c. 统计页面实时 UV 数
  d. 统计在线用户数
  e. 统计用户每天搜索不同词条的个数
       不适用需要精准判断的场景,如黑名单,以免误伤
       
Redis 内存淘汰算法
随机
TTL(从设置了过期时间的 Keys 中获取最早过期的 一批 Keys,然后淘汰这些 Keys)
LRU(Least Recently Used,通过 Key 的最后访问时间来判定哪些 Key 更适合被淘汰)
LFU(Least Frequently Used,最不经常使用,访问次数)  
Redis驱逐策略(基于淘汰算法)
noeviction:达到内存限额后返回错误,客户尝试可以导致更多内存使用的命令(大部分写命令,但DEL和一些例外)
allkeys-lru:为了给新增加的数据腾出空间,驱逐键先试图移除一部分最近使用较少的
volatile-lru:为了给新增加的数据腾出空间,驱逐键先试图移除一部分最近使用较少的,但只限于有过期设置的驱逐key
allkeys-random: 为了给新增加的数据腾出空间,驱逐任意key
volatile-random: 为了给新增加的数据腾出空间,驱逐任意key,但只限于有过期设置的驱逐key
volatile-ttl: 在设置了过期时间的key空间中,具有更早过期时间的key优先移除

Redis使用规范
禁止使用较长key,可以使用md5后的值
禁用keys、flushall、flushdb等命令
必须设置缓存过期时间,不能把Redis当做持久化存储的数据库(不绝对,长期热点数据比如配置信息可以不过期)
禁止存储大value,可以使用不同key分片存储在不同集群节点
使用批处理操作提高效率,原生的可以使用mget、mset,非原生可以使用pipeline(多个命令一起提交,不支持事务,主要是减少网络延迟)
一个应用对应一个Redis实例,避免相互覆盖数据

常见问题及解决方案
缓存失效(过期了,正常业务场景)

缓存击穿,缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。设置热点数据(比如配置)不过期,设置数据中过期时间大于实际过期时间,加锁读取数据库
对该key的请求进行拦截

缓存穿透
缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截。设置排队锁排队访问

缓存雪崩
缓存在同一时间内大量键值过期(失效),需从数据库中获取数据,大量并发请求访问数据库,影响系统稳定。设置排队锁,在并发访问时,排队访问。缓存超时时间设置时,增加一个随机时间长度,避免所有缓存在同一时间失效。建立缓存备份机制(例如:运用本地缓存+分布式缓存互为备份,Redis自动备份)。定时任务更新缓存并续期

缓存污染(多发生在本地缓存,没有深拷贝,改变了对象引用值)

缓存一致性方案
弱一致性方案
先更新数据库,再更新缓存
这套方案,大家是普遍反对的。为什么呢?有如下两点原因。原因一(线程安全角度)同时有请求A和请求B进行更新操作,那么会出现(1)线程A更新了数据库(2)线程B更新了数据库(3)线程B更新了缓存(4)线程A更新了缓存这就出现请求A更新缓存应该比请求B更新缓存早才对,但是因为网络等原因,B却比A更早更新了缓存。这就导致了脏数据,因此不考虑。原因二(业务场景角度)有如下两点:(1)如果你是一个写数据库场景比较多,而读数据场景比较少的业务需求,采用这种方案就会导致,数据压根还没读到,缓存就被频繁的更新,浪费性能。(2)如果你写入数据库的值,并不是直接写入缓存的,而是要经过一系列复杂的计算再写入缓存。那么,每次写入数据库后,都再次计算写入缓存的值,无疑是浪费性能的。显然,删除缓存更为适

先删除缓存,再更新数据库(不推荐)
该方案会导致不一致的原因是。同时有一个请求A进行更新操作,另一个请求B进行查询操作。那么会出现如下情形:(1)请求A进行写操作,删除缓存(2)请求B查询发现缓存不存在(3)请求B去数据库查询得到旧值(4)请求B将旧值写入缓存(5)请求A将新值写入数据库上述情况就会导致不一致的情形出现。而且,如果不采用给缓存设置过期时间策略,该数据永远都是脏数据

先更新数据库,再删除缓存(推荐)
先更新数据库,再延迟删除缓存
监听binlog更新redis(不推荐,容易出问题)

强一致性方案
通过加锁

     

标签:方案设计,缓存,设置,过期,数据库,redis,更新,key
来源: https://blog.csdn.net/qq_35572013/article/details/123047489

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有