百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

京东前台PC首页系统技术详解(京东前台是干什么的)

off999 2025-03-20 17:29 20 浏览 0 评论

京东零售系统在2018年实现前中台架构的调整与划分。中台实现基础服务组件开发,前台主要对接用户请求,通过对中台RPC数据的聚合,来满足用户多样化需求。其前台系统又分为首页系统、单品系统、搜索系统、列表系统、订单系统等等。

作为PC首页研发,本文主要讲解PC首页的技术实现。

PC首页业务逻辑从最初的模板渲染,到后来的SSI模块加载以及现在的前后端分离。开发语言也从之前的ASP、PHP逐步过渡到以LUA为主的技术框架。通过技术迭代升级,首页页面打开速度从之前的200ms缩减到30ms内,API性能从之前的500ms优化至100ms左右。

京东零售系统,每天承载着亿万网民的购物需求。PC首页又是京东商城的一级入口,所以系统必须达到以下3方面要求:页面完整性(容灾、兜底、降级);流畅的加载速度(高并发、页面加载优化、API加载优化);监控&告警。

下面将根据系统设定目标逐步讲解首页系统实现方案。

1.页面完整性

页面完整性指任何时候访问页面均需呈现正常的页面样式,不得出现天窗以及非200状态码(40x、50x等)。如下图楼层,若将单模块缺失直接呈现给用户,将导致页面天窗,影响体验。在单模块异常时,系统可对整楼层隐藏操作,优先保证页面完整显示。


下面从6方面讲解容灾降级的业务逻辑:

页面的容灾:前端页面主要承载页面骨架,也会包含部分开关配置及必要的兜底数据,即使后端API服务异常,html依然可以提供基础的用户体验。前端页面由模板渲染生成,其中模板变量通过配置中心(蜂巢系统)维护,定时worker触发生成前端页面,然后推送到静态资源服务器,最终通过CDN加速提供服务。其中在worker触发生成html阶段执行多层验证逻辑,保证html的完整性。

接口的容灾:一般接口逻辑均是优先读取缓存数据,若缓存失效则继续读取上游RPC数据来输出。但上游系统均不保证100%可用,如何保证在上游异常的情况下提供可靠服务使页面正常渲染呢?PC首页系统在接口层面做了2方面工作:

第一、接口在读取&聚合上游RPC数据后会保存两部分缓存,一个为正常用户加速缓存,一般会设置5min过期时间,一个是兜底缓存,永不过期。当缓存或者上游RPC服务均不可用时,接口会读取兜底缓存保证正常的数据输出。

第二、如果API服务由于自身问题(例如宿主机异常、Redis服务异常、用户网络抖动等)导致无法提供正常的服务怎么办。为了避免这个问题,系统为API提供了一条新的访问途径-CDN API。CDN API会访问由Worker定时生成的静态结果集(File)输出数据。当前端异步加载数据感知常规线路异常后自动触发CDN API线路来保证接口可用性。

依据上面2种兜底逻辑,绘制如下流程图,此逻辑将首页API服务的可靠率提高至100%。


接口的降级:如下图所示,正常情况接口通过读取Cache、RPC数据、兜底Cache提供服务。但如果Cache和RPC服务均异常,接口的响应时间就大大浪费在前两阶段(10ms+100ms)。为了避免此情况的发生,系统通过配置中心(蜂巢系统)设置降级开关,当系统感知降级开关打开时,将直接读取兜底Cache,保证API的响应速度。



NGINX的容灾:NGINX容灾指系统监控到接口非200状态码的时候在NGINX层面执行兜底逻辑,此兜底逻辑可以读取(或代理)远程静态资源实现透明容灾。具体实现通过error_page指令完成,error_page指令可以在特定的状态码设置一个named location,并在其代码块中执行相应的兜底业务逻辑。

