最近拜读了许令波老师极客时间的专栏《如何设计一个秒杀系统》有所感,特总结如下:
很重要的一点是根据不同的用户体量来做不同的设计,首先你得知道你预估的QPS是多少,业务的瓶颈在哪里,10w级别可能瓶颈就在数据读取上,通过增加缓存一般就能解决,如果到100w级别,那么服务端的网络可能都是瓶颈,所以要把大部分的静态数据放到cdn上甚至缓存在浏览器里。
那秒杀有哪些关键点呢:无非是高性能、一致性、高可用。要解决的问题主要是并发读,并发写。下面来说下有哪些办法可以对这种秒杀进行优化:
1、架构原则:用户请求数据量要少;请求次数要少;请求经过的节点要少;依赖的服务要少;不能单点。
2、独立部署:防止流量影响其它业务;热点数据放到单独的缓存系统,甚至直接放到本地。
3、动静分离:秒杀开始时不用刷新整个页面;静态页面存储在离用户最近的地方(用户浏览器里、CDN 上或者在服务端的 Cache 中);静态化改造(直接缓存http连接);借助nginx处理静态文件请求。
4、限流:评估出最大qps,进行限流保护;总 QPS =(1000ms / 响应时间)× 线程数量。
5、热点隔离:比如说某个商品突然成了热点数据,请求量暴增,这个时候就有可能影响用户访问其它的商品,可以怎么做呢,其实可以按照商品id做一致性hash路由到不同的处理队列,防止热点商品占用太多服务器资源。
6、发现热点:由于请求是一层一层调用的,比如先到搜索,再到详情,再到下单,支付等;就可以通过一些中间件收集到上游的热点数据,提前通知下游做好防护。
7、削峰:技术上有排队、答题、分层过滤;业务上也可于同一时间发放其它优惠来分散请求。
8、优化系统:减少编码,静态字符串可以提前编好码缓存;减少序列化,因为序列化也涉及编码;使用原生Servlet 处理请求避免使用mvc框架也能稍微降低响应时间;并发读优化,类似库存业务,没必要每次读都走库或缓存中间件,可以直接放在本地,定时更新,允许少量数据不一致情况,到写入的时候再保证最终一致性。
9、库存业务:减库存又分为如下方式:下单减库存、扣款减库存、预扣库存。秒杀根据业务可以采用第一种。
10、解决并发锁:我们知道mysql数据库有行锁,大量线程竞争行锁会导致等待线程增加,tps下降影响数据库吞吐量,可以在应用层做排队,按照商品维度设置队列顺序执行,这样能减少同一台机器对数据库同一行记录进行操作的并发度,同时也能控制单个商品占用数据库连接的数量。
11、避免多扣:1.应用层面通过事务;2.数据库设置无符号整数;3.sql增加条件。
12、降级:通过开关限制系统非核心功能;过载保护,当机器负载达到一定阈值时,直接拒绝请求(nginx、服务器)。
......
会持续补充,套路是不是很多呀,加油!
本文为原创编辑,如需转载请注明作者信息及本文链接,谢谢尊重个人劳动成果。