如何设计秒杀系统(二)
实施方案
热点数据
- 分类:
静态热点数据,可以提前预测的热点数据,可以提前缓存。
动态热点数据,一般是突发的临时的。 - 如何发现热点数据
可以通过运营手段提前报名来发现静态热点数据,也可以通过数据统计出TOPN的商品。
发现动态热点数据:
构建一个异步的系统,它可以收集交易链路上各个环节中的中间件产品的热点 Key,如 Nginx、缓存、RPC 服务框架等这些中间件(一些中间件产品本身已经有热点统计模块)。
建立一个热点上报和可以按照需求订阅的热点服务的下发规范,主要目的是通过交易链路上各个系统(包括详情、购物车、交易、优惠、库存、物流等)访问的时间差,把上游已经发现的热点透传给下游系统,提前做好保护。比如,对于大促高峰期,详情系统是最早知道的,在统一接入层上 Nginx 模块统计的热点 URL。
将上游系统收集的热点数据发送到热点服务台,然后下游系统(如交易系统)就会知道哪些商品会被频繁调用,然后做热点保护。
注意事项:- 日志抓取采用异步的方式,即保证通用性也不影响主流程。
- 应用和组件间要有自己的限流保护措施。
- 热点发现要快(3s)
热点数据的处理:
对热点数据利用LRU队列进行缓存
把热点请求和普通请求进行隔离,防止热点数据影响到普通的请求
(业务隔离,系统隔离,数据隔离)。
削峰错谷
为什么要削峰:
- 节省服务器资源
- 让服务端处理变得更加平稳
怎么做:
1.排队
消息对立
线程加锁,排队等待
内存排队算法
顺序读文件
2.答题
系统设计思路:
答题验证设计:
- 分层过滤
依次走浏览器缓存,CDN,统一cache,后台,数据库
原则:
将动态请求的读数据缓存(Cache)在 Web 端,过滤掉无效的数据读;
对读数据不做强一致性校验,减少因为一致性校验产生瓶颈的问题;
对写数据进行基于时间的合理分片,过滤掉过期的失效请求;
对写请求做限流保护,将超出系统承载能力的请求过滤掉;
对写数据进行强一致性校验,只保留最后有效的数据。
系统性能优化
- 概述
一般用QPS来衡量性能,总 QPS =(1000ms / 响应时间)× 线程数量
响应时间:
响应时间一般由CPU执行时间和线程等待时间组成,优化线程等待时间对性能影响不大,要做的是增加CPU的执行时间。
线程数:
默认配置,线程数 = 2 * CPU 核数 + 1
最佳实践得出来的公式:
线程数 = [(线程等待时间 + 线程 CPU 时间) / 线程 CPU 时间] × CPU 数量
当然还是不要“本本主义”,需要实际去做性能测试,选择合适的线程数量。 - 如何发现瓶颈
JProfiler 和 Yourkit 这两个工具,它们可以列出整个请求中每个函数的 CPU 执行时间,或者使用jstack 定时地打印调用栈。 - 如何优化
1.减少编码
拿java举例,就是减少把字符编译成字节的过程,因为比较耗时
举例:
网页输出是可以直接进行流输出的,即用 resp.getOutputStream() 函数写数据,把一些静态的数据提前转化成字节,等到真正往外写的时候再直接用 OutputStream() 函数写,就可以减少静态数据的编码转换。
2.减少序列化
把关联性强的应用进行合并部署,放到同一个tomcat容器中,不走本机的socket
3.Java优化
把大量的请求和数据从nginx或者Web代理容器(Varnish、Squid)中返回;
直接写servlet,避免使用传统的框架
直接输出流数据 resp.getOutputStream()
4.并发读缓存
利用一致性hash及案例集中式缓存