* 主要思路:
1、数据变更还是通过MQ通知;
2、数据异构Worker得到通知,然后按照一些维度进行数据存储,存储到数据异构JIMDB集群(JIMDB:Redis+持久化引擎),存储的数据都是未加工的原子化数据,如商品基本信息、商品扩展属性、商品其他一些相关信息、商品规格参数、分类、商家信息等;
3、数据异构Worker存储成功后,会发送一个MQ给数据同步Worker,数据同步Worker也可以叫做数据聚合Worker,按照相应的维度聚合数据存储到相应的JIMDB集群;三个维度:基本信息(基本信息+扩展属性等的一个聚合)、商品介绍(PC版、移动版)、其他信息(分类、商家等维度,数据量小,直接Redis存储);
4、前端展示分为两个:商品详情页和商品介绍,使用Nginx+Lua技术获取数据并渲染模板输出。
另外我们目前架构的目标不仅仅是为商品详情页提供数据,只要是Key-Value获取的而非关系的我们都可以提供服务,我们叫做动态服务系统。
具体实现:
数据闭环即数据的自我管理,或者说是数据都在自己系统里维护,不依赖于任何其他系统,去依赖化;这样得到的好处就是别人抖动跟我没关系。
数据异构,是数据闭环的第一步,将各个依赖系统的数据拿过来,按照自己的要求存储起来;
数据原子化,数据异构的数据是原子化数据,这样未来我们可以对这些数据再加工再处理而响应变化的需求;
数据聚合,将多个原子数据聚合为一个大JSON数据,这样前端展示只需要一次get,当然要考虑系统架构,比如我们使用的Redis改造,Redis又是单线程系统,我们需要部署更多的Redis来支持更高的并发,另外存储的值要尽可能的小;
数据存储,我们使用JIMDB,Redis加持久化存储引擎,可以存储超过内存N倍的数据量,我们目前一些系统是Redis+LMDB引擎的存储,目前是配合SSD进行存储;另外我们使用Hash Tag机制把相关的数据哈希到同一个分片,这样mget时不需要跨分片合并。
我们目前的异构数据时键值结构的,用于按照商品维度查询,还有一套异构时关系结构的用于关系查询使用。
详情页架构设计原则 / 数据维度化
对于数据应该按照维度和作用进行维度化,这样可以分离存储,进行更有效的存储和使用。我们数据的维度比较简单:
1、商品基本信息,标题、扩展属性、特殊属性、图片、颜色尺码、规格参数等;
2、商品介绍信息,商品维度商家模板、商品介绍等;
3、非商品维度其他信息,分类信息、商家信息、店铺信息、店铺头、品牌信息等;
4、商品维度其他信息(异步加载),价格、促销、配送至、广告词、推荐配件、最佳组合等。
拆分系统
将系统拆分为多个子系统虽然增加了复杂性,但是可以得到更多的好处,比如数据异构系统存储的数据是原子化数据,这样可以按照一些维度对外提供服务;而数据同步系统存储的是聚合数据,可以为前端展示提供高性能的读取。而前端展示系统分离为商品详情页和商品介绍,可以减少相互影响;目前商品介绍系统还提供其他的一些服务,比如全站异步页脚服务。
Worker无状态化+任务化
1、数据异构和数据同步Worker无状态化设计,这样可以水平扩展;
2、应用虽然是无状态化的,但是配置文件还是有状态的,每个机房一套配置,这样每个机房只读取当前机房数据;
3、任务多队列化,等待队列、排重队列、本地执行队列、失败队列;
4、队列优先级化,分为:普通队列、刷数据队列、高优先级队列;例如一些秒杀商品会走高优先级队列保证快速执行;
5、副本队列,当上线后业务出现问题时,修正逻辑可以回放,从而修复数据;可以按照比如固定大小队列或者小时队列设计;
6、在设计消息时,按照维度更新,比如商品信息变更和商品上下架分离,减少每次变更接口的调用量,通过聚合Worker去做聚合。
多级缓存化
浏览器缓存,当页面之间来回跳转时走local cache,或者打开页面时拿着Last-Modified去CDN验证是否过期,减少来回传输的数据量;
CDN缓存,用户去离自己最近的CDN节点拿数据,而不是都回源到北京机房获取数据,提升访问性能;
服务端应用本地缓存,我们使用Nginx+Lua架构,使用HttpLuaModule模块的shared dict做本地缓存( reload不丢失)或内存级Proxy Cache,从而减少带宽;
另外我们还使用使用一致性哈希(如商品编号/分类)做负载均衡内部对URL重写提升命中率;
我们对mget做了优化,如去商品其他维度数据,分类、面包屑、商家等差不多8个维度数据,如果每次mget获取性能差而且数据量很大,30KB以上;而这些数据缓存半小时也是没有问题的,因此我们设计为先读local cache,然后把不命中的再回源到remote cache获取,这个优化减少了一半以上的remote cache流量;
服务端分布式缓存,我们使用内存+SSD+JIMDB持久化存储。
详情页架构设计原则 / 动态化
数据获取动态化,商品详情页:按维度获取数据,商品基本数据、其他数据(分类、商家信息等);而且可以根据数据属性,按需做逻辑,比如虚拟商品需要自己定制的详情页,那么我们就可以跳转走,比如全球购的需要走jd.hk域名,那么也是没有问题的;
模板渲染实时化,支持随时变更模板需求;
重启应用秒级化,使用Nginx+Lua架构,重启速度快,重启不丢共享字典缓存数据;
需求上线速度化,因为我们使用了Nginx+Lua架构,可以快速上线和重启应用,不会产生抖动;另外Lua本身是一种脚本语言,我们也在尝试把代码如何版本化存储,直接内部驱动Lua代码更新上线而不需要重启Nginx。