楼层容灾:在多模块楼层,前端会调用多个API进行页面渲染。如下图所示,此楼层一共包含4个模块,每个模块均提供独立的API接口。当其中一个模块API异常,即触发楼层隐藏动作,避免天窗的出现。(这里执行的是页面可以有损但必须完整的策略)



终极容灾(页面CDN兜底):在2016年,启动“永不消失的首页”项目,即不论情况如何极端(包括Redis服务异常、服务器异常、RPC异常、网络异常等等),系统均可快速响应并切换至历史页面来保证页面完整。

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


(此项目自上线后尚未触发一次。在其他的业务场景中,需要考虑各自实际情况)


2.流畅的加载速度

既要保证页面完整性,也要保证页面以及API的加载速度。下面从性能方面讲解系统的优化方向。

技术选型

首页是一种重性能、轻逻辑的业务场景,没有过多的基础服务依赖,主要与Redis和上游RPC做交互。系统通过读取上游RPC数据后聚合、过滤、验证后输出,最终完成页面展示。用户请求简化流程图如下:



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



如上图所示,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。当用户访问到特定楼层即可快速加载数据。



并发请求:每个API都会涉及多个上游RPC服务,为了避免串行请求带来的耗时累加,系统将每个上游RPC封装成单个子API服务,然后通过
ngx.location.capture_multi命令实现并发请求来优化API耗时。

磁盘IO优化:为了减少磁盘io,系统日志模块使用批量写入策略来减少磁盘io的消耗。在OpenResty中每个请求(包含自请求)都会初始化一个 ngx.ctx全局表,首页应用将当前请求在不同阶段产生的日志内容统一写入ngx.ctx.Log表中,并在log_by_lua*阶段统一触发io操作将日志写入文件系统。

图片优化:电商系统页面会引入大量的图片,虽然图片系统引入CDN服务,但单个域在高并发的时候依然会有堵塞。为了解决单域问题,我们将图片部署到多个域上,例如img10.360buyimg.com、img11.360buyimg.com、img12.360buyimg.com等等。但多域会叠加DNS解析耗时,此时页面可以引入预解析指令(dns-prefetch)来减少dns的解析时间,提高图片加载速度。另外使用懒加载也是优化的一个技巧。

3.监控&报警

原有的报警信息通过 “系统日志->研发->产品->运营”的方式层层传递,不但处理问题时效长,而且占用研发资源。为了简化报警流程,现有系统直接将报警信息同步给产品&运营,减少信息流通环节,提高效率。

增加报警逻辑的同时不影响系统性能,系统通过异步非阻塞的ngx.socket.tcp组件实现消息同步。具体流程为系统将日志通过ngx.socket.tcp组件传递给分布式任务,分布式任务通过异步方式将日志同步到Elastic集群。报警系统根据报警规则触发报警信息发送。(注:使用ngx.socket.tcp组件请合理使用连接池,避免频繁建立连接)

小结

随着首页系统的迭代升级,团队沉淀了蜂巢系统平台以及OpenLua框架。蜂巢系统通过积木赋能、组件化思想搭建,可快速响应业务需求。OpenLua框架实现Lua的MVC分层结构,并融入京东内部组件,在满足API性能的同时提升开发效率。

继续前行,永不止步。在之后的的研发道路上,将继续沉淀业务需求,强化组件化、标准化思想,深耕蜂巢系统、OpenLua框架,使之更加灵活、高效、易用。

相关推荐

使用 python-fire 快速构建 CLI_如何搭建python项目架构

命令行应用程序是开发人员最好的朋友。想快速完成某事?只需敲击几下键盘,您就已经拥有了想要的东西。Python是许多开发人员在需要快速组合某些东西时选择的第一语言。但是我们拼凑起来的东西在大多数时候并...

Python 闭包:从底层逻辑到实战避坑,附安全防护指南

一、闭包到底是什么?你可以把闭包理解成一个"带记忆的函数"。它诞生时会悄悄记下自己周围的变量,哪怕跑到别的地方执行,这些"记忆"也不会丢失。就像有人出门时总会带上...

