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

实用指南:缓存高可用架构-读缓存

业务场景

如何将十几秒的查询请求优化成毫秒级

缓存中间件技术选型

目前比较流行的缓存中间件Memcached、MongoDB、Redis进行简单对比

使用MongoDB的最少,因为它只是一个数据库,由于它的读写速度与其他数据库相比更快,人们才把它当作类似缓存的存储。

因此接下来就是比较Redis和Memcached,并从中做出选择。目前,Redis比Memcached更流行,这里总结一下原因,共3点。

(1)数据结构举个例子,在使用Memcached保存List缓存对象的过程中,如果往List中增加一条数据,则起初需要读取整个List,再反序列化塞入数据,接着再序列化存储回Memcached。而对于Redis而言,这仅仅是一个Redis请求,它会直接帮助塞入数据并存储,简便快捷。

(2)持久化对于Memcached来说,一旦系统宕机数据就会丢失。因为Memcached的设计初衷就是一个纯内存缓存。借助Memcached的官方文档得知,1.5.18版本以后的Memcached协助Restartable Cache(可重启缓存)​,其实现原理是重启时CLI先发信号给守护进程,然后守护进程将内存持久化至一个材料中,架构重启时再从那种文件中恢复数据。不过,这个设计仅在正常重启情况下使用,意外情况还是不处理。而Redis是有持久化功能的。

(3)集群这点尤为重要。Memcached的集群设计非常简单,客户端根据Hash值直接判断存取的Memcached节点。而Redis的集群因在高可用、主从、冗余、Failover等方面都有所考虑,所以集群设计相对复杂些,属于较常规的分布式高可用架构。因此,经过一番慎重的思考,项目组最终决定使用Redis作为缓存的中间件。技术选型做完后,开始考虑缓存的一些具体问题,先从缓存何时存储数据入手。

缓存何时存储素材

使用缓存的逻辑如下:

1)先尝试从缓存中读取数据。

2)若缓存中没有资料或者数据过期,再从数据库中读取数据保存到缓存中。

3)最终把缓存数据返回给调用方。

这种逻辑唯一麻烦的地方是,当用户发来大量的并发请求时,它们会发现缓存中没有数据,那么所有请求会同时挤在第2)步,此时如果这些请求全部从数据库读取数据,就会让数据库崩溃。

数据库的崩溃行分为3种情况。

1)单一数据过期或者不存在,此种情况称为缓存击穿。

解决方案:第一个线程如果发现Key不存在,就先给Key加锁,再从数据库读取数据保存到缓存中,最终释放锁。如果其他线程正在读取同一个Key值,那么必须等到锁释放后才行。关于锁的问题前面已经讲过,此处不再赘述。

2)数据大面积过期或者Redis宕机,这种情况称为缓存雪崩。

解决方案:设置缓存的过期时间为随机分布或设置永不过期即可。

3)一个恶意请求获取的Key不在数据库中,此种情况称为缓存穿透。

比如正常的商品ID是从100000到1000000(10万到100万之间的数值)​,那么恶意请求就可能会故意请求2000000以上的数据。这种情况如果不做处理,恶意请求每次进来时,肯定会发现缓存中没有值,那么每次都会查询数据库,虽然最终也没在数据库中找到商品,但是无疑给数据库增加了负担。

这里给出两种解决办法:

①在业务逻辑中直接校验,在数据库不被访问的前提下过滤掉不存在的Key。

②针对恶意请求的Key存放一个空值在缓存中,防止恶意请求骚扰数据库。

缓存预热

上面这些逻辑都是在确保查询材料的请求已经过来后如何适当地处理,如果缓存数据找不到,再去数据库查询,最终是要占用服务器额外资源的。那么最理想的就是在用户请求过来之前把数据都缓存到Redis中。这就是缓存预热。其具体做法就是在深夜无人访问或访问量小的时候,将预热的数据保存到缓存中,这样流量大的时候,用户查询就无须再从数据库读取数据了,将大大减小数据读取压力。

如何更新缓存

更新缓存的步骤特别简单,共两步:更新数据库和更新缓存。但这简单的两步中需要考虑很多问题。

