因为一次redis缓存穿透,全面探究redis能做什么
问题背景:
网关支付 , 支付之前需要根据商户去获取支持的银行列表 , 银行列表是商家首次在我们系统里申请开户的时候配置进去的 , 第一次获取列表是通过调远程接口查询数据库获取的 , 获取成功后 , 结果保存在redis缓存中 , 有效期设置6小时 , 以后每次查询都直接访问redis缓存即可 。
出现问题是有一批新商户没有配置银行列表 , 发起支付获取银行列表时 , 首次调用接口获取结果失败 , 没有放置缓存;商户反复提交了4次 , 每次访问缓存不存在 , 然后远程调用接口服务 , 接口返回同样不存在的错误 , 导致第5次远程调用返回500错误 。
这是典型的缓存穿透问题 。 缓存穿透是指用户不断发起请求缓存和数据库中都没有的数据 , 这时的用户很可能是攻击者 , 攻击会导致数据库压力过大 。
解决办法:
从缓存和数据库中都取不到的值 , 这时可以将key-value键值对写为key-null , 缓存有效时间可以设置短点 , 如30秒(设置太长会导致正常情况也没法使用) 。 这样至少30秒内访问redis能获取到空值 , 可以防止用户反复用同一个id暴力攻击数据库 。
缓存除了穿透问题还有击穿和雪崩问题 。 1)、缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期) , 这时由于并发用户特别多 , 同时读一个热点key , 而这个key缓存没读到数据 , 又同时去数据库取数据 , 引起数据库压力瞬间增大 。
最好的例子就是爆款微博热搜 , 大家同时去访问 , 造成的微博瘫痪 。
解决办法:
- 设置热点数据永远不过期 。
- 加互斥锁 , 用到redis的分布式锁 , 即setnx方法 , 保证对于每个key同时只有一个线程去查询后端服务 , 其他线程没有获得分布式锁的情况下 , 只需要阻塞等待即可 。
举例比如双11 , 所有商品都放入缓存 , 设置过期时间为1小时 , 到了凌晨1点 , 商品信息集体失效 , 此刻所有的查询会全部落到数据库上 。
解决方案:
- 数据预热 , 在即将发生大并发访问之前 , 手动触发加载缓存不同的key , 过期时间随机设置 , 让缓存失效时间点尽量均匀 , 防止同一时间大量数据过期现象发生 。
- 如果缓存数据库是分布式部署 , 将热点数据均匀分布在不同的缓存数据库中 。
- 设置热点数据永远不过期 。
Redis 是一个开源(BSD许可)的 , 内存中的数据结构存储系统 , 它可以用作数据库、缓存和消息中间件 。它支持多种类型的数据结构 , 如 字符串(strings) ,散列(hashes) ,列表(lists) ,集合(sets) ,有序集合(sorted sets) 与范围查询 ,bitmaps ,hyperloglogs 和地理空间(geospatial) 索引半径查询 。Redis 内置了 复制(replication) , LUA脚本(Lua scripting) ,LRU驱动事件(LRU eviction) , 事务(transactions) 和不同级别的 磁盘持久化(persistence) ,并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability) 。
和Memcached类似 , 它支持存储的value类型相对更多 , 这些类型大多数支持add/remove、list支持push/pop、set支持取交集并集和差集 , 而且这些操作都是原子性的 。 在此基础上 , zset支持各种不同方式的排序 。 与memcached一样 , 为了保证效率 , 数据都是缓存在内存中 。 区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件 , 实现数据持久化 , 并且在此基础上实现了master-slave(主从)同步 。
推荐阅读
- Satechi推出Dock5多设备充电站 一次可同时充五种设备
- 富士康 拜腾再续“前缘”,原来是因为这个
- 最壕“年终奖”出炉!雷军下血本:一次颁发两个百万美金技术大奖
- 有没有必要给老年人买台智能手机?
- 无线网络联盟:Wi-Fi 6E是二十年来最重大的一次升级
- 让35亿人用上5G!美巨头突然宣布,华为这一次也落后了?
- 中国移动又开始了一次奇怪尝试
- 芯片巨头推出5G新品,拿下9个第一次,全球35亿人集体受益
- 30天自制操作系统:第一天
- 2020年的手机渠道商:因为华为缺货,赚的盆满钵满