redis缓存一致性问题 & 秒杀场景下的实战分析

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 本篇文章讲述了在高并发场景下 redis缓存一致性问题 & 秒杀场景下的实战分析, 数据库缓存不一致解决方案, 缓存与数据库双写一致以及秒杀场景下缓存一致性问题的实战解决方案

👳我亲爱的各位大佬们好

♨️本篇文章记录的为 redis缓存一致性问题 & 秒杀场景下的实战分析相关内容,适合在学Java的小白,帮助新手快速上手,也适合复习中,面试中的大佬🙉🙉🙉。
♨️如果文章有什么需要改进的地方还请大佬不吝赐教❤️🧡💛
👨‍🔧 个人主页 : 阿千弟

@[toc]
在这里插入图片描述

为什么会有缓存一致性问题

由于我们的缓存的数据源来自于数据库 , 而数据库的数据是会发生变化的 , 因此,如果当数据库中数据发生变化,而缓存却没有同步 , 此时就会有一致性问题存在

数据库缓存不一致解决方案

用户使用缓存中的过时数据,就会产生类似多线程数据安全问题,从而影响业务,产品口碑等;怎么解决呢?有如下几种方案

①Cache Aside Pattern (旁路缓存模式)

人工编码方式:缓存调用者在更新完数据库后再去更新缓存,也称之为双写方案

1. Cache-Aside读流程

在这里插入图片描述

2. Cache-Aside 写流程

更新的时候,先更新数据库,然后再删除缓存

好处
读的时候,先读缓存,缓存命中的话,直接返回数据
缓存没有命中的话,就去读数据库,从数据库取出数据,放入缓存后,同时返回响应。

②Read/Write Through Pattern (读写穿透模式)

由系统本身完成,数据库与缓存的问题交由系统本身去处理

1. Read-Through的简要流程

  • 从缓存读取数据,读到直接返回

  • 如果读取不到的话,从数据库加载,写入缓存后,再返回响应。

    2. Write through

    Write-Through模式下,当发生写请求时,也是由缓存抽象层完成数据源和缓存数据的更新
    在这里插入图片描述

③Write Behind Caching Pattern (异步缓存写入)

Write Behind则是只更新缓存,不直接更新数据库,通过批量异步的方式来更新数据库。

在这里插入图片描述

缓存与数据库双写一致

核心思路如下:

根据 id 查询时,如果缓存未命中,则查询数据库,将数据库结果写入缓存,并设置超时时间

根据 id 修改时,先修改数据库,再删除缓存

保持最终一致性

①. 采用延时双删策略
在这里插入图片描述
伪代码如下

public void write(String key,Object data){
   
     redis.delKey(key);
     db.updateData(data);
     Thread.sleep(500);
     redis.delKey(key);
 }

具体的步骤就是:

1. 先删除缓存;

  1. 再写数据库;
  2. 休眠500毫秒;
  3. 再次删除缓存。

这个休眠时间 = 读业务逻辑数据的耗时 + 几百毫秒(redis和数据库主从同步的耗时)。 为了确保读请求结束,写请求可以删除读请求可能带来的缓存脏数据。

删除缓存重试机制

  • 不管是延时双删还是Cache-Aside的先操作数据库再删除缓存,如果第二步的删除缓存失败呢,删除失败会导致脏数据。
  • 删除失败就多删除几次呀,保证删除缓存成功。

在这里插入图片描述

除缓存重试机制

1. 写请求更新数据库

  1. 缓存因为某些原因,删除失败
  2. 把删除失败的key放到消息队列
  3. 消费消息队列的消息,获取要删除的key
  4. 重试删除缓存操作
    在这里插入图片描述

秒杀场景下缓存一致性问题

减库存的方式

电商场景下的购买过程一般分为两步:下单和付款。“提交订单”即为下单,“支付订单”即为付款。

减库存方式基本有以下几种方式

1. 下单减库存。买家下单后,扣减商品库存。

2. 付款减库存。买家下单后,并不立即扣减库存,而是等到付款后才真正扣减库存。但因为付款时才减库存,如果并发比较高,可能出现买家下单后付不了款的情况,因为商品已经被其他人买走了。