1)先更新数据库还是先更新缓存?更新缓存时先删除还是直接更新?

2)假设第一步成功了,第二步失败了怎么办?

3)假设两个线程同时更新同一个数据,A线程先结束第一步,B线程先完成第二步怎么办?

消除上面的三个难题,存在以下5中方案:

组合1:先更新缓存,再更新数据库

组合2:先删除缓存,再更新数据库

组合3:先更新数据库,再更新缓存

组合4:先更新数据库,再删除缓存

组合5:先删除缓存,更新数据库,再删除缓存

以上五种组合,第5种是相对最优的解决方案,可以最大程度确保数据准确性,降低查询到脏数据(这里指旧数据)的可能性。

缓存的高可用设计

设计高可用方案时,需要考虑5个要点。

1)负载均衡:是否允许通过加节点的方式来水平分担读请求压力。

否可以凭借划分到不同节点的方式来水平分担写压力。就是2)分片:

3)素材冗余:一个节点的数据若是失效,其他节点的数据是否许可直接承担失效节点的职责。

4)Failover:任何节点失效后,集群的职责是否能够重新分配以保障集群正常工作。

5)一致性保证:在数据冗余、Failover、分片机制的数据转移过程中,如果某个地方出了问题,能否保证所有的节点数据或节点与数据库之间数据的一致性(依靠Redis本身是不行的)​。

要是对缓存高可用有需求,可以使用Redis的Cluster模式,以上5个要点它都会涉及。关于Cluster的部署方法,可以参考Redis官方文档或其他相关教程。

缓存的监控

缓存上线以后,还需要定时查看其启用情况,再判断业务逻辑是否需要优化,也就是所谓的缓存监控。在查看缓存使用情况时,一般会监控缓存命中率、内存利用率、慢日志、延迟、客户端连接数等资料。

目前也有很多开源的监控工具,如RedisLive、Redis-monitor。至于最终使用哪种监控工具,则得根据实际情况而定。

http://www.jsqmd.com/news/99011/

相关文章:

  • Java-199 JMS Queue/Topic 集群下如何避免重复消费:ActiveMQ 虚拟主题与交付语义梳理
  • PCB层压工艺参数Tuning指南,新手也能看懂!
  • tauri 嵌入 webview
  • PCB层压品质检测,这些方法比X光更靠谱!
  • [NISACTF 2022]ezpie
  • 总结金属基覆铜板绝缘层失效原因-PCB工程师必看
  • PCB层压不良原因是什么?
  • 高频PCB层压那些特殊要求,90%工程师都不知道!
  • Dify变量注入实现上下文动态传递
  • RDMA设计18:队列管理模块设计3
  • YashanDB数据库的容器化部署探索
  • Excalidraw:开源手绘风格白板工具详解
  • 2025年卡式龙骨供应商权威推荐榜单:隔墙龙骨/传统龙骨/吊顶龙骨源头厂家精选 - 品牌推荐官
  • C语言之小A的糖果
  • Qwen3-VL-8B与OCR结合实现精准图文理解
  • ComfyUI ACE-Step:用AI轻松创作多风格音乐
  • YashanDB数据库的权限管理体系及安全最佳实践
  • EmotiVoice:开源的情感化TTS语音引擎
  • 新代
  • Ubuntu24中ISO文件制作工具
  • 【Science】曹晓风/张宪省/赵忠等点评!杨卫兵研究团队破解植物干细胞命运的“细胞壁密码”
  • GEO优化不踩坑:不同规模企业的服务商选择与落地干货 - bykj8888
  • Dify入门指南:快速构建生成式AI应用
  • 单菌基因组数据分析文献和教程集锦
  • Kotaemon从入门到精通:核心用法与实战
  • TensorRT-LLM模型导出详解(v0.20.0rc3)
  • 2025家用美颜吸顶灯选购全攻略:揭秘化妆显白、拍照自然与视频肤色通透的照明黑科技 - 阿喂嘞lvv
  • Langflow中Prompt技术的底层实现解析
  • 大模型时代的技术从业者:核心能力重构与实践路径
  • 告别社区店促销困局:用数据解锁老客复购新路径