GithubHelp home page GithubHelp logo

seckill's Introduction

seckill——分布式秒杀系统的实践

前言

  1. 本项目主要是模拟应对大并发场景下,如何完成商品的秒杀,以及针对秒杀场景下为应对大并发所做的优化。本项目为分布式应用,对职责进行合理划分,降低单体应用的业务耦合性。
  2. 本项目主要借鉴了这位大神,表示感谢:https://github.com/Grootzz/dis-seckill
  3. 本项目主要用于笔者个人面试求职,如果需要使用请与我联系。

系统架构

  • 系统整体使用springClou-netfix进行分布式开发,使用eureka作为注册中心
  • 各个微服务模块使用springBoot框架开发,包括通用模块,用户模块,商品模块,订单模块,客户端Feign模块,视图模块,缓存模块,消息队列模块,网关模块
  • 使用redis作为缓存
  • 使用rabbitMQ作为消息队列
  • 使用zuul作为网关,进行负载均衡
  • 使用zipkin服务链路追踪,方便观察微服务运行情况

主要特点

  • 热点分离:把商品和秒杀商品进行分离
  • 动静分离:使用nginx进行部署可以进行动静分离
  • 读写分离:
    • 并发读:控制在cache,不做校验
    • 并发写:进行校验
  • 时间分片削峰:前端的验证码,后端的MQ
  • 限流

项目特色

  • 使用模板方法的设计模式,设计redis的Key前缀
  • 使用分布式锁,防止恶意注册
    • 数据库:
      • 使用悲观锁比较简单,使用在insert加上on duplicate key update 即可,这样可以以去重复的方式加锁访问。
      • 使用索引也比较简单,对phone字段加唯一索引即可。
      • 使用乐观锁需要在表上加上一个表示版本的字段。 利用数据库实现锁,会造成大量的请求落在数据库上,并阻塞等待执行,这个过程是需要消耗数据库资源的,使得真正的业务请求得不到处理,在秒杀大并发情形下,可能会导致数据库宕机,数据我们不使用数据库来实现锁,而是在服务端实现锁。
    • 服务端:
      • 如果只有一个用户服务模块实例,则采用JUC下的ReentrantLock重入锁实现即可,或者直接对方法加上synchronized,这在单个实例下式没有问题的,也就是单进程的情况。
      • 如果用户服务模块存在多个实例,也就是以集群的方式部署,那么就涉及进程之间的锁问题,synchronized和ReentrantLock这种单进程的锁只对落到本服务模块的请求有效,而对多进程无效,依旧会有线程安全问题。 这个时候,分布式锁就派上用场了。
  • 使用自定义方法拦截器和验证码功能,防止用户重复请求.
    • 在拦截器中,使用自定义注解,限制次数。自定义注解有以下优点:
      • 类属性自动赋值。
      • 验证对象属性完整性。
      • 代替配置文件功能,像spring基于注解的配置。
      • 可以生成文档,像java代码注释中的@see,@param
    • 使用ThreadLocal保存当前线程的用户:因为ThreadLocal是线程安全的,使用ThreadLocal可以保存当前线程持有的对象。每个用户的请求对应一个线程,所以使用ThreadLocal以线程为键保存用户是合适的。
    • 前端按钮不可用,防止用户短时间重复请求
  • 动态生成秒杀的接口地址,避免恶意攻击:如果秒杀接口的地址为静态地址,那么用户可以轻易的使用接口地址完成进行恶意秒杀,这样会使得参与秒杀的用户参与度低,达不到业务目的,引入随机地址则可以很好的规避这个问题。
  • 优化秒杀接口,提高性能:在查询库存时直接访问数据库,因为并发量比较大,存在性能问题。
    • 后面使用redis作为缓存,每个商品被秒杀后,更新redis的库存信息,redis获取不到信息时,再访问数据库
    • 进一步优化,使用内存的HashMap作为库存标记,减小redis压力,秒杀未结束才继续访问redis,减小网络开销。
    • 判断是否重复秒杀:
      • 原来需要通过访问数据库判断订单是否存在,性能较差。
      • 后来使用redis,在下单之后将订单信息缓存再redis中,可以直接从redis取秒杀订单,减少对数据库的访问
    • 在秒杀这一业务方法中,一开始通过加悲观锁(synchronized / 数据库的事务),性能较差。
    • 后面通过MQ对请求排队处理(解耦、异步、削峰)
    • 再后来通过加乐观锁(数据库的版本号),有一定优化,吞吐量高

数据库设计

  • 用户:账号、密码、盐、地址、注册时间、登录时间
  • 商品:名字、标题、简介、价格、库存
  • 订单:用户、订单状态、创建时间
  • 秒杀的商品:商品(建立索引)、秒杀价格、库存、秒杀开始和结束时间
  • 订单项:用户、商品、订单,数量(用户和商品建立索引)
秒杀商品和商品是分别使用两个表存储的,这样做的目的在于:商品列表包含了商品的详细信息,秒杀商品存储的信息为和秒杀有关的信息,如果使用同一个表存储商品的所有信息(包含秒杀信息),那么,在向表写入数据的时候,就会造成过多的请求阻塞地获取锁,而实际上,秒杀业务下,写入操作多为和秒杀有关的字段,如果将这些字段分离处理,商品表主要用于读,而秒杀商品列表用于秒杀业务,这样就可以提高数据库的吞吐量。
秒杀订单和订单用两个表,订单包含了具体的订单信息,而秒杀订单主要是作为一张联系表

一个商品对应一个秒杀商品 一个秒杀订单对应一个具体的订单和多个商品和一个具体的用户 一个用户可以买多个商品,一个商品也能被多个用户购买, 一个用户可以下多个订单,一个订单只能属于一个用户

主要问题

超卖

  • 数据层:在数据库用where判断+事务
  • 业务层:redis记录
  • 控制层:用本地内存的ConcurrentHashMap判断+redis预减判断(原子性操作)

可重复买

  • 数据层:用数据库判断是否已经存在数据+事务
  • 控制层:redis判断

两个问题:

  • 数据层:分布式事务

用户未登录

用户登录之后,系统才会为其分配cookie并缓存。如果用户访问需要登录的接口,那么系统会先从缓存里拿cookie,如果拿不到证明用户未登录,提醒用户登录;否则可以从缓存里拿到并重新缓存,重新设置cookie过期时间。

  • 控制层:拦截器。在web项目中,定义拦截器就是为了防止用户没有登录而可以访问app、网页等,常用的方式就是拦截所有请求,结合注解实现未登录拦截。登录时分配token,缓存。在需登录接口验证token,从缓存拿,并更新缓存

用户恶意刷

  • 控制层:注解。通过指定某个时间间隔的秒杀次数,判断是否过度秒杀

seckill's People

Contributors

corncarrots avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.