Redis+分布式+秒杀

聊一下MySQL

关于mysql关系型数据库的一些分析:

1、从性能上:如果查询结果不是很频繁变动的SQL语句,我们就没有必要每次都去查询数据库,可以把这种数据放在基于缓存的数据库中,这样不仅提升了查询效率还分担了数据库压力。

2、从并发上:在大并发的情况下(比如618秒杀活动,你敢让千万级的请求直接打到数据库上吗?)所有的请求直接访问数据库,数据库就由可能造成宕机,可以让这些高并发瞬时的请求从数据库分离出来,找一个适合处理高并发的来处理这些请求。

那就是Redis!!!

是什么?

  • 基于内存的K/V存储中间件(关于K/V你还能想到谁?)
  • NoSQL(非关系型)数据库

干啥用?

  • 缓存

(将热点数据放到内存中,设置内存的最大使用量以及淘汰策略来保证缓存的命中率)

  • 设置定时过期数据
  • 分布式锁

(在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。可以使用 Redis 自带的 SETNX 命令实现分布式锁)

  • 抽奖功能
  • 实现排行榜
  • .......

面试题:1、redis常见的数据结构有哪些?

2、Redis持久化了解么?

秒杀场景

618预热早已开启,其中必不可少的秒杀是一个非常典型的活动场景。比如,在双 11、618 等电商促销活动中,都会有秒杀场景。秒杀场景的业务特点是限时限量,业务系统要处理瞬时的大量高并发请求。在秒杀活动中,大量用户在同一时间窗口内抢购限量商品,这往往会给系统带来极高的并发压力。使用传统的关系型数据库来处理并发请求往往会导致性能瓶颈和系统崩溃。而Redis作为一种高性能的内存数据库,能够快速处理大量的读写请求,非常适合用于秒杀场景。

秒杀的特征一:瞬时并发访问量非常高。一般数据库只能支撑千级别的并发请求,而redis的并发处理能力能达到万级别,甚至更高。在秒杀时,我们需要使用redis拦截大部分请求,避免大量请求直接发送给数据库,造成数据库宕机。

秒杀的特征二:读多写少,都是简单的查询操作。对于简单的查询操作并且结果相对固定我们可以先将其查询出来放入redis中,减轻数据库的压力。秒杀活动中只有少部分用户能成功下单,所以,商品库存查询操作(读操作)要远多于库存扣减和下单操作(写操作)。

秒杀的特征三:实时性和响应时间要求。 秒杀活动通常是实时进行的,用户希望尽快得知抢购结果。系统需要具备高性能和低延迟,及时响应用户的请求。

三个阶段

秒杀前

秒杀前,用户会不断的刷新商品详情页,那么就会导致对详情页的请求量急剧增加。这个阶段的应对方案,一般是尽量把商品详情页的页面元素静态化,然后使用 CDN(CDN技术的关键思想是通过将内容缓存到离用户更近的地方,减少用户从原始服务器获取内容的距离和时间) 或是浏览器把这些静态化的元素缓存起来。这样一来,秒杀前的大量请求可以直接由 CDN 或是浏览器缓存服务,不会到达服务器端了。

秒杀时

用户点击秒杀按钮---->大量并发请求查询库存--->有库存(下单){没有则返回,可能会点击其他秒杀按钮,继续查询库存}--->库存扣减---->生成实际订单---->后续处理(物流、订单支付等)

这个阶段的操作是:库存查验、库存扣减、订单处理。而最大的并发力都在库存查验操作上。这个阶段为了支撑大量高并发的库存查验请求,我们需要在这个环节使用 Redis 保存库存量,这样一来,请求可以直接从 Redis 中读取库存并进行查验。

为什么订单处理操作可以在数据库中执行?而库存扣减操作不能在数据库中执行?

1、数据可靠性:数据库是一种持久化存储的解决方案,能够提供数据的持久性和可靠性。将订单处理操作放在数据库中执行可以确保订单数据的安全存储,即使在系统出现异常或故障的情况下,订单数据也能够得到

保护,不会丢失或损坏。(不要把鸡蛋放在同一个篮子里)

2、在数据库中进行库存扣减操作会带来额外的开销。我们已经事先在redis中保存好了库存量,如果交给数据库来处理扣减,那么就需要数据库将最新的值再同步到redis中,这样反而繁琐也带来了额外的开销。

3、可能会出现超售的情况。数据库的处理速度很慢,而秒杀又是一个快速高并发的场景,可能数据库更新完一个库值,秒杀就结束了,可能会导致用户查询到旧的库存值,再进行下单,出现超售的情况。

所以需要在redis中把库存扣减和库存查验两个操作一气呵成,实现原子操作。

秒杀后

