redis秒杀系统的实现

目录
  • 1.如何设计一个秒杀系统
  • 2.秒杀流程
    • 2.1 前端处理
    • 2.2 后端处理
  • 3.超卖问题
  • 4.总体思路

1.如何设计一个秒杀系统

在设计任何系统之前,我们首先都需要先理解秒杀系统的业务背景

下面我简单的举一个例子:

在某个时间点,某某电商网站要低价卖某件商品,而且限量1千件,抢购人数超过数十万人。
所以我们面临的第一个秒杀的问题就是:时间极短,然后瞬间流量非常大
我们的系统必须保证秒杀抢购的结果不出错,达到抢购的预期目的。
而且秒杀库存的实现也需要保障秒杀结果的准确性。
总结几个特点就是:

  • 高性能:秒杀中有大量的并发读写,所以需要使系统能支撑起高并发访问,这是一个关键点。
  • 高可用:藐视瞬间流量非常大,很有可能会导致系统宕机,所以需要从各方面保证系统的可用性。
  • 一致性:由于秒杀请求量非常大,此时就需要我们的秒杀结果要准确。因为一旦出错,那么波及面会非常广,损失非常大。

2.秒杀流程

我们先从秒杀的入口开始说起
在秒杀入口的地方会有这些问题需要解决:

2.1 前端处理

静态资源处理

秒杀商品一般都会包含很多静态资源,所以这些图片什么的静态资源一定要放到CDN(Content Delivery Network,即内容分发网络),能放的尽量放进去。让秒杀时后端服务器的压力尽可能小。
说到此处,我重点描述讲解CDN

为了能在传统IP网上发布丰富的宽带媒体内容,提出在现有互联网基础上建立一个内容分发平台专门为网站提供服务。由于CDN是为加快网络访问速度而被优化的网络覆盖层,因此被形象地称为“网络加速器”。
首先要说的是应用服务器和资源服务器应该解耦,也就是应用服务器只处理逻辑,而资源服务器存放内容或者叫资源。

  • CDN专注于「内容」,也就是CDN的C所代表的Content,专注于静态资源的分发和访问,比如一张图片,一个文本文件,一个视频,一个CSS,一个JS等等,任何以文件形式存储的,为了提高在互联网上的访问速度和质量,都可以将这个资源部署在CDN这个网络上。
  • CDN动作是「分发」,也就是如何让刚才提到的那些「内容」快速的部署在这个网络中,从而快速为用户服务,其实还有一层更重要的含义是用户的快速访问与就近接入,分发的目的是为了用户更好的体验。
  • CDN落定于「网络」,是部署于全国或者全世界的一大堆服务器,这些服务器基于当前互联网的基础架构在其上层再构成一个网络,这个网络专为资源分发而生。

那CDN的原理是什么呢?为什么用户可以接入离他最近的服务器呢?
主要是利用了DNS来判断用户位置,再返回给用户最近的机房的服务器的资源地址。
下面我再通俗的解释一下:
肯德基的总部在美国,可是你家楼下也有一家肯德基,并且汉堡包是一模一样的,这就是CDN(这个比喻来自知乎,觉得非常的恰当)。肯德基部署了很多个CDN在世界各地提供服务,用户都是找到最近的店,这个计算过程就是刚才讲的「就近接入」。

什么是CDN的调度呢?

(1)DNS调度是最常用和最通用的调度方案,缺点是存在DNS劫持的风险,调度的精确度也会差一些;
(2)302调度非常适合用在大文件下载和视频点播这两个应用场景,优点是可以提高调度的精确度,缺点是将会增加首包的时延(在大文件下载和视频点播场景下对首包时延不太敏感,而对调度精确度要求更高)
(3)HTTPDNS调度的优点是有较高的安全性(可以规避DNS劫持风险)和调度精确度,但是有个很大的缺点,需要客户端提供支持(例如在手机APP上嵌入SDK),通用性较差。

通俗来讲:

在一个商圈有两家肯德基,有一家组织活动,鸡腿随便吃,所以顾客全部涌到这家店,已经水泄不通,另一家店则门可罗雀。这个时候CDN的调度功能就要发挥作用了,另一家店也发布了一个消息说,买一个汉堡,打五折。这个时候,在第一家店抢不上鸡腿的顾客,马上跑去了第二家店,这个时候两个店的流量处于均衡状态。这就是CDN的调度。

恶意访问行为的处理

当我们推出秒杀活动后,还需要考虑黄牛党们开发出的各种秒杀器,可以自动填单,自动回答各种问题,以及自动模拟点击等,令我们防不胜防。
针对这些我们可以通过各种工作来限制和识别这些恶意访问。

  • 例如限制IP的提交次数
  • 提高各种动态验证码及问题的难度
  • 增加黑名单账户

