静态化技术在蘑菇街的应用(转)

前言

大家都知道利用缓存技术是提升网站性能和稳定性的利器,比如利用redis集群来缓冲mysql的压力,利用opcache缓存编译后的bytecode提升php的性能等等,同样对于网站的整体架构而言,如果一些数据更新频率不高的页面,没有必要每次都从数据库里读取数据,一来调用数据库,响应速度慢;二来增加数据库服务器的负荷,在大促时尤其明显;三,依赖过多的底层组件,如solr,mysql,redis,当出现单点故障的时候,会导致页面的可用性急剧下降。因此在上半年,我们对蘑菇街App端商品详情页做了页面静态化的改造,经过差不多半年的线上运行和大促的考验,效果比较明显,mobile_goods_pool集群的压力明显降低,商品详情页的平均RT由原来的200ms下降到现在的100ms不到,整体稳定性达到了99.99%。

内容大纲

  1. 动态页面的动静分离怎么做
  2. 页面是怎么缓存的,在哪一层做的缓存
  3. 数据一致性怎么保证,缓存失效是如何处理的

动静如何分离

  1. 动静分离
  • 我们将商品详情页的数据做了动静拆分,静态数据包含图片,详情,喜欢列表,评价列表等等,动态数据则包含是否喜欢,评价列表里的是否关注评论者等个性化数据,一次请求拆分成了两次请求,detail和detail_dyn,其中detail请求从缓存中取数据
  1. 动态数据如何获取
  • 在最初的设计方案里面,我们考虑用异步请求的方式,App端获取数据时请求两次,第一次请求静态数据后,发起第二次请求拿动态数据,在客户端做merge之后再渲染,看似问题不大,但是由于手机端网络环境的复杂性导致体验非常不好,第二次请求的响应延时导致页面整体延时非常大,而手机端的优化原则是尽量减少网络请求数,因此我们想到了在服务端即缓存服务器端做异步请求的方式,因此引入了ESI的技术,具体可以看这里

页面如何缓存

在项目初期,我们选型了varnish作为缓存系统,但随着开发过程中引入了ESI,发现varnish对ESI的支持非常弱,比如不支持querystring和cookie的参数传递,而例如详情页上的一些实时促销信息需要传递iid到detail_dyn的请求中,这时varnish就不适用了。因此我们经过调研,选择了apache traffic server(简称ATS)作为我们最终的缓存系统,ATS是一款新兴的高性能、模块化的http代理和缓存系统,提供了对ESI full feature的支持,而且支持磁盘存储。

首先对于ESI的支持是刚需,另外支持磁盘存储对我们而言也是非常适配的特性,大家都知道varnish是基于内存的,假设活跃商品的量级足够大的时候,内存不可能放下所有的商品数据,当需要做数据的分布式存储时,会涉及到proxy路由规则改动,数据垂直切片,服务器水平扩容,服务器容灾等等问题,运维和开发的成本也会上升不少,ATS支持磁盘存储,因此我们在架构上选择了单机全量缓存的方案,用第一层nginx反向代理做负载均衡和健康检测,并且对现有架构的几乎没有侵入,运维成本的降低保证了项目的快速上线。

老的web架构

old_frame.jpg

静态化之后的web架构

new_frame.jpg

缓存如何失效

cache很重要的一点是保证数据一致性,我们做了Get method的缓存,但是当数据库中的数据被更新时,ATS如何感知到,并且刷新数据是很重要的。因此在项目中我们开发了一个失效中心的java application来做这件事。

  • 如何感知数据变化

不能在业务代码做update,delete操作的时候嵌入一行代码,首先,这样对业务的倾入性太大,成本太高,其次对业务系统性能也会有影响。因此我们采用异步监听mysql binlog的方案来感知数据变化,将失效中心的数据源接入Pigeon系统(蘑菇街内部使用的mysql binlog订阅系统)中。

  • 失效怎么做

当需要移除ATS cache中某个object时,ATS提供了自定义的http请求:Purge。Purge基于Http协议,性能非常好。

curl -X PURGE -H 'Host: mogujie.com' -v "http://www.mogujie.com/nmapi/goods/v9/goods/detail?iid= 17q45cw&itemInfoId= 17q45cw"
* About to connect() to localhost port 80 (#0)
* Trying 127.0.0.1... 
* connected
* Connected to localhost (127.0.0.1) port 80 (#0)

> PURGE /nmapi/goods/v9/goods/detail?iid=17q45cw&itemInfoId=17q45cw HTTP/1.1
> User-Agent: curl/7.28.1
> Host: mogujie.com
> Accept: */*
>
< HTTP/1.1 200 Ok
< Date: Mon, 27 Jul 2015 09:43:07 GMT
< Connection: keep-alive。

当下次浏览器访问这个商品时,ATS将不会命中,请求会透传到web容器进行回源。

总结

静态化的方案部署上线之后,detail的命中率达到80%左右,商品详情页接口的访问深度缩短,系统响应速度得到了很大提升。对于ATS这样的工具来说,它的作用是将第一次动态请求的页面缓存起来,在过期时间内,后续的访问请求返回的都是缓存里的数据,不再向后端服务器发起请求,适用场景是一些高PV,且更新频率不高的页面。

posted @ 2015-09-16 23:08  JimmyFang  阅读(317)  评论(0编辑  收藏  举报