3. 预扣库存。买家下单后,库存为其保留一定的时间(如 15 分钟),超过这段时间,库存自动释放,释放后其他买家可以购买。

下单减库存

优势:用户体验最好。下单减库存是最简单的减库存方式,也是控制最精确的一种。下单时可以直接通过数据库事务机制控制商品库存,所以一定不会出现已下单却付不了款的情况。

劣势:可能卖不出去。正常情况下,买家下单后付款概率很高,所以不会有太大问题。但有一种场景例外,就是当卖家参加某个促销活动时,竞争对手通过恶意下单的方式将该商品全部下单,导致库存清零,那么这就不能正常售卖了。恶意下单的人是不会真正付款的,这正是 “下单减库存” 的不足之处。

付款减库存

优势:一定实际售卖。“下单减库存” 可能导致恶意下单,从而影响卖家的商品销售, “付款减库存” 由于需要付出真金白银,可以有效避免。

劣势:用户体验较差。用户下单后,不一定会实际付款,假设有 100 件商品,就可能出现 200 人下单成功的情况,因为下单时不会减库存,所以也就可能出现下单成功数远远超过真正库存数的情况,这尤其会发生在大促的热门商品上。如此一来就会导致很多买家下单成功后却付不了款,购物体验自然是比较差的。

预扣库存

优势:缓解了以上两种方式的问题。预扣库存实际就是“下单减库存”和 “付款减库存”两种方式的结合,将两次操作进行了前后关联,下单时预扣库存,付款时释放库存。

劣势:并没有彻底解决以上问题。比如针对恶意下单的场景,虽然可以把有效付款时间设置为 10 分钟,但恶意买家完全可以在 10 分钟之后再次下单。

实际如何减库存

业界最为常见的是预扣库存。无论是外卖点餐还是电商购物,下单后一般都有个 “有效付款时间”,超过该时间订单自动释放,这就是典型的预扣库存方案。

预扣库存还需要解决恶意下单和避免超卖的问题。

恶意下单

结合安全和反作弊措施来制止。

  • 识别频繁下单不付款的买家并进行打标,这样可以在打标买家下单时不减库存
  • 为大促商品设置单人最大购买件数,一人最多只能买 N 件商品
  • 对重复下单不付款的行为进行次数限制阻断。

    避免超卖

对于普通商品,秒杀只是一种大促手段,即使库存超卖,商家也可以通过补货来解决。而对于一些商品,秒杀作为一种营销手段,完全不允许库存为负,也就是在数据一致性上,需要保证大并发请求时数据库中的库存字段值不能为负。

  • 通过事务来判断,即保证减后库存不能为负,否则就回滚。
  • 直接设置数据库字段类型为无符号整数,这样一旦库存为负就会在执行 SQL 时报错。
  • 使用 CASE WHEN 判断语句:UPDATE item SET inventory CASE WHEN inventory xxx THEN inventory xxx ELSE inventory

866cf5a1baf5430a85321906f7b576fb.gif

性能的优化

库存是个关键数据,更是个热点数据。对系统来说,热点的实际影响就是 “高读” 和 “高写”,也是秒杀场景下最为核心的一个技术难题。

高并发读

秒杀场景解决高并发读问题,关键词是“分层校验”。在读链路时,只进行不影响性能的检查操作,如用户是否具有秒杀资格、商品状态是否正常、用户答题是否正确、秒杀是否已经结束、是否非法请求等,而不做一致性校验等容易引发瓶颈的检查操作。直到写链路时,才对库存做一致性检查,在数据层保证最终准确性。

在分层校验设定下,系统可以采用分布式缓存甚至 LocalCache 来抵抗高并发读。即允许读场景下一定的脏数据,这样只会导致少量原本无库存的下单请求被误认为是有库存的,等到真正写数据时再保证最终一致性,由此做到高可用和一致性之间的平衡。

分层校验的核心思想是:不同层次尽可能过滤掉无效请求,只在“漏斗” 最末端进行有效处理,从而缩短系统瓶颈的影响路径。

高并发写

缓存

秒杀商品和普通商品的减库存是有差异的,核心区别在数据量级小、交易时间短,如果减库存逻辑非常单一的话,可以直接在一个带有持久化功能的缓存中进行减库存操作。

