博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
秒杀系统设计要点
阅读量:4090 次
发布时间:2019-05-25

本文共 2366 字,大约阅读时间需要 7 分钟。

1、概述

秒杀其实主要解决的是两个问题,一个是并发读,一个是并发写。秒杀系统本质上是一个满足大并发、高性能和高可用的分布式系统。

在整个用户请求路径上从浏览器到服务端我们要遵循几个原则:

  1. 用户请求的数据尽量少,从而减少cpu消耗
  2. 请求数尽量少:合并CSS和JavaScript文件
  3. 路径尽量短,减少节点消耗:多个强依赖的应用合并部署,简化调用方式
  4. 依赖尽量少:高优先级的系统减少对低优先级系统的依赖,方式重要的系统被不重要的系统拖垮。
  5. 不要有单点,要有备份

具体措施:

  1. 将热点数据(如库存数据)单独放在一个缓存系统中,以提高读性能。静态数据可以放在机器内存。
  2. 增加秒杀答题,防止有秒杀器抢单。
  3. 动静分离,局部刷新
  4. 增加系统限流保护,防止最坏情况发生。

2、动静分离

静态数据如何做缓存?

  1. 把静态数据缓存到离用户近的地方:用户浏览器、CDN、服务端Cache。
  2. 静态化改造就是要直接缓存HTTP连接,相比于java,像Nginx、Apache和Varnish更擅长处理大并发静态文件请求。

如何把动态页面改造成适合缓存的静态页面?

  1. URL唯一化,这样就可以用URL作为key来缓存整个HTTP连接
  2. 分离浏览者相关的因素,如是否登录、登录身份。可以用动态请求获取。
  3. 分离时间因素,服务器输出的时间也动态获取
  4. 异步化地域因素,与地域相关的因素异步动态获取
  5. 去掉Cookie,在缓存的静态数据中不含有Cookie

动态内容的处理方案?

  1. ESI:在web代理服务器上做动态内容请求,并将请求插入到静态页面中。这种对服务器性能有些影响。
  2. CSI:单独发起JavaScript请求,向服务器请求动态内容。这种页面可能延时

动静分离架构方案:

  1. 实体机单机部署,以增大cache容量,并采用一致性Hash分组的方式来提升命中率。但是会造成CPU的浪费。

  1. 统一Cache层,就是将单机的cache分离出来形成cache集群。可以减少运维成本,也方便其他系统接入。

  1. 上CDN,CDN离用户最近,效果更好。

3、热点数据

热点:分为热点操作和热点数据,热点数据分为静态热点数据和动态热点数据。

如何发现热点数据?

  1. 发现静态热点数据:(1)卖家报名,把参加活动的商品打标。(2)大数据计算平时热卖商品topN
  2. 发现动态热点数据:(1)日志聚合、分析,如nginx可以检测那些url被高频访问。

如何处理热点数据?

  1. 优化:临时缓存热点数据,采用LRU淘汰算法替换。
  2. 限制:对商品ID做一致性HASH,分桶,每个分桶一个处理队列。
  3. 隔离:(1)业务隔离(2)系统隔离,申请单独域名(3)数据隔离,使用单独的Cache集群或者数据库

4、流量削峰

流量削峰方式:

  1. 排队,(1)使用消息队列(2)线程池加锁等待(3)请求序列化到文件,然后顺序地读文件来恢复请求
  2. 答题,避免秒杀器作弊,延缓请求。
  3. 分层过滤:在不同的层次尽可能地过滤掉无效请求,让漏斗最末端的才是有效请求。

5、服务端性能优化

QPS:每秒请求数、RT:响应时间。

总QPS=(1000ms/响应时间)*线程数量

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

如何优化系统:

  1. 减少编码:java编解码很慢,可以把一些静态的数据提前转化成字节缓存起来,等到真正往外写的时候直接用OutputStream()函数写,就可以减少静态数据的编码转换。Velocity就是这么做的。
  2. 减少序列化:减少RPC,将关联性比较强的应用进行合并部署,比如说部署在同一个tomcat容器中,且不走本机的socket。
  3. Java极致优化:(1)直接用Servlet处理请求,不用框架(2)直接输出流数据,使用resp.getOutputStream而不是resp.getWriter()函数,可以省掉一些不便字符的编码。数据输出使用JSON而不是模板引擎。
  4. 并发读优化:静态数据秒杀前全量推送到秒杀机器上,一直缓存到秒杀结束。动态数据设置缓存TTL,失效后拉取最新数据。

6、减库存的设计

减库存的方式:

  1. 下单减库存
  2. 付款减库存
  3. 预扣库存:买家下单,库存为其保留一定时间,超过时间,库存自动释放。付款后实际地减去库存。

第三种比较好,但是不能避免恶意下单不付款。可以采取以下措施:

  1. 设置每人最大购买件数
  2. 重复下单不付款的次数限制
  3. 超卖补货,或者付款时提示库存不足

大型秒杀中如何减库存?

秒杀中多使用下单减库存,业务上要保证大并发请求时库存数据不能为负数,做法有:

  1. 可以通过事务来判断,为负数就回滚。
  2. 设置数据库的字段为无符号整数,这样小于0是数据库报错。
  3. 使用CASE WHEN语句:
UPDATE item SET inventory=CASE WHEN inventory>=xxx THEN inventory-xxx ELSE inventory END

秒杀减库存的极致优化:如果减库存逻辑非常单一,可以考虑直接放到缓存中完成,否则必须在数据库中完成减库存,不过这会导致多个线程竞争数据库行锁,要解决并发锁的问题,有两种办法:

  1. 应用层做排队,防止热点商品占用太多数据库连接
  2. 数据库层做排队,阿里的补丁可以在数据库层对单行记录做到并发排队。

7、设计兜底方案

系统的高可用建设涉及项目生命周期的各个阶段,如下图所示:

遇到大流量时,应该从哪些方面来保障系统的稳定运行?

  1. 降级,当系统容量达到一定程度时,限制或者关闭系统的某些非核心功能
  2. 限流,当系统容量达到瓶颈时,通过限制一部分流量来保护系统。既要支持URL以及方法级别的限流,也要支持基于QPS和线程的限流,后者比较常用。
  3. 拒绝服务,可以在Nginx设置过载保护,当机器负载过高时拒绝HTTP请求并返回503错误码(表示服务不可用)。

 

转载地址:http://nlbii.baihongyu.com/

你可能感兴趣的文章
mapReduce(3)---入门示例WordCount
查看>>
hbase(3)---shell操作
查看>>
hbase(1)---概述
查看>>
hbase(5)---API示例
查看>>
SSM-CRUD(1)---环境搭建
查看>>
SSM-CRUD(2)---查询
查看>>
SSM-CRUD (3)---查询功能改造
查看>>
Nginx(2)---安装与启动
查看>>
springBoot(5)---整合servlet、Filter、Listener
查看>>
C++ 模板类型参数
查看>>
C++ 非类型模版参数
查看>>
设计模式 依赖倒转原则 & 里氏代换原则
查看>>
DirectX11 光照
查看>>
图形学 图形渲染管线
查看>>
DirectX11 计时和动画
查看>>
DirectX11 光照与材质的相互作用
查看>>
DirectX11 法线向量
查看>>
DirectX11 兰伯特余弦定理(Lambert)
查看>>
DirectX11 漫反射光
查看>>
DirectX11 环境光
查看>>