京东前台PC首页系统技术详解( 二 )


为实现历史快照,项目借鉴爬虫技术,定时抓取PC首页的完整数据,并将快照数据推送至静态服务器 。当监控到系统异常时开启降级开关将页面及时回滚至特定历史版本 。此降能绕开正常的服务流程,直接读取兜底的静态资源 。具体流程如下:
 

京东前台PC首页系统技术详解

文章插图
 
(此项目自上线后尚未触发一次 。在其他的业务场景中,需要考虑各自实际情况)
 
2.流畅的加载速度
既要保证页面完整性,也要保证页面以及API的加载速度 。下面从性能方面讲解系统的优化方向 。
技术选型
首页是一种重性能、轻逻辑的业务场景,没有过多的基础服务依赖,主要与Redis和上游RPC做交互 。系统通过读取上游RPC数据后聚合、过滤、验证后输出,最终完成页面展示 。用户请求简化流程图如下:
 
京东前台PC首页系统技术详解

文章插图
 
 
结合业务场景,京东首页在2015年开始调研并尝试使用OpenResty服务,基于NGINX的异步事件模型以及高性能的脚本语言LUA,OpenResty完美胜任京东首页的高并发场景 。经过近几年的沉淀,OpenResty成为京东首页的基础架构,也以此沉淀了OpenLua开发框架 。
 
京东前台PC首页系统技术详解

文章插图
 
 
如上图所示,OpenResty(Nginx)服务的请求处理拥有11个阶段之多,每个阶段都有其特定的业务场景 。在init_by_lua*阶段,框架初始化环境变量、init_worker_by_lua*阶段初始化降级开关以及基础配置,并将其同步至共享cache(ngx.shared.DICT)、 init_write_by_lua*阶段初始化路由策略、access_by_lua*阶段实现访问权限验证,加解密等、content_by_lua*阶段实现主体业务逻辑、log_by_lua*阶段实现日志以及Ump信息的输出 。
Redis HotKey(热key)优化:在多数的业务场景中都使用Redis集群为服务加速,通过集群的横向扩展能力增加系统吞吐率 。但在特殊的业务场景会有热点数据的出现,导致流量倾斜,增加单个分片的压力,这样就极大制约API的效率,极端情况甚至可以拖垮Redis集群 。如何避免热点数据有2种方案:1、通过复制热点数据将数据存放到不同的Redis分片,每次通过随机算法读取;2、热点数据前置、减少Redis的压力 。由于第一种方案实现繁琐,系统使用第二种方案解决热点数据,也就是将发现的热点数据存储到本地cache中(ngx.shard.DICT),通过本地cache服务直接对外提供服务,由于ngx.shard.DICT效率极高,极大优化API的响应时间 。
Redis BigKey优化:项目开发中BigKey是不可忽略的性能点,可能在前期开发以及压测时均可以完美达到设定值,但是线上环境效率不理想,这时候就要考虑bigkey的因素了 。由于bigkey占用内存较多,不但会使网卡成为瓶颈,在set、get也会阻塞其他操作,直接导致Redis吞吐量下降 。
在PC首页系统bigkey的定义范围为>5k,只要key的值大于5k均需要单独处理 。处理方案依然是2种 。1、业务上做切割 。例如一个业务场景需要将一个大的商品列表放到Cache中,一般做法是通过kv(set key value)保存到Redis中 。这时业务优化方案是将一个key扩展到1+n个key,一个key存储id list,其余n个key存储id对应的详情信息,这样就将bigkey打散为多个key 。2、技术上做切割 。例如系统定义的bigkey为5k,通过算法将value以5k的界限做切割,然后系统存储一个关系key以及n个小key实现bigkey转小key的过程 。
不管使用哪个方案,目标是一致的,避免bigkey的出现 。在将bigkey转小key的过程中,合理使用管道技术减少redis的网路消耗 。
分布式任务的使用:随着个性化推荐算法的推广,商城首页全面接入推荐算法 。由于个性化算法基于实时计算,耗时较高,为了保证用户浏览的流畅度,系统引入分布式服务 。如下图所示,用户在请求第一屏的时候将用户信息push到分布式任务系统,分布式任务利用时间差计算下面楼层的个性化数据并存储到Redis 。当用户访问到特定楼层即可快速加载数据 。
 
京东前台PC首页系统技术详解

文章插图
 
 
并发请求:每个API都会涉及多个上游RPC服务,为了避免串行请求带来的耗时累加,系统将每个上游RPC封装成单个子API服务,然后通过ngx.location.capture_multi命令实现并发请求来优化API耗时 。
磁盘IO优化:为了减少磁盘io,系统日志模块使用批量写入策略来减少磁盘io的消耗 。在OpenResty中每个请求(包含自请求)都会初始化一个 ngx.ctx全局表,首页应用将当前请求在不同阶段产生的日志内容统一写入ngx.ctx.Log表中,并在log_by_lua*阶段统一触发io操作将日志写入文件系统 。


推荐阅读