使用Python实现九九乘法表的打印_用python打印一个九九乘法表

任务要求九九乘法表的结构如下:1×1=11×2=22×2=41×3=32×3=63×3=9...1×9=92×9=18...9×9=81使用Python编写程序,按照上述格式打印出完整的九...

吊打面试官(四)--Java语法基础运算符一文全掌握

简介本文介绍了Java运算符相关知识,包含运算规则,运算符使用经验,特殊运算符注意事项等,全文5400字。熟悉了这些内容,在运算符这块就可以吊打面试官了。Java运算符的规则与特性1.贪心规则(Ma...

Python三目运算基础与进阶_python三目运算符判断三个变量

#头条创作挑战赛#Python中你学会了三步运算,你将会省去很多无用的代码,我接下来由基础到进阶的方式讲解Python三目运算基础在Python中,三目运算符也称为条件表达式。它可以通过一行代码实现条...

Python 中 必须掌握的 20 个核心函数——set()详解

set()是Python中用于创建集合的核心函数,集合是一种无序、不重复元素的容器,非常适合用于成员检测、去重和数学集合运算。一、set()的基本用法1.1创建空集合#创建空集合empty_se...

15个让Python编码效率翻倍的实用技巧

在软件开发领域,代码质量往往比代码数量更重要。本文整理的15个Python编码技巧,源自开发者在真实项目中验证过的工作方法,能够帮助您用更简洁的代码实现更清晰的逻辑。这些技巧覆盖基础语法优化到高级特性...

《Python从小白到入门》自学课程目录汇总(和猫妹学Python)

小朋友们好,大朋友们好!不知不觉,这套猫妹自学Python基础课程已经结束了,猫妹体会到了水滴石穿的力量。水一直向下滴,时间长了能把石头滴穿。只要坚持不懈,细微之力也能做出很难办的事。就比如咱们的学习...

8÷2(2+2) 等于1还是16?国外网友为这道小学数学题吵疯了……

近日,国外网友因为一道小学数学题在推特上争得热火朝天。事情的起因是一个推特网友@pjmdoll发布了一条推文,让他的关注者解答一道数学题:Viralmathequationshavebeen...

Python学不会来打我(21)python表达式知识点汇总

在Python中,表达式是由变量、运算符、函数调用等组合而成的语句,用于产生值或执行特定操作。以下是对Python中常见表达式的详细讲解:1.1算术表达式涉及数学运算的表达式。例如:a=5b...

Python运算符:数学助手,轻松拿咧

Python中的运算符就像是生活中的数学助手,帮助我们快速准确地完成这些计算。比如购物时计算总价、做家务时分配任务等。这篇文章就来详细聊聊Python中的各种运算符,并通过实际代码示例帮助你更好地理解...

Python学不会来打我(17)逻辑运算符的使用方法与使用场景

在Python编程中,逻辑运算符(LogicalOperators)是用于组合多个条件表达式的关键工具。它们可以将多个布尔表达式连接起来,形成更复杂的判断逻辑,并返回一个布尔值(True或Fa...

Python编程基础:运算符的优先级_python中的运算符优先级问题

多个运算符同时出现在一个表达式中时,先执行哪个,后执行哪个,这就涉及运算符的优先级。如数学表达式,有+、-、×、÷、()等,优先级顺序是()、×、÷、+、-,如5+(5-3)×4÷2,先计算(5-3)...

Python运算符与表达式_python中运算符&的功能

一、运算符分类总览1.Python运算符全景图2.运算符优先级表表1.3.1Python运算符优先级(从高到低)优先级运算符描述结合性1**指数右→左2~+-位非/一元加减右→左3*//...

Python操作Excel:从基础到高级的深度实践

Python凭借其丰富的库生态系统,已成为自动化处理Excel数据的强大工具。本文将深入探讨五个关键领域,通过实际代码示例展示如何利用Python进行高效的Excel操作,涵盖数据处理、格式控制、可视...

取消回复欢迎 发表评论: