当前位置: 首页 > 科技观察

京东三级列表页持续架构优化——Golang+Lua(OpenResty)最佳实践

时间:2023-03-21 11:08:14 科技观察

接上一篇《京东三级列表页持续架构优化—前端优化实践》。品类列表入口品类列表入口可通过京东首页首屏左侧导航进入。是用户购买产品的主要入口之一。品类列表展示了每个品类的商品,包括综合排序、价格排序、销量排序、上架时间排序、图书和出版时间排序。您可以按品牌、价格和各种扩展属性筛选出所需的产品。下图以空调清单为例。分类列表特点分类众多,整个站点有上千个分类;商品多,每个品类有很多商品,有的品类有上千万种商品;需求是多样化的,不同品类的需求是不同的,比如大家电、书籍的需求。不一样;请求量大,实时性要求高。老架构老架构,前端使用nodejs做模板渲染,后端服务调用搜索接口。老架构的缺点:响应时间比较长;因为是搜索返回的数据,不方便对数据进行二次处理。升级新架构*新架构设计为分布式,数据可切分多个切片,服务层级可水平扩展;高可用,双机房双活部署;反应快;数据闭环,线上服务不依赖主数据,基于外部API;运维方便,集群切换方便,分类管理配置方便;数据提升,通过优化排序算法,提升GMV、订单转化率、客单价等。*新架构新架构功能模块如上图所示:页面渲染:使用OpenResty(Nginx+Lua)进行模板渲染,方便调整页面逻辑;业务处理:使用golang,所有过滤和过滤逻辑都在这一层处理;数据异构:页面渲染需要的相关数据,过滤筛选需要的数据都是通过异构得到的;消息处理:通过接入MQ消息,可以实时处理商品上下架、库存更新、价格变动等消息;质量分数计算:通过大数据平台计算商品质量分数,为综合排名提供依据;配置管理中心:负责后台调度、分类配置等,新架构上线流程如下图所示。新架构的离线数据流如下图所示。数据集市采用京东大数据平台;JSS是京东自主研发的分布式文件存储系统;JIMDB是京东自研的KV存储系统,可以作为分布式Redis使用。各模块详解*质量分的计算由于每个品类的产品很多,每个品类都有数千万个SKU,用户浏览的SKU有限,我们需要对用户最有可能购买的产品进行排名;针对每个品类所有SKU的质量得分计算涉及几十个指标(包括销量、评价、浏览量、转化率等);根据质量得分排序;由于涉及的数据量大,所有计算均在大数据平台上完成;将计算结果推送给JSS。由于有一些特殊的规则,比如品牌插入,店铺插入,特殊排序等,这些规则都是通过worker来实现的,worker读取jss,进行特殊的规则处理。将处理后的数据推送到MYSQL。*Heterogeneousservice异构服务主要是对需要的商品数据进行异构过滤和展示;调用外部接口形成广泛的产品表。如下图所示:*业务处理子系统上图展示了列表的各种过滤逻辑和排序逻辑。业务处理子系统提供前端所需的所有过滤接口,以及数据展示。系统采用golang开发,过滤后的数据全部存储在内存中,提高检索速度;显示的数据放在jimdb中,减少内存大小,缩短golang的GC时间。下图显示了存储在内存中的数据。*消息处理系统本系统接收并处理相关消息(商品变化、下架、价格变化、库存变化),并实时在线更新,如下图所示:*页面展示子系统页面展示子系统采用Nginx+Lua实现,负责模板的渲染,如下图所示。为了提高页面的渲染速度,有些页面使用了异步渲染。比如聚合页面缩略图,js可以渲染缩略图;如果扩展属性超过5个,js可以异步渲染。页面需要的价格数据、库存数据、广告数据都是异步加载的,保证了这些数据的实时性。页面渲染优化:HTML文档越简单,渲染越快,性能越好;例如:页面缩略图的聚合让js渲染缩略图;5个以上扩展属性允许js异步渲染;延迟加载数据,例如:滚动加载图片和页眉;资源加载排序,对每个资源进行优先级排序,优先加载必要的资源,将低优先级的请求保存在队列中,用于延迟加载或在必要的资源加载完成后加载。例如:热词搜索推荐、热销前三界面、价格优先加载。对于库存、促销信息、广告词、预售产品、店铺信息等,延迟加载;对于点击流,广告统计在加载前延迟两秒;更多页面优化参考:《京东三级列表页持续架构优化—前端优化实践》。Golang+Lua(OpenResty)*Golang的应用--JSON序列化性能低下遇到的坑:Golang内置encoding/json,encoding/gob,使用ffjson;GC问题:减少内存对象。减少对象申请,两个作用:减少内存占用,减少内存碎片;字符串拼接:尽量使用字节数组而不是String,因为String会创建新的对象;Go占用OS内存,缓慢释放:执行:debug.freeOSMemory();goroutineflashback:goroutine闪退,导致应用进程闪退,异常捕获;并发处理图:必须加读写锁(sync.RWMutex)。*选择Lua(OpenResty)Lua:轻量级、协程、嵌入式、开发效率高;OpenResty:OpenResty是一个网络应用开发框架,它封装了Nginx核心、LuaJIT、许多有用的Lua库以及Nginx第三方模块。**模板引擎https://github.com/bungle/lua-resty-template用于模板渲染。Nginx配置如下所示。该模板如下所示。**Cache缓存:为后端服务异常提供后台数据;当流量过大时,可以开启缓存,减轻后端服务的压力。缓存过程:解析url,对url进行hash,得到对应的key,从后端服务中获取数据,如果数据完整,渲染模板,将对应的数据放入对应的缓存中,将key放入keycache中,并设置缓存时间;pagecache永不过期,当key过期时,会主动更换;为什么要分两种缓存:第一页缓存只缓存每个分类首页的数据,这样就可以缓存所有分类的首页,保证所有分类都有后台数据。Otherpagecache缓存首页以外的页面,保证热点数据在缓存中。如果超过容量,就会被lru淘汰;为什么每个类型都缓存多个分片:因为lua_shared_dict有自旋锁,在单个分片读写压力大的时候会有一定的瓶颈,所以使用多个分片,每个分片的大小是设置的,根据具体缓存数据;firstpage和otherpage缓存在每台nginx服务器上,缓存内容有限;Redis缓存可以集中缓存,可以缓存更多的数据;**异常处理异常处理分为两层Backing,保证每一层都报错,异常可以处理,没有5xx错误等,提高用户体验,第一层backing,展示各分类的缓存主页;第二个靠山,跳转到京东首页。lua执行问题,通过nginx配置error_page,进入异常处理。界面响应问题,通过ngx.exec内部跳转进入异常处理。注意:error_page默认只匹配一次,多次匹配需要配置recursive_error_pageson;ngx.exec是内部跳转,类似于管道,数据流向单一,没有额外的http请求。新版本性能*页面渲染性能页面响应时间:模板渲染+业务筛选界面(go),平均30ms左右,tp99在80ms以内,快6倍以上;页面渲染(NGINX+LUA)TPS,并发100时,16核单机每秒3500笔,大约高出10倍。*服务筛选界面(GO)性能服务筛选界面(GO):平均10ms以内,tp99在50ms左右,响应时间提升6倍以上。作者:谢钢,京东商城架构师,负责京东分类榜、凤凰等系统的架构开发;曾在搜狐视频负责UGC视频架构开发。【本文来自专栏作者张凯涛微信?(凯涛博客),?id:kaitao-1234567】