高并发 Nginx+Lua OpenResty系列(10)——商品详情页
本章以京东商品详情页为例,京东商品详情页虽然仅是单个页面,但是其数据聚合源是非常多的,除了一些实时性要求比较高的如价格、库存、服务支持等通过AJAX异步加载加载之外,其他的数据都是在后端做数据聚合然后拼装网页模板的。
如图所示,商品页主要包括商品基本信息(基本信息、图片列表、颜色/尺码关系、扩展属性、规格参数、包装清单、售后保障等)、商品介绍、其他信息(分类、品牌、店铺【第三方卖家】、店内分类【第三方卖家】、同类相关品牌)。更多细节此处就不阐述了。
整个京东有数亿商品,如果每次动态获取如上内容进行模板拼装,数据来源之多足以造成性能无法满足要求;最初的解决方案是生成静态页,但是静态页的最大的问题:1、无法迅速响应页面需求变更;2、很难做多版本线上对比测试。如上两个因素足以制约商品页的多样化发展,因此静态化技术不是很好的方案。
通过分析,数据主要分为四种:商品页基本信息、商品介绍(异步加载)、其他信息(分类、品牌、店铺等)、其他需要实时展示的数据(价格、库存等)。而其他信息如分类、品牌、店铺是非常少的,完全可以放到一个占用内存很小的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中获取数据了。
高并发 Nginx+Lua OpenResty系列(10)——商品详情页的更多相关文章
- 高并发 Nginx+Lua OpenResty系列(8)——Lua模版渲染
模版渲染 动态web网页开发是Web开发中一个常见的场景,比如像京东商品详情页,其页面逻辑是非常复杂的,需要使用模板技术来实现.而Lua中也有许多模板引擎,如目前京东在使用的lua-resty-tem ...
- 高并发 Nginx+Lua OpenResty系列(3)——模块指令
Nginx Lua 模块指令 Nginx共11个处理阶段,而相应的处理阶段是可以做插入式处理,即可插拔式架构:另外指令可以在http.server.server if.location.locatio ...
- 高并发 Nginx+Lua OpenResty系列(11)——流量复制/AB测试/协程
流量复制 在实际开发中经常涉及到项目的升级,而该升级不能简单的上线就完事了,需要验证该升级是否兼容老的上线,因此可能需要并行运行两个项目一段时间进行数据比对和校验,待没问题后再进行上线.这其实就需要进 ...
- 高并发 Nginx+Lua OpenResty系列(9)——HTTP服务
此处我说的HTTP服务主要指如访问京东网站时我们看到的热门搜索.用户登录.实时价格.实时库存.服务支持.广告语等这种非Web页面,而是在Web页面中异步加载的相关数据.这些服务有个特点即访问量巨大.逻 ...
- 高并发 Nginx+Lua OpenResty系列(2)——Nginx Lua API
Nginx Lua API 和一般的Web Server类似,我们需要接收请求.处理并输出响应.而对于请求我们需要获取如请求参数.请求头.Body体等信息:而对于处理就是调用相应的Lua代码即可:输出 ...
- 高并发 Nginx+Lua OpenResty系列(1)——环境搭建
OpenResty是一款基于Nginx的高性能负载均衡服务器容器,简单来说是Nginx+Lua.结合了Lua语言来对Nginx进行扩展,使得在Nginx上具有web容器功能. OpenResty运行环 ...
- 高并发 Nginx+Lua OpenResty系列(5)——Lua开发库Redis
Redis客户端 lua-resty-redis是为基于cosocket API的ngx_lua提供的Lua redis客户端,通过它可以完成Redis的操作.默认安装OpenResty时已经自带了该 ...
- 高并发 Nginx+Lua OpenResty系列(4)——Lua 模块开发
在实际开发中,不可能把所有代码写到一个大而全的lua文件中,需要进行分模块开发:而且模块化是高性能Lua应用的关键.使用require第一次导入模块后,所有Nginx 进程全局共享模块的数据和代码,每 ...
- 高并发 Nginx+Lua OpenResty系列(7)——Lua开发库json
JSON库 在进行数据传输时JSON格式目前应用广泛,因此从Lua对象与JSON字符串之间相互转换是一个非常常见的功能:目前Lua也有几个JSON库,如:cjson.dkjson.其中cjson的语法 ...
随机推荐
- Linux调试工具
1. 使用printf调试 #ifdef DEBUG Printf(“valriable x has value = %d\n”, x) #endif 然后在编译选项中加入-DDEBUG 更复杂的调试 ...
- Netty:一种非易失堵塞client/server相框
Netty:一种非易失堵塞client/server相框 作者:chszs.转载需注明.博客主页:http://blog.csdn.net/chszs Netty是一个异步事件驱动的网络应用框架,为J ...
- WPF中桌面屏保的制作(主要代码)
原文:WPF中桌面屏保的制作(主要代码) 制作要点:(1) 使用System.Windows.Threading.DispatcherTimer;(2) 将Window属性设置为: this ...
- 组态DNS、搜索域名和主机名
一个.组态DNS和搜索领域 特别配置DNS该文件是/etc/resolv.conf:同时,我们可以ifcfg-eth0网卡的配置和其他配置文件中指定的. 演示样本: [root@instructor ...
- .net core config读取
最简单的方式 引用 Microsoft.Extensions.Configuration Microsoft.Extensions.Configuration.Json json文件 新建一个Conf ...
- js动态创建表格
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...
- C#正则表达式的完全匹配、部分匹配及忽略大小写的问题
原文:C#正则表达式的完全匹配.部分匹配及忽略大小写的问题 问题的提出 根据用户给定表达式,里面含有各种数学函数,如求绝对值,三角函数,平方.开方等,分别以类似ABS(表达式),Sin(表达式),AS ...
- JS 小鸟飞
<!DOCTYPE html><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> ...
- 【C#】wpf添加gif动图支持
原文:[C#]wpf添加gif动图支持 1.nuget里下载XamlAnimatedGif包,然后安装. 2.添加XamlAnimatedGif包的命名空间:xmlns:gif="https ...
- thinkphp5 的一些笔记
Model里面的一些属性添加 protected $resultSetType = 'collection'; protected $autoWriteTimestamp = 'timestamp'; ...