美文网首页程序员Java 杂谈
设计一个秒杀系统

设计一个秒杀系统

作者: 我是曾经那个少年 | 来源:发表于2018-11-05 23:26 被阅读31次

    设计一个秒杀系统

    1 设计的架构原则

    1.1 4要1不要

    1. 尽量减少请求数量

      js,css等额外请求要少 合并请求

    2. 尽量减少请求数据

    3. 尽量减少请求路径

      用户发出去请求到返回数据过程中,经过的中间节点数要少

    4. 请求依赖要尽量少

      秒杀系统中的商品信息和用户信息是关键信息,优惠券列表,成交列表弱依赖

    5. 不要有单点

      避免服务状态华

    1.2 不同场景的架构

    秒杀系统架构1
    商品购买增加定时上架  -- 秒杀开始,才能看到按钮
    
    单独部署  不和其他业务冲突
    
    热点数据放到缓存
    
    增加秒杀答题,方式秒杀器抢单
    
    秒杀系统架构2
    页面动静分离
    
    在服务端对秒杀少商品进行缓存
    
    增加系统限流保护
    

    2 动静分离的可选方案

    2.1 为什么要考虑动静分离

    提高了单次的请求效率

    减少了没必要的请求

    2.2 怎么区分动静数据

    动静数据主要区别就是看页面中输出的数据是否和URL,浏览者,时间,地域相关,以及是否含有Cookie等私密数据。

    静态数据不是磁盘上的HTML内容,而是数据中是否有个性化的数据。

    2.3 怎么对静态数据缓存

    1. 把静态数据缓存到离用户最近的地方,例如 浏览器里,CDN,或者服务端的Cache。

    2. 静态化改造就是要直接缓存HTTP连接,WEB代理服务器根据请求URL,直接取出对应的HTTP响应头和响应体直接返回。

    3. 在系统那个部分做静态缓存?WEB服务器由于Java语言。

    2.4 怎么进行动静分离

    怎么分离动态内容:

    1. URL唯一话,每个商品的URL是独一无二的。

    2. 分离浏览者相关的因素,包括是否登录,以及登录身份,这些相关因素可以单独拆分出来,通过动态请求来获取。

    3. 分离时间因素,服务端输出的时间也应该通过动态请求获取。

    4. 异步化地域因素,请求页面上与地域相关的因素做异步式获取。

    5. 去掉Cookie。缓存的静态数据中不包含有Cookie.

    动态内容处理通用的两种方案:

    1. ESI方案,在Web代理服务器上做动态内容请求,并将请求插入静态页面中,当用户拿到页面的时候已经是一个完整的页面。

    2. CSI方案,单独发起一个异步的JavaScript请求,以向服务端获取动态内容。

    2.5 架构方案

    2.5.1 实体机单机部署

    采用一致性Hash分组的方式来提升命中率,这里将Cache分成若干组,是希望能达到命中率和访问率的平衡。

    优点:

    1. 没有网络瓶颈,而且能使用大内存。
    2. 既能提升命中率,又能减少Gzip压缩。
    3. 减少Cache失效压力,因为采用定时失效方式。
      缺点:
      运维复杂度高
    2.5.2 统一Cache层

    将单机的Cache统一分离出来,形成一个单独的Cache集群。

    优点:

    1. 可以减少多个应用接入Cache的成本,只需关注自己的Java系统就好。
    2. 易于维护。
    3. 共享内存,最大化利用内存。不同系统之间的内存可以动态切换。

    缺点:

    1. Cache层内部交换网络成为瓶颈。
    2. 缓存服务器的网卡也会成为瓶颈。
    3. 机器少,风险比较大,挂掉一台会影响很大一部分缓存数据。
    2.5.3 上CDN

    3 二八原则:有针对的处理好系统的热点数据

    3.1 热点?

    热点请求会占用大量服务器资源。

    热点操作:

    热点数据:静态热点数据(提前预测的热点数据,大数据分析热点商品,历史成交记录,用户购物车)+动态热点数据()

    3.2 发现热点数据

    3.2.1 发现静态热点数据
    1. 卖家报名的方式,然后给卖家的商品打tag,数据进行预处理,然后缓存数据。
    2. 分析买家访问的商品等,然后统计出TOP N的商品。
    3.2.2 发现动态热点数据

    系统内部秒级自动发现热点商品

    1. 构建一个异步的系统,进行收集交易链路上各个环节中的中间件热点key。如:Nginx,缓存,RPC服务框架等。
    2. 上游系统把已经发现的热点透传给下游系统,提前做好保护。

    3.3 如何处理热点数据

    1. 优化:缓存热点数据,用队列进行存储,采用LRU淘汰算法。
    2. 限制:作为一种保护机制,把热点请求限制在一个请求队列里面。防止热点数据占用太多资源。
    3. 隔离:热点数据隔离出来,不要让1%的请求影响到另外的99%。业务隔离+系统隔离+数据隔离。

    4 流量削峰

    秒杀这个场景来说,最终抢到商品的人数是固定的,所以100人和10000人发起请求的结果都是一样的,并发度越高,无效请求越多。

    4.1 为什么削峰

    服务器能处理的资源是恒定的,所以为了服务稳定,我们延缓用户请求的发出,以便减少和过滤掉一些无效的请求。

    4.2 削峰的思路

    • 排队

    把一步操作,变成二步操作,其中增加一步操作用来起到缓冲的作用。

    1. 利用消息队列,把请求缓冲起来,然后消费端异步处理请求。
    2. 利用线程池加锁等待。
    3. 先进先出内存排队算法的实现方式。
    4. 把请求序列化到文件中,然后顺序的读文件来恢复请求操作。
    • 答题

    一方面防止买家使用秒杀器在参加秒杀的时候作弊。一方面延缓请求,起到流量削峰的作用。

    image
    • 分层过滤
    image
    1. 大部分数据和流量在用户浏览器或者CDN上获取,这一层拦截大部分数据的读取。
    2. 前台系统的数据,尽量得走cache,过滤一些无效请求。
    3. 后台系统,做数据的二次校验,对系统做好保护和限流。
    4. DB数据层,完成数据的强一致性校验。

    基本原则

    1. 将动态请求的读数据缓存在Web端,过滤掉无效请求读。
    2. 对读数据不做强一致性校验,减少因为一致性校验产生瓶颈的问题。
    3. 对写数据进行基于时间的合理分片,过滤掉过期的失效请求。
    4. 对写请求做限流保护,将超出系统承载能力的请求过滤掉。
    5. 对写数据进行强一致性校验,只保留最后有效的数据。

    5 提升系统性能

    5.1 影响性能的因素

    响应时间:

    每秒请求数:(Query Per Second)

    CPU的执行时间+线程数

    线程数=2*cpu+1

    线程数=[(线程等待时间+线程CPU时间)/线程CPU时间]*CPU数量

    5.2 如何发现瓶颈

    CPU诊断工具:Jprofiler+Yourkit工具+jstack定时地打印调用栈,

    QPS达到极限时候,CPU的使用率是不是超过95%,如果没有超过,那么CPU还有提升的空间。

    5.3 如何优化系统

    1. 减少编码:
    2. 减少序列化
    3. Java极致优化 直接使用Servlet处理请求,直接输出流数据。
    4. 并发读优化 不变的信息,缓存系统内存里面,变化的信息,采用失效时间,失效之后拉取最新数据。

    6 秒杀系统 减库存设计

    6.1 减库存的几种方式

    • 下单减库存:有些人下单之后不会付款。
    • 付款减库存:买家下单之后,不能发起付款。
    • 预扣库存:买家下单之后,库存为其保留一定时间,超过这个时间,库存自动释放。在买家付款之前,系统会校验该订单的库存是否保留,如果没有保留,则再次尝试预扣,如果预扣失败,则不允许继续付款。

    6.2 数据库一致性

    • 应用程序中通过事物来判断,即保证减库存不能为负数,否则就回滚。
    • 数据库字段设置为无符号整数,小于0的时候SQL抛出异常。

    相关文章

      网友评论

        本文标题:设计一个秒杀系统

        本文链接:https://www.haomeiwen.com/subject/xazexqtx.html