当前位置: 首页 > news >正文

Redis缓存设计与性能优化

缓存设计

缓存击穿

数据过期的时候一下子涌入大量的请求,在缓存中不存在。

  • 加互斥锁,只允许一个线程去更新缓存数据
  • 异步预热缓存

缓存穿透

  • 请求的数据根本不存在于缓存和数据库中,每次请求都会打到数据库,导致数据库压力剧增。
  • 缓存空对象。对不存在的数据也缓存一个空值,设置较短过期时间。查同一个不存在的商品进行空值延期
  • redisson布隆过滤器。
  • 参数校验。请求前先校验 userId 是否合理,比如正整数、存在合法范围

缓存雪崩

大量缓存同时失效(或者缓存层支撑不住或者宕机),请求直接打到数据库,造成数据库瞬间崩溃或响应变慢。

  • 过期时间随机化。避免大量 key 同时过期(比如加上随机 1~5 分钟)
  • 设置热点数据永远不过期。
  • 缓存预热或提前加载。系统启动时或定时任务提前加载热门缓存

热点缓存key重建优化

使用分布式锁和dcl(双重检查),只允许一个线程去更新缓存数据。好处是全局一把锁并且一把锁只锁一个对应需要重建的数据。

优化:确定得出数据的时间可以使用trylock避免大量的锁逻辑

缓存与数据库双写不一致

  1. 双写不一致
    双写不一致
  2. 读写并发不一致
    在这里插入图片描述
    解决方案:
  • 一致性要求不高,设置合理的过期时间+每隔一段时间触发读的主动更新
  • 延迟双删。缺点会让每个更新操作都延时
  • 高一致性的情况。对更新缓存的操作加分布式锁,优化可以使用分布式读写锁(因为写数据库要更新缓存,读数据库也要更新缓存(在缓存没对应数据的情况))
  • 引入中间件canal监听binlog修改缓存

读多写少的情况加入缓存提高性能,写多读多的情况又不能容忍缓存数据不一致就不要加缓存了。

开发规范与性能优化

键值设计

  1. key名设计:可读性、可管理性和简洁性。以业务名或者数据库名为前缀用冒号分隔拼接,key名称不宜过长。不要包含特殊字符
  2. value设计:拒绝bigkey(防止网卡流量、慢查询)
    字符串类型为超过10KB,非字符串类型元素超过5000属于大key
  3. bigkey的危害,getall导致redis阻塞,网络拥塞,过期删除时候没有过期异步删除会阻塞redis
  4. 如何优化bigkey
  • 对大key数据拆分经过hash分开存入big list: list1、list2、…listN
  • 如果bigkey不可避免,也要尽量避免getall和直接删除所有字段,可以分批删除
  • 控制key的生命周期,使用expire设置过期时间
  • 选择适合的数据类型

命令使用

  • O(N)命令关注N的数明确N的值。有遍历的需求可以使用scan代替。
  • 禁用命令,禁止线上使用keys、flushall、flushdb等,通过redis的rename机制禁掉命令
  • 合理使用select,redis的多数据库较弱,使用数字进行区分,很多客户端支持较差,同时多业务用多数据库实际还是单线程处理,会有干扰。
  • 使用批量操作提高效率例如mget、mset、pipeline,但要注意控制一次批量操作的元素个数(例如500以内,实际也和元素字节数有关)。

原生命令是原子操作,pipeline是非原子操作。pipeline可以打包不同的命令,原生命令做不到。pipeline需要客户端和服务端同时支持。

  • Redis事务功能较弱,不建议过多使用,可以用lua替代

客户端使用

  1. 避免多个应用使用一个Redis实例
  2. 使用带有连接池的数据库,可以有效控制连接,同时提高效率

