概述
秒杀系统要解决的两个棘手问题:并发读和并发写。要完成这个目标有两个思路,“减”和“分",减指的是要充分渐少不必要的请求,做到用户请求的数据尽量少、请求数尽量少、路径尽量短、依赖尽量少,不要有单点;”分“则指的是要合理进行数据库的分库分表。
那么秒杀系统的目标则是:
高性能: 秒杀涉及大量的并发读和并发写,因此支持高并发访问这点非常关键。包括设计数据的动静分离方案、热点的发现与隔离、请求的削峰与分层过滤、服务端的极致优化。
一致性: 秒杀中商品减库存的实现方式同样关键。可想而知,有限数量的商品在同一时刻被很多倍的请求同时来减库存,减库存又分为“拍下减库存”“付款减库存”以及预扣等几种,在大并发更新的过程中都要保证数据的准确性,其难度可想而知。
高可用: 设计兜底方案。
设计原则
- 数据尽量少
动静分离,减少网络传输,减少服务间的依赖,减少数据的序列化和反序列化。 - 请求数尽量少
合并静态文件,如css和js等。 - 路径尽量短
多个依赖服务合在一起的耦合性将会大大降低,可以将应用服务合并部署。 - 依赖尽量少
还是要减少所依赖的服务,可以考虑的方案是服务分级,必要时对低级别应用进行降级。 - 不要有单点
这个是要在系统设计之初就要考虑的,做到服务的无状态化。
总结来讲,还是要根据具体的场景来设计应用的架构。
实施方案
动静分离
- 什么是动态和静态数据
动态数据”和“静态数据”的主要区别就是看页面中输出的数据是否和 URL、浏览者、时间、地域相关,以及是否含有 Cookie 等私密数据。 - 怎么缓存静态数据
缓存到离用户最近的地方,常见的就三种,用户浏览器里、CDN 上或者在服务端的 Cache 中。
静态化改造就是把数据缓存在代理服务器,根据请求 URL,直接取出对应的 HTTP 响应头和响应体然后直接返回。
相对于JAVA这种应用层,Web 服务器(如 Nginx、Apache、Varnish)更适合也更擅长处理大并发的静态文件请求,缓存静态化数据。 - 如何对常见应用做改造
- URL 唯一化,也就是更具URL做缓存,常见的有根据商品Id缓存作为key缓存商品图片等静态信息;
- 分离浏览者相关的因素;
- 分离时间因素,服务端输出的时间也通过动态请求获取。
- 异步化地域因素。详情页面上与地域相关的因素做成异步方式获取,当然你也可以通过动态请求方式获取,只是这里通过异步获取更合适。
- 去掉 Cookie。服务端输出的页面包含的 Cookie 可以通过代码软件来删除,如 Web 服务器 Varnish 可以通过 unset req.http.cookie 命令去掉 Cookie。注意,这里说的去掉 Cookie 并不是用户端收到的页面就不含 Cookie 了,而是说,在缓存的静态数据中不含有 Cookie。
- 怎么组织动态化数据
- ESI 方案(或者 SSI):在服务端组装整个页面,然后直接返回。
- CSI 方案:客户端异步请求数据。
- 怎么组织架构
- 实体机单机部署
nginx将请求随机路由到某个实体机的cacahe层,在根据hash定位到该机器分组中的某个varnish实例。
优点:
1.没有网络瓶颈,而且能使用大内存;
2.既能提升命中率,又能减少 Gzip 压缩;
3.减少 Cache 失效压力,因为采用定时失效方式。
缺点:
实体机太复杂,又有java应用又有cache,运维难度大 - 统一cache层
优点:
1.减少运维成本;
2.应用不用关心cache;
3.共享内存。
缺点:
1.Cache 层内部交换网络成为瓶颈;
2.缓存服务器的网卡也会是瓶颈;
3.机器少风险较大,挂掉一台就会影响很大一部分缓存数据。
- 实体机单机部署
- 使用CDN(2级CDN比较理想)