秒杀链接隐藏

如果稍微懂点程序的人可以提前拿到秒杀链接,那么就可以通过程序在最快的时间发起秒杀请求,这样人家就可以拿到大部分商品了。为了防止这一点,可以使秒杀链接动态化。使用MD5算法等加密随机字符串作为URL的一部分,秒杀开始后才将连接放出来,同时在后台进行校验,此时已经可以防止一大批的羊毛党了。

前端限流

可以在秒杀按钮点击之后灰掉几秒钟,几秒钟之内只能点击一次。
可以使用Nginx用户请求到Nginx的时候将流量分散到多个服务器上,而且也可以针对用户进行一些过滤,将一些请求拦截,保证后端的稳定性。比如1万个商品,最多放进来10万个请求就可以了,其他的用户就只能等着静态页面喽。同时也可以在秒杀预约的时候随机发放一些token,只有拥有这些token的客户才有可能抢购成功。
同时在分布式的架构下,我们也可以通过gateway,redis+lua或者nginx进行限流

2.2 后端处理

后端限流

如果服务的流量到达最大值的时候,新的请求就不能再进来了。
而服务宕机的时候也需要引导请求到备用服务器上面,然后返回一些静态提示页面等。
隔离就要求,秒杀的服务单独部署,只承担其秒杀的单一职责,即使出问题,也不会影响其他的服务。

削峰

秒杀流量在某一个时间点非常高,那么我们让瞬间进来的流量进到一个缓冲池,然后再进行平缓处理。比较多用到的方案就是使用消息队列来处理。

库存预热

由于秒杀的商品的数量一般都是提前已知的,这时我们可以提前将商品的一些数据提前加载到缓存中。并且可以将商品分区来进行秒杀,根据每个大区的用户数量以及活跃程度,为每个大区分配单独的秒杀商品数量。这样也可以分散服务器压力。

使用缓存

高并发的情况下必然会遇到缓存雪崩,缓存击穿,缓存穿透等问题。而且秒杀的场景是读多写少,使用Redis作为缓存非常合适,为了避免单台Redis服务器出问题,导致缓存击穿等问题,升级使用Redis集群是一个比较好的方案。提升可用性的性能也可以大大提高。
下面我简单说一下缓存雪崩,缓存击穿以及缓存穿透

首先我们要先了解一下缓存的处理流程
前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果。

知道什么是缓存之后我们重点来了解一下这三个名次具体指什么,以及如何去解决
缓存穿透
描述:缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
解决方案:

  • 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
  • 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击

缓存击穿
描述: 缓存击穿是指缓存中没有数据但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。
解决方案:

  • 设置热点数据永远不过期。
  • 加互斥锁,互斥锁参考代码如下

我简单解释一下代码思路:
我们首先从缓存中获取数据,如果数据不存在,我们则去获取锁,这把锁 只需要能够互斥,可重入即可,最简单的就是redis的setnx来实现,获取锁资源以后,从数据库读取数据,同时将数据更新至缓存,然后释放锁;如果获取锁资源失败,我们就让其隔一段时间之后重新尝试去获取锁资源。

缓存雪崩
缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。
和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案:

  • 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
  • 如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
  • 设置热点数据永远不过期。

3.超卖问题

秒杀中一个重要的点就是超卖问题,由于抢购人数多,流量也很大,但是也不能卖多了。
目前常见的解决方案就是:

1.数据库要加唯一索引,减库存的时候要先进行库存数量判断等,数据库锁,加版本号的乐观锁方式等等。2

.采用Redis来维护库存,由于秒杀活动可以预先知道商品的数量,所以可以提前将商品的数据加载到Redis中,如果Redis的库存不足的话则秒杀失败。

3.生成订单的时候将请求放到服务端的异步队列中去处理,可以使用Redis的队列,或者MQ均可。

4.总体思路

其实秒杀方案的总体思路也很简单:

1.尽可能的将请求拦截在上游;

2.后端均要处理限流;

3.尽量减少请求到数据库;

4.多利用缓存;

5.使用异步操作-可以使用队列等;

6.秒杀服务单一职责;

7.尽早失败,让秒杀请求返回

