Redis - 应用

缓存

在一个网站中,经常使用关系型数据库(比如MySQL来存储数据),关系型数据库虽然功能强大,但是效率不高。因此如果数据库的并发量比较高,对于数据库的压力是很大的,极容易造成数据库宕机

解决方法:

  1. 开源:引入更多的机器,构成数据库集群(主从复制、分库分表等)
  2. 节流:引入缓存,或其他方式保存经常访问的热点数据,从而降低数据库的请求数量

redis的访问速度要比MySQL快很多,处理同一个访问请求,Redis消耗的系统资源也要比MySQL少很多,因此Redis能够支持更大的并发量

  1. 当需要查询数据时,业务服务器先访问Redis
    1. 如果Redis中存在,则直接返回
    2. 如果redis不存在则查询数据库

缓存更新策略

  1. 定期生成

    每隔一定的周期,对访问的数据频次进行统计,挑选出访问频次最高的前N%的数据。这种方式得到的数据实时性较差,但是更加可控,适用于搜索引擎

  2. 实时生成

    先给缓存设置容量上限(maxmemory参数),用户每次查询,先查redis如果redis中存在则直接返回,如果不存在就查询数据库,然后将查到的结果也保存到redis。这种方法得到的数据实时性更高,但不太可控,适合内部使用

缓存淘汰策略

如果缓存容量达到上限,就需要按照一定规则将"不太热门的数据删除",以保存新的数据

  1. FIFO (First In First Out) 先进先出:

    把缓存中存在时间最久的数据丢弃

  2. LRU (Least Recently Used) 淘汰最久未使用的

    记录每一个key的最近访问时间,淘汰最近访问时间最远的

  3. LFU (Least Frequently Used) 淘汰访问次数最少的

    记录每一个key最近一段时间的访问次数,淘汰访问次数最少的

  4. Random 随机淘汰

    随机抽取key进行淘汰

Redis内置的淘汰策略

volatile-lru:从设置了过期时间的key中淘汰最久未使用的

allkeys-lru:,从所有key中淘汰最久未使用的

volatile-lfu: 4.0版本新增,在设置了过期时间的key中,淘汰最近一段时间访问次数最少的

allkeys-lfu:4.0版本新增,从所有key 淘汰访问次数最少

volatile-random:从设置了过期时间的key中,随机淘汰数据.

allkeys-random :从所有key中随机淘汰数据

volatile-ttl 在设置了过期时间的key中,优先淘汰剩余过期时间最短的

noeviction 默认策略,当内存达到上限时,新写入操作会报错

缓存使用注意事项

缓存预热

redis刚刚启动的时候内部没有数据,此时先通过离线的方式,通过一些途径先把热点数据导入一批。刚导入的热点数据不需要特别准确,只需要帮助MySQL抵挡一部分数据就可以了,随之时间推移,会有新的热点数据替换掉旧的热点数据,缓存热点会逐渐自动调整,来适应当前的情况

缓存穿透

访问的key在redis和数据库中都不存在,此时key不会被放到缓存上,每次访问都会打到数据库。

产生原因

  1. 业务设计不合理,比如缺少必要的参数校验环节
  2. 部分数据在数据库中误删除
  3. 黑客恶意攻击

如何解决

  1. 针对要查询的参数进行严格的合法性校验,比如要查询一个手机号,就要判定这个手机号的格式是否正确

  2. 针对数据库中不存在的key,也存储到redis中,不过value为一个"",避免后续频繁访问数据库

  3. 使用布隆过滤器,来提前判断某个key是否存在

    布隆过滤器是结合hash+bitmap的思想,将key通过n个不同的哈希函数映射到位图上n个不同的位置。当输入一个字符串时,使用哈希函数去判断位图上对应的n个位置是否都为1,如果有一个为0则表示不存在

缓存雪崩

短时间内大量的key在缓存上失效,导致数据库压力骤增

产生原因

  1. redis宕机
  2. redis上大量的key同时过期(设置了相同的过期时间)

如何解决

  1. 部署高可用的redis集群,并且完善监控报警机制,比如哨兵模式
  2. 设置过期时间时添加随机的时间因子

缓存击穿

缓存雪崩的特殊情况,针对热点key,突然过期,导致大量请求直接访问到数据库上

  1. 将热点key设置为永不过期
  2. 进行服务降级,比如访问数据库时使用分布式锁,限制同时请求数据库的并发量

分布式锁

如果数据库内部商品库存只有一件,但是有两台客户端同时访问数据库来判断是否有库存,得到的结果都是有库存,此时就会出现超卖的情况

概念

为解决上述在一个分布式系统中,多个节点同时访问一个公共资源时引发的类似线程安全的问题,就引入了分布式锁

本质上是一个公共服务器,来记录加锁状态

实现

引入一个redis数据库,并设置统一一个key

  1. 每个客户端在进行业务逻辑处理之前,使用set key v nx ex 10 写入键值对。如果写入成功,表示目前服务器没有加锁,可以执行后续的业务逻辑,执行完毕后,将锁删除。如果写入失败,则表示服务器正在被其他客户端访问

  2. 设置过期时间,以解决持有锁的客户端宕机导致锁无法正常释放的情况

  3. 将key设置为针对哪个资源进行加锁,将value设置为每个客户端服务器的唯一编号。客户端服务器删除锁之前,先比较一下自己的编号与value是否相同,相同则删除。以解决一个客户端加锁,另一个客户端由于某种bug将不属于自己的锁删除

  4. 引入lua脚本,解决删除key时,get和del命令不是原子的问题

    lua 复制代码
    if redis.call('get',KEYS[1]) == ARGV[1] then
     return redis.call('del',KEYS[1])
    else 
    return 0
    end;
  5. 引入一个线程(看门狗),这个线程的作用时在锁快要过期时,自动续约,以实现动态过期时间

  6. 引入 Redlock 算法,引入一组Redis节点,,加锁时按照一定的顺序,写入多个master节点,如果某个节点加锁失败就立刻尝试下一个节点,当加锁成功的节点数超过总节点数的一半,则表示加锁成功

    解决redis集群主节点宕机并且主从复制的延迟,导致的锁丢失问题

相关推荐
数聚天成DeepSData4 小时前
遥感农业数据集下载全攻略
数据库·人工智能·深度学习·机器学习·自然语言处理·数据挖掘
一勺菠萝丶4 小时前
生产环境平滑升级实战-Nginx维护页数据库迁移与安全回滚
数据库·nginx·安全
心静自然凉8004 小时前
MySQL主从同步配置(一主一从)
数据库
haidy ahmed5 小时前
企微复杂审批流反序列化:动态表单解析引擎与EAV存储模型
数据库·人工智能·自动化·企业微信
Lihua奏5 小时前
MVCC:为什么多人同时读写数据,数据库还能不乱
数据库
青山木5 小时前
一把 Redis 分布式锁,踩透四个坑:锁争抢、僵尸锁、锁过期、锁丢失
java·数据库·redis·后端
数智化管理手记5 小时前
智能财务如何减少财务加班?智能财务落地需要哪些工具支撑?
大数据·网络·数据库·数据挖掘·精益工程
IvorySQL5 小时前
深度拆解 IvorySQL 去 O 核心解决方案
数据库·人工智能·postgresql
吴声子夜歌6 小时前
Redis 3.x——客户端
数据库·redis