秒杀系统架构设计-第二章
动静分离,有哪些方案可选
动静分离的目的是客户端大幅度减少了请求的数据量,响应自然就会快起来。
那到底什么才是动静分离呢?所谓"动静分离",其实就是把用户请求的数据划分为"动态数据"和"静态数据"。
简单来说,"动态数据"和"静态数据"的主要区别就是看页面中输出的数据是否和URL、浏览者、时间、地域相关。比如说:
- 网站的页面,不管谁访问,它都是一样的。它就是一个典型的静态数据,但是它是个动态页面。
- 首页中的数据因为访问的人不同,而显示不同的数据,比如某些电商网站,推荐的内容与访问者有关系,这些个性化的数据就可以理解为动态数据。
也就是所谓"动态"还是"静态",并不是说数据本身是否动静,而是数据中是否含有和访问者相关的个性化数据。
理解静态数据和动态数据以后,"动静分离"这个方案就很容易理解了,我们将静态数据做缓存,有了缓存之后,静态数据的访问效率自然就提高了。
第一,你应该把静态数据缓存到离用户最近的地方。常见的就是三种,用户浏览器、CDN,服务端的Cache中,你应该根据情况,把它们尽量缓存到离用户最近的地方。
第二,静态化改造就是要直接缓存HTTP链接。静态化改造是直接缓存HTTP链接而不是仅仅缓存数据,WEB代理服务器根据请求URL,直接取出对应的HTTP响应头和响应体然后直接返回,这个响应过程简单的连HTTP协议都不用重新组装,甚至连HTTP请求头也不需要解析。
第三,让谁来缓存静态数据也很重要。不同语言的Cache软件处理缓存数据的效率也各不相同。
如何做动静分离的改造
以典型的商品详情系统为例来详细介绍。
- URL唯一化。商品详情系统天然的就可以做到URL唯一化,比如每个商品都由ID来标识,那么http://item.xxx.com/item.html...。为啥要URL唯一呢?前面说了我们是要缓存整个HTTP连接,那么以什么作为key呢?就以URL作为缓存的key,例如以id=xxx这个格式进行区分。
- 分离浏览者相关的因素。浏览者相关的因素包括是否已登录,以及登录身份等,这些相关因素我们可以单独拆分出来,通过动态请求来获取。
- 分离时间因素。服务端输出的时间也通过动态请求获取。
- 异步化地域因素。详情页面上与地域相关的因素做成异步方式获取,当然你也可以通过动态请求方式获取,只是这里通过异步获取更合适。
- 去掉Cookie。服务端输出的页面包含cookie可以通过代码软件来删除,使缓存的静态数据中不含有Cookie。
用缓存的方式来处理静态数据。而动态内容的处理通常由两种方案:ESI(Edge Side Includes)方案和CSI(Client Side Include)方案。
- ESI:即在Web代理服务器上做动态内容请求,并将请求插入到静态页面中,该方式对服务器性能有些影响,但是用户体验好
- CSI:即单独发起一个异步请求,以向服务端获取动态内容。这种方式服务端性能更佳,但是用户端页面可能会延时,体验稍差
动静分离的架构方案
我们把静态数据和动态数据做了分离,那么如何在系统架构上进一步对这些动态和静态数据重新组合,再完整地输出给用户呢?
这就涉及对用户请求路径进行合理的架构了。根据架构上的复杂度,
- 实体机单机部署
- 统一Cache层
- 上CDN
实体单机部署
有以下几个优点:
- 没有网络瓶颈,而且能使用大内存
- 提升命中率,减少Gzip压缩
- 减少Cache失效压力
但是实体单机部署因为将应用和缓存部署再同一个机器上,无法充分利用机器的性能,也增加运维的复杂度。
统一Cache层
将单机的Cache统一分离出来,形成一个单独的Cache集群。
优点:单独一个Cache层,可以减少多个应用接入缓存的成本;更易于维护,如后面加强监控、配置自动化;可以共享内存,最大化利用内存。
缓存集中会带来一些问题:Cache层内部交换网络成为瓶颈;缓存服务器的网卡也会是瓶颈;机器少风险较大,挂掉一台就会影响很大一部分缓存数据。
解决这些问题,可以对Cache做hash分组,这样能够避免热点数据过度集中导致新的瓶颈产生。
使用CDN
将部分数据从Cache进一步前移到CDN上,因为CDN离用户最近,效果会更好。
这么做有几个问题要解决:
- 失效问题。
- 命中率问题。
- 发布更新问题
将商品详情系统放到全国的CDN节点上使不太现实的,因为存在以上问题。我们可以选择若干个节点来尝试实施。要满足几个条件:
- 靠近访问量比较集中的地区;
- 离主站相对较远;
- 节点到主站间网络比较好,而且稳定;
- 节点容量比较大,不会占用其他CDN太多的资源。
最后,还有一点很重要,那就是节点不要太多。
基于上面几个因素,选择CDN的二级Cache比较合适,因为二级Cache数量偏少,容量也更大,让用户的请求先回源的CDN的二级Cache中,如何没命中再回源站获取数据
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。