到此这篇关于redis秒杀系统的实现的文章就介绍到这了,更多相关redis 秒杀系统内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • redis使用watch秒杀抢购实现思路

    本文实例为大家分享了redis使用watch秒杀抢购的具体代码,供大家参考,具体内容如下 1.使用watch,采用乐观锁 2.不使用悲观锁,因为等待时间非常长,响应慢 3.不使用队列,因为并发量会让队列内存瞬间升高 代码: import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import redis.clients.jedis.Jedis; /** * redis测试抢购 * *

  • Redis瞬时高并发秒杀方案总结

    1.Redis 丰富的数据结构(Data Structures) 字符串(String) Redis字符串能包含任意类型的数据;: 一个字符串类型的值最多能存储512M字节的内容: 利用INCR命令簇(INCR, DECR, INCRBY)来把字符串当作原子计数器使用: 使用APPEND命令在字符串后添加内容. 列表(List) Redis列表是简单的字符串列表,按照插入顺序排序: 你可以添加一个元素到列表的头部(左边:LPUSH)或者尾部(右边:RPUSH): 一个列表最多可以包含232-1个

  • Redis锁完美解决高并发秒杀问题

    目录 1 单机环境下的锁 2 分布式情况下使用Redis锁. 3 一台服务宕机,导致无法释放锁 4 给每一把锁加上过期时间 5延长锁的过期时间,解决锁失效 6 使用Redisson简化代码 场景:一家网上商城做商品限量秒杀. 1 单机环境下的锁 将商品的数量存到Redis中.每个用户抢购前都需要到Redis中查询商品数量(代替mysql数据库.不考虑事务),如果商品数量大于0,则证明商品有库存.然后我们在进行库存扣减和接下来的操作.因为多线程并发问题,我们不得不在get()方法内部使用同步代码块

  • Redis中的String类型及使用Redis解决订单秒杀超卖问题

    本系列将和大家分享Redis分布式缓存,本章主要简单介绍下Redis中的String类型,以及如何使用Redis解决订单秒杀超卖问题. Redis中5种数据结构之String类型:key-value的缓存,支持过期,value不超过512M. Redis是单线程的,比如SetAll & AppendToValue & GetValues & GetAndSetValue & IncrementValue & IncrementValueBy等等,这些看上去像是组合命

  • 使用Redis实现秒杀功能的简单方法

    1. 怎样预防数据库超售现象 设置数据库事务的隔离级别为Serializable(不可用) Serializable就是让数据库去串行化的去执行事务,一个事务执行完才能去执行下一个事务,效率太慢 在数据表上设置乐观锁字段,例如设置版本号(version) 不同事务在执行更新操作时,需要先判断一下版本号是否已被修改 代码实现乐观锁流程 1.1. 什么表需要设置乐观锁 出现同时修改同一条记录的业务,相应的数据表要设置乐观锁 不会出现同时修改同一记录的数据库,就不需要设置乐观锁 2. 利用Redis防

  • Redis使用watch完成秒杀抢购功能的代码

    redis使用watch完成秒杀抢购功能: 使用redis中两个key完成秒杀抢购功能,mywatchkey用于存储抢购数量和mywatchlist用户存储抢购列表. 它的优点如下: 1. 首先选用内存数据库来抢购速度极快. 2. 速度快并发自然没不是问题. 3. 使用悲观锁,会迅速增加系统资源. 4. 比队列强的多,队列会使你的内存数据库资源瞬间爆棚. 5. 使用乐观锁,达到综合需求. 我觉得以下代码肯定是你想要的. <?php header("content-type:text/htm

  • redis秒杀系统的实现

    目录 1.如何设计一个秒杀系统 2.秒杀流程 2.1 前端处理 2.2 后端处理 3.超卖问题 4.总体思路 1.如何设计一个秒杀系统 在设计任何系统之前,我们首先都需要先理解秒杀系统的业务背景 下面我简单的举一个例子: 在某个时间点,某某电商网站要低价卖某件商品,而且限量1千件,抢购人数超过数十万人.所以我们面临的第一个秒杀的问题就是:时间极短,然后瞬间流量非常大我们的系统必须保证秒杀抢购的结果不出错,达到抢购的预期目的.而且秒杀库存的实现也需要保障秒杀结果的准确性.总结几个特点就是: 高性能

  • springboot集成redis实现简单秒杀系统

    本文实例为大家分享了springboot集成redis实现简单秒杀系统的具体代码,供大家参考,具体内容如下 项目是有地址的,我会放到文章的最后面 1. 直接service,我们会介绍两种秒杀模式 public interface GoodsService { /** * 通过lua脚本实现的秒杀 * @param skuCode 商品编码 * @param buyNum 购买数量 * @return 购买数量 */ Long flashSellByLuaScript(String skuCode

  • 解密Redis助力双11背后电商秒杀系统(推荐)

    背景 秒杀活动是绝大部分电商选择的低价促销,推广品牌的方式.既可以给平台带来用户量,还可以提高平台知名度.一个好的秒杀系统,可以提高平台系统的稳定性和公平性,获得更好的用户体验,提升平台的口碑,从而提升秒杀活动的最大价值. 本文讨论云数据库Redis版缓存设计高并发的秒杀系统. 秒杀的特征 秒杀活动对稀少或特价的商品进行定时定量售卖,吸引成大量的消费者进行抢购,但又只有少部分消费者可以下单成功.因此,秒杀活动将在一定时间内产生比平时大几十倍倍,上百倍的页面访问流量和下单请求流量. 秒杀活动可以分

  • SpringBoot之使用Redis实现分布式锁(秒杀系统)

    一.Redis分布式锁概念篇 建议直接采用Redis的官方推荐的Redisson作为redis的分布式锁 1.1.为什么要使用分布式锁 我们在开发应用的时候,如果需要对某一个共享变量进行多线程同步访问的时候,可以使用我们学到的Java多线程的18般武艺进行处理,并且可以完美的运行,毫无Bug! 注意这是单机应用,也就是所有的请求都会分配到当前服务器的JVM内部,然后映射为操作系统的线程进行处理!而这个共享变量只是在这个JVM内部的一块内存空间! 后来业务发展,需要做集群,一个应用需要部署到几台机

  • 如何设计一个秒杀系统

    什么是秒杀 秒杀场景一般会在电商网站举行一些活动或者节假日在12306网站上抢票时遇到.对于电商网站中一些稀缺或者特价商品,电商网站一般会在约定时间点对其进行限量销售,因为这些商品的特殊性,会吸引大量用户前来抢购,并且会在约定的时间点同时在秒杀页面进行抢购. 秒杀系统场景特点 秒杀时大量用户会在同一时间同时进行抢购,网站瞬时访问流量激增. 秒杀一般是访问请求数量远远大于库存数量,只有少部分用户能够秒杀成功. 秒杀业务流程比较简单,一般就是下订单减库存. 秒杀架构设计理念 限流: 鉴于只有少部分用

  • 限时抢购秒杀系统架构分析与实战

    1 秒杀业务分析 正常电子商务流程 (1)查询商品:(2)创建订单:(3)扣减库存:(4)更新订单:(5)付款:(6)卖家发货 秒杀业务的特性 (1)低廉价格:(2)大幅推广:(3)瞬时售空:(4)一般是定时上架:(5)时间短.瞬时并发量高: 2 秒杀技术挑战 假设某网站秒杀活动只推出一件商品,预计会吸引1万人参加活动,也就说最大并发请求数是10000,秒杀系统需要面对的技术挑战有: 对现有网站业务造成冲击 秒杀活动只是网站营销的一个附加活动,这个活动具有时间短,并发访问量大的特点,如果和网站原

  • 如何通过SpringBoot实现商城秒杀系统

    这篇文章主要介绍了如何通过SpringBoot实现商城秒杀系统,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 学习自:地址 1.主要流程 1.1数据库: 1.2 环境 window下:Zookeeper,Redis,rabbitmq-server.jdk1.8以上. 1.3 介绍 这里只做秒杀部分功能,其他功能不会涉及.项目运行后可访问秒杀商品页面 当用户没登陆,点击详情会跳转到登陆页面. 用户登陆后可以查看商品的详情并进行抢购. 注意,用户对

  • 秒杀系统Web层设计的实现方法

    秒杀系统Web层设计的实现方法 一.Restful接口设计 使用资源+名词的方式来为url链接命名.例如: 访问详情页的链接可以是: seckill/{seckillId}/detail 二.SpringMVC配置 1.首先要在web.xml中配置中央控制器. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&q

  • SpringBoot使用Redisson实现分布式锁(秒杀系统)

    前面讲完了Redis的分布式锁的实现,接下来讲Redisson的分布式锁的实现,一般提及到Redis的分布式锁我们更多的使用的是Redisson的分布式锁,Redis的官方也是建议我们这样去做的.Redisson点我可以直接跳转到Redisson的官方文档. 1.1.引入Maven依赖 <dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter&l

  • Java秒杀系统:web层详解

    目录 设计Restful接口 SpringMVC 项目整合SpringMVC 使用SpringMVC实现Restful接口 逻辑交互 身份认证 计时面板 总结 设计Restful接口 根据需求设计前端交互流程. 三个职位: 产品:解读用户需求,搞出需求文档 前端:不同平台的页面展示 后端:存储.展示.处理数据 前端页面流程: 详情页流程逻辑: 标准系统时间从服务器获取. Restful:一种优雅的URI表述方式.资源的状态和状态转移. Restful规范: GET 查询操作 POST 添加/修改

随机推荐