本章以京东商品详情页为例,京东商品详情页虽然仅是单个页面,可是其数据聚合源是很是多的,除了一些实时性要求比较高的如价格、库存、服务支持等经过AJAX异步加载加载以外,其余的数据都是在后端作数据聚合而后拼装网页模板的。前端
如图所示,商品页主要包括商品基本信息(基本信息、图片列表、颜色/尺码关系、扩展属性、规格参数、包装清单、售后保障等)、商品介绍、其余信息(分类、品牌、店铺【第三方卖家】、店内分类【第三方卖家】、同类相关品牌)。更多细节此处就不阐述了。后端
整个京东有数亿商品,若是每次动态获取如上内容进行模板拼装,数据来源之多足以形成性能没法知足要求;最初的解决方案是生成静态页,可是静态页的最大的问题:一、没法迅速响应页面需求变动;二、很难作多版本线上对比测试。如上两个因素足以制约商品页的多样化发展,所以静态化技术不是很好的方案。缓存
经过分析,数据主要分为四种:商品页基本信息、商品介绍(异步加载)、其余信息(分类、品牌、店铺等)、其余须要实时展现的数据(价格、库存等)。而其余信息如分类、品牌、店铺是很是少的,彻底能够放到一个占用内存很小的Redis中存储;而商品基本信息咱们能够借鉴静态化技术将数据作聚合存储,这样的好处是数据是原子的,而模板是随时可变的,吸取了静态页聚合的优势,弥补了静态页的多版本缺点;另一个很是严重的问题就是严重依赖这些相关系统,若是它们挂了或响应慢则商品页就挂了或响应慢;商品介绍咱们也经过AJAX技术惰性加载(由于是第二屏,只有当用户滚动鼠标到该屏时才显示);而实时展现数据经过AJAX技术作异步加载;所以咱们能够作以下设计:架构
接收商品变动消息,作商品基本信息的聚合,即从多个数据源获取商品相关信息如图片列表、颜色尺码、规格参数、扩展属性等等,聚合为一个大的JSON数据作成数据闭环,以key-value存储;由于是闭环,即便依赖的系统挂了咱们商品页仍是能继续服务的,对商品页不会形成任何影响;
接收商品介绍变动消息,存储商品介绍信息;
介绍其余信息变动消息,存储其余信息。异步
整个架构以下图所示:性能
技术选型
MQ可使用如Apache ActiveMQ;
Worker/动态服务能够经过如Java技术实现;
RPC能够选择如alibaba Dubbo;
KV持久化存储能够选择SSDB(若是使用SSD盘则能够选择SSDB+RocksDB引擎)或者ARDB(LMDB引擎版);
缓存使用Redis;
SSDB/Redis分片使用如Twemproxy,这样无论使用Java仍是Nginx+Lua,它们都不关心分片逻辑;
前端模板拼装使用Nginx+Lua;
数据集群数据存储的机器能够采用RAID技术或者主从模式防止单点故障;
由于数据变动不频繁,能够考虑SSD替代机械硬盘测试
核心流程
首先咱们监听商品数据变动消息;
接收到消息后,数据聚合Worker经过RPC调用相关系统获取全部要展现的数据,此处获取数据的来源可能很是多并且响应速度彻底受制于这些系统,可能耗时几百毫秒甚至上秒的时间;
将数据聚合为JSON串存储到相关数据集群;
前端Nginx经过Lua获取相关集群的数据进行展现;商品页须要获取基本信息+其余信息进行模板拼装,即拼装模板仅须要两次调用(另外由于其余信息数据量少且对一致性要求不高,所以咱们彻底能够缓存到Nginx本地全局内存,这样能够减小远程调用提升性能);当页面滚动到商品介绍页面时异步调用商品介绍服务获取数据;
若是从聚合的SSDB集群/Redis中获取不到相关数据;则回源到动态服务经过RPC调用相关系统获取全部要展现的数据返回(此处能够作限流处理,由于若是大量请求过来的话可能致使服务雪崩,须要采起保护措施),此处的逻辑和数据聚合Worker彻底同样;而后发送MQ通知数据变动,这样下次访问时就能够从聚合的SSDB集群/Redis中获取数据了。设计