有需要时可以对连接池预热

  1. 高并发下添加熔断功能

  2. 设置合理的密码,如有必要可以使用SSL加密访问

  3. Redis过期键有三种清除策略

    • 被动删除:当读/写一个已经过期的key时,会触发惰性删除策略,直接删除掉这个过期key
    • 主动删除:由于惰性删除策略无法保证冷数据被及时删掉,所以Redis会定期主动淘汰一批已过期的key
    • 当前已用内存超过maxmemory限定时,触发主动清理策略
    1. 过期时间的key
      • volatile-ttl:在筛选时,会针对设置了过期时间的键值对,根据过期时间的先后进行删除,越早过期的越先被删除。
      • volatile-random:就像它的名称一样,在设置了过期时间的键值对中,进行随机删除。
      • volatile-lru:会使用 LRU 算法筛选设置了过期时间的键值对删除。
      • volatile-lfu:会使用 LFU 算法筛选设置了过期时间的键值对删除。
    2. 所有的key
      • allkeys-random:从所有键值对中随机选择并删除数据。
      • allkeys-lru:使用 LRU 算法在所有数据中进行筛选删除。
      • allkeys-lfu:使用 LFU 算法在所有数据中进行筛选删除。
    3. 不处理
      • noeviction:不会剔除任何数据,在内存上限时拒绝所有写入操作并返回客户端错误信息"(error) OOM command not allowed when used memory",此时Redis只响应读操作。
    • LRU 算法(Least Recently Used,最近最少使用)淘汰很久没被访问过的数据,以最近一次访问时间作为参考。(默认推荐)
    • LFU 算法(Least Frequently Used,最不经常使用)淘汰最近一段时间被访问次数最少的数据,以次数作为参考。

当存在热点数据时,这时使用LFU可能更好点。
LRU的效率很好,但偶发性的、周期性的批量操作会导致LRU命中率急剧下降。

策略核心思想应对场景
LRU淘汰最近最少使用的键应对时间敏感的缓存访问模式
LFU淘汰历史访问频率最低的键应对长期热点数据的缓存使用场景

配置淘汰算法

maxmemory 256mb
maxmemory-policy allkeys-lru
CONFIG SET maxmemory 256mb
CONFIG SET maxmemory-policy volatile-lru
  1. 不配置最大内存的情况,redis会无限制的使用虚拟内存(使用硬盘模拟内存),性能下降。

相关文章:

  • 容器化革命:告别传统Dockerfile,拥抱现代构建最佳实践
  • JavaScript性能优化实战大纲
  • pikachu靶场通关笔记06 XSS关卡02-反射型POST
  • 用 NGINX 还原真实客户端 IP ngx_mail_realip_module
  • pikachu靶场通关笔记05 XSS关卡01-反射型GET
  • GitHub开源|AI顶会论文中文翻译PDF合集(gpt-translated-pdf-zh)
  • Chrome/ Edge 浏览器弹出窗口隐藏菜单地址栏
  • 解决微信小程序中 Flex 布局下 margin-right 不生效的问题
  • 迁移学习模型构建指南(Python实现)
  • 【C/C++】高性能网络编程之Reactor模型
  • 5.28本日总结
  • 青少年编程与数学 02-020 C#程序设计基础 09课题、面向对象编程
  • IO 中的阻塞、非阻塞、同步、异步及五种IO模型
  • 如何更新和清理 Go 依赖版本
  • flutter使用html_editor_enhanced: ^2.6.0后,编辑框无法获取焦点,无法操作
  • 4.8.4 利用Spark SQL实现分组排行榜
  • 2021年认证杯SPSSPRO杯数学建模D题(第二阶段)停车的策略全过程文档及程序
  • 手机如何压缩文件为 RAR 格式:详细教程与工具推荐
  • python:selenium爬取网站信息
  • 华为手机用的时间长了,提示手机电池性能下降,需要去换电池吗?平时要怎么用能让电池寿命长久一些?
  • 宁波靠谱的网站推广定制/怎么在百度上发布个人文章
  • 个人网站需要哪些内容/建站软件
  • 做网站实例/长春网站建设团队
  • 百度做网站的联系人/内蒙古最新消息
  • 网站建设用户登录/杭州网站优化
  • 学平面设计网站/seo工具不包括