• 秒杀系统个人总结


    秒杀系统架构

    秒杀系统是一个并发量要求高、负载均衡要求高的、业务场景简单但是逻辑稍微复杂的系统,所以经常会作为面试高级后端开发的面试题。主要考察的就是对问题的拆解、分析、解决,以及架构设计的能力。

    基础架构

    • 客户端

      • web 浏览器 / app
    • 负载均衡层

      • Nginx
    • web 层

      • 接收 Http 请求
      • 做限流
        • 分布式限流
        • id 限流
    • service 层

      • 库存操作
      • 生成订单
    • 数据存储层

      • mq + mysql

    客户端

    服务端是一个潜在的考察点,还是有很多问题需要解决的。有些网上给出的设计方案没有对这块做详细考虑。

    • 客户端限流(在浏览器上行不通)

      客户端做一定控制来限流(比如概率),防止刷单,减少成功次数,显示在排队,实际上没发网络请求

    • 前端展示

      秒杀按钮展示要有个定时器,涉及到前后端时钟同步的问题

      • 校对时间差

        获取服务端时间,客户端时间 - 服务端时间,比较得到差值,用这种方法来同步。然而注意到网络是有开销的,这个开销需要想办法消除。否则这种毫秒级甚至秒级的时间差,会影响到秒杀的公平性。

        • 发送更轻量级的服务响应
        • 优化代码,使客户端和服务端计算时间的流程很短
        • 回调计算时间先执行

        如果这个同步是很长时间之前同步的呢,可能时间过了很久后已经相差较多了。

        • 定时同步,半小时一次

        如果客户修改系统时间怎么办

        • 记录客户端的周期时间序列(这个周期可以设置的短一些,比如10秒这样子),第一次为基准,先做客户端与服务端同步,得到差值 T
        • 在第二个周期,计算两个时刻的时间差,再减去周期时间,就是相差的时间,如果在某一个很小的范围内,说明没有问题,如果不在范围内,说明可能修改了时间,那么修改 T 为 T + 差值

    web 层

    这一层要考虑限流问题,以及防止恶意刷量的问题。首先限流要尽量在上层去做,以最大程度减少后端系统的压力。其次,要避免用户找到url,不停的大量发送网络请求,或者在活动前就发送,这样也是有问题的。

    • 限流

      这属于分布式限流,一般采用 redis 来做限流,可以用令牌桶来做

    • 防止提前刷 url

      这个可以在服务端根据系统时间来决定要不要处理,也可以用一个随机的网址来保证无法模拟 url 请求(这个点还比较模糊)
      而且这里涉及到服务端各服务器的时钟同步

    • 同一个 url

      这里可以用 redis 记录或者本地记录来进行计数过滤,保证用户每秒发送请求响应次数不超过一个阈值

    service 层

    • 如果有库存,并且拿到了资源,再生单的逻辑顺序
    • 解决并发问题的思路
        • 悲观锁

          性能比较差

        • 乐观错

          性能好些

      • 缓存

        缓存来保存库存量,减少访问 mysql 带来的并发,用 redis 可以做到

        但是如果在拿到资格后出现问题,怎么办?在缓存里已经被减掉了,这时需要归还资格,否则卖出的数就会少,这个错误可能会出现在生单,订单入库的阶段,直到入库,这个资格才能算作彻底被消费掉

    数据存储层

    mysql 更合适,有唯一键的限制,hbase 存放海量数据

    同步还是异步的问题

    • 同步

      好处,等待结果写入库里,完全闭环

    • 异步

      可能会写入失败,丢失订单信息,因为订单详情是要尽快展示给用户的,所以一旦失败,该取消这次秒杀的结果,还是继续认为成功,是比较棘手的问题。异步出错了,可能可以修复,但是也可能会一直出错,重试无效。这种应该归还,然后把结果通知给用户。如果异步默认生单成功,但是怎么也写不进去,那就会有问题了。(这块每太想清楚)

      先说说异步做法

      • 交由本地线程池处理

        占用 service 层资源

      • 发送 kafka

        减少了 service 层资源占用,但是要保证 kafka 可靠,这里需要保证 有副本,ack -> ALL,replica 设置>1

    其他问题

    • 如何保证同一个用户只能下一个单

      • 如果是用 redis 来做

        • 那么可以在获取权限的前一层写入,做第一层判断
        • 也就是如果获取到一次资格,立马锁定,如果后面的生单失败了,再解锁
      • 如果用 mysql 来做

        • 会导致在最下层才判断出来,而前面已经拿到了资格,导致很多人没抢到,这时应该返回什么?一般返回失败,直到全局的秒杀结束,再通知结束。
    • 因为资源被占用后,后续不一定生单成功,所以如果资源没了,不应该直接展示秒杀结束

      • 要有一个全局的标识,确认秒杀结束
    • server 端时间同步

      • 服务启动时以某一个为基准就好,可以是集群中的,也可以是集群外的
  • 相关阅读:
    web安全——代理(nginx)
    2016年3-7月书单推荐
    web安全——系统(Linux)
    web安全——防火墙
    web安全——简介
    系统安全扫描工具(appscan)的扫描类型小记
    知识管理,让生活更美好
    亚马逊如何变成 SOA(面向服务的架构)
    徐小平:关了公司以后,我有这些话要对你说
    网易味央第二座猪场落户江西 面积超过3300亩
  • 原文地址:https://www.cnblogs.com/43726581Gavin/p/9066053.html
Copyright © 2020-2023  润新知