用户量减少,服务器完全可以独立进行订单处理等操作。

实现

我们可以使用Redis的原子操作和分布式锁来支撑秒杀时的场景。(本文介绍分布式锁)

简单聊聊分布式

简单理解:类比卫生间的隔间:

  1. 隔离性: 卫生间的隔间将每个使用者隔离开来,使每个人都能独立使用空间,不会相互干扰。同样,分布式系统中的各个节点也是相互隔离的,它们可以独立运行,不会相互影响。
  2. 资源共享: 卫生间的隔间提供共享的基础设施,如水源和排水管道等。类似地,分布式系统中的节点可以共享一些资源,如共享存储、共享数据库等。
  3. 容错性: 如果一个卫生间隔间出现故障或需要维护,其他隔间仍然可以继续使用。同样,分布式系统中的节点之间可以具备容错能力,如果某个节点发生故障,其他节点可以接替其工作。
  4. 扩展性: 如果需要更多的卫生间隔间,可以增加更多的隔间来满足需求。同样,分布式系统可以通过增加更多的节点来实现扩展性,以处理更大的负载和流量。

Redis分布式锁(秒杀场景)

先让客户端向 Redis 申请分布式锁,只有拿到锁的客户端才能执行库存查验和库存扣减。这样一来,大量的秒杀请求就会在争夺分布式锁时被过滤掉。因为多个并发客户端只有一个客户端能够拿到锁,已经保证了客户端并发访问的互斥性。大部分秒杀请求本身就会因为抢不到锁而被拦截。

为啥要实现分布式锁:

  • 在有限的资源情况下,控制同一时间(段)只有某些线程(用户/服务器)能访问到资源。(比如秒杀时)
  • 单个锁只对单个jvm有限(好比用厕所只能用专属于自己的哪个)

关键:怎么保证同一时间内只有一个任务抢到锁。

核心思想是:先来的人先把数据改成自己的标识(ip)后来的人发现标识已存在,就抢锁失败,继续等待,等先来的人执行方法结束,把标识清空,其他的人继续抢锁。(类比抢厕所/上厕所 )

注意事项:

  • 要注意解锁(你不可能一直占着厕所吧!!!)。
  • 一定要注意加上过期时间(否则如果因为服务器挂掉,锁就会一直存在了)。

使用分布式锁可能存在的问题

1、锁提前过期:分布式锁设置的时间提前过期,会导致其他方法加入一块同时执行。(好比你拉*没拉完,外面大哥把厕所门给撬开了)导致多个方法同时执行了。

2、还有可能导致连锁效应(解锁时不小心释放掉别人的锁)同样导致多个方法同时执行。

3、解锁的时候,判断好了是自己的锁,但是当要执行解锁的时候,就在这个时刻,自己的锁过期了(不需要删了)有其他的方法见缝插针进来了,导致A删了B的锁。(就像是你用完厕所,你自己的门锁时间过期开了,你手里还有把解锁的“钥匙”,结果你打开了刚进来的大哥的锁)这里其实是破坏了原子性。(需要保证A的操作是原子性的,不能有其他操作打断。(也就是说A的上锁和解锁中间不能有其他的锁操作)跟操作系统的PV操作好像)。

4、锁提前过期,任务还没执行完,可以进行续期。(就像你上厕所,外面大哥等了你10min,结果你还没完事,然后你跟大哥说再给我10min)进行续期。

关于redis在秒杀场景中的应用还有很多,这只是一丢丢~

场景题

1、如何防止超卖问题?
分布式锁:在秒杀场景中,可以使用分布式锁来控制对库存的并发访问。只有获取到锁的请求才能进行库存扣减操作,避免多个请求同时进行库存扣减。

2、如何保证订单的顺序和可靠性?
在秒杀场景中,可以使用Redis等分布式锁来保证同一时刻只有一个请求能够创建订单。

3、如何解决重复下单的问题?
幂等性校验:在接收到订单请求后,在处理订单之前进行幂等性校验。可以通过订单号、用户ID、商品ID等唯一标识来判断是否已经存在相同的订单,如果存在则认为是重复下单,进行相应的处理,如返回已存在订单的信息或提示用户下单失败。

4、做了什么限流削峰的措施?

5、如果缓存中的数据突然失效,导致请求全部打到了数据库,怎么办?

6、秒杀系统面临的问题有哪些?
热点数据预热:在秒杀活动开始之前,预先将热门商品或活动相关的数据加载到缓存中,即进行热点数据的预热。这样可以在活动期间减少缓存失效的情况,降低对数据库的压力。

........

博客参考

实践篇(11)Redis支撑秒杀场景的关键技术

posted @ 2023-05-29 19:27  有点儿意思  阅读(266)  评论(0编辑  收藏  举报