如果有比较复杂的减库存逻辑,或者需要使用到事务,那就必须在数据库中完成减库存操作。

优化DB性能

库存数据落地到数据库实现其实是一行存储(MySQL),因此会有大量线程来竞争 InnoDB 行锁。但并发越高,等待线程就会越多,TPS 下降,RT 上升,吞吐量会受到严重影响。

排队

通过缓存加入集群分布式锁,从而控制集群对数据库同一行记录进行操作的并发度,同时也能控制单个商品占用数据库连接的数量,防止热点商品占用过多的数据库连接。

006HJgYYgy1ft42gwg5hog306y06yjwa.gif

如果这篇【文章】有帮助到你💖,希望可以给我点个赞👍,创作不易,如果有对Java后端或者对spring感兴趣的朋友,请多多关注💖💖💖
👨‍🔧 个人主页 : 阿千弟

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
13天前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
|
15天前
|
存储 缓存 NoSQL
【赵渝强老师】基于Redis的旁路缓存架构
本文介绍了引入缓存后的系统架构,通过缓存可以提升访问性能、降低网络拥堵、减轻服务负载和增强可扩展性。文中提供了相关图片和视频讲解,并讨论了数据库读写分离、分库分表等方法来减轻数据库压力。同时,文章也指出了缓存可能带来的复杂度增加、成本提高和数据一致性问题。
【赵渝强老师】基于Redis的旁路缓存架构
|
23天前
|
缓存 NoSQL Redis
Redis 缓存使用的实践
《Redis缓存最佳实践指南》涵盖缓存更新策略、缓存击穿防护、大key处理和性能优化。包括Cache Aside Pattern、Write Through、分布式锁、大key拆分和批量操作等技术,帮助你在项目中高效使用Redis缓存。
128 22
|
22天前
|
缓存 NoSQL 中间件
redis高并发缓存中间件总结!
本文档详细介绍了高并发缓存中间件Redis的原理、高级操作及其在电商架构中的应用。通过阿里云的角度,分析了Redis与架构的关系,并展示了无Redis和使用Redis缓存的架构图。文档还涵盖了Redis的基本特性、应用场景、安装部署步骤、配置文件详解、启动和关闭方法、systemctl管理脚本的生成以及日志警告处理等内容。适合初学者和有一定经验的技术人员参考学习。
121 7
|
26天前
|
存储 缓存 监控
利用 Redis 缓存特性避免缓存穿透的策略与方法
【10月更文挑战第23天】通过以上对利用 Redis 缓存特性避免缓存穿透的详细阐述,我们对这一策略有了更深入的理解。在实际应用中,我们需要根据具体情况灵活运用这些方法,并结合其他技术手段,共同保障系统的稳定和高效运行。同时,要不断关注 Redis 缓存特性的发展和变化,及时调整策略,以应对不断出现的新挑战。
62 10
|
26天前
|
缓存 监控 NoSQL
Redis 缓存穿透的检测方法与分析
【10月更文挑战第23天】通过以上对 Redis 缓存穿透检测方法的深入探讨,我们对如何及时发现和处理这一问题有了更全面的认识。在实际应用中,我们需要综合运用多种检测手段,并结合业务场景和实际情况进行分析,以确保能够准确、及时地检测到缓存穿透现象,并采取有效的措施加以解决。同时,要不断优化和改进检测方法,提高检测的准确性和效率,为系统的稳定运行提供有力保障。
48 5
|
26天前
|
缓存 监控 NoSQL
Redis 缓存穿透及其应对策略
【10月更文挑战第23天】通过以上对 Redis 缓存穿透的详细阐述,我们对这一问题有了更深入的理解。在实际应用中,我们需要根据具体情况综合运用多种方法来解决缓存穿透问题,以保障系统的稳定运行和高效性能。同时,要不断关注技术的发展和变化,及时调整策略,以应对不断出现的新挑战。
43 4
|
1月前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(一)
数据的存储--Redis缓存存储(一)
|
1月前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(二)
数据的存储--Redis缓存存储(二)
数据的存储--Redis缓存存储(二)
|
1月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
77 6
下一篇
无影云桌面