阿里巴巴淘系技术

阿里巴巴淘系技术 查看完整档案

杭州编辑  |  填写毕业院校淘宝  |  技术专家 编辑 tech.taobao.org 编辑
编辑

阿里巴巴集团淘系技术部官方账号。淘系技术旗下包含淘宝技术、天猫技术、闲鱼技术、躺平等团队和业务。我们服务9亿用户,赋能各行业1000万商家,并成功主导了11次阿里巴巴经济体双十一技术大考,打造了全球领先的线上新零售技术平台。
我们的愿景是致力于成为全球最懂商业的技术创新团队,让科技引领面向未来的商业创新和进步。
公众号关注:淘系技术

个人动态

阿里巴巴淘系技术 发布了文章 · 11月25日

阿里亿级长连网关的云原生演进之路(2020最新沉淀)

导读

AServer接入网关承载整个阿里集团的入口流量,负责亿级用户的长链保活,支持上万路由策略转发,是连接上亿用户与后端几十万服务节点的桥梁,在今年双十一需要支撑亿级在线用户、千万级QPS、生效上万条API管控策略,做到了安全可靠的转发路由,并保障了用户体验如丝般顺滑。

在大规模业务流量与管控支撑的背后,需要对系统每一个细节的精确把控,消除每一个潜在的风险点。

借助云原生架构可以极大地简化运维操作,降低了潜在的风险,今年双十一阿里AServer接入网关上千台规模的Pod平稳扛过峰值。本文主要介绍阿里AServer接入网关如何从上一代架构拥抱变化,全面云原生的演进之路。

(更多干货请关注【淘系技术】公众号)

一、架构演进背景

每年双十一大促都是对阿里所有服务最严峻的考验,尤其对AServer接入网关来说,作为阿里集团第一道门户,需要抵御大促峰值带来的流量洪峰,清洗攻击流量,所需集群规模巨大。

巨大集群规模,以及对机器性能极致要求,导致了运维上的复杂性;随着接入业务的增多,所支持的业务场景扩宽,业务对路由策略的灵活性、生效的实时性要求变高,对路由策略的动态编排能力有着强烈诉求;由于业务的多样性,业务线不同封网节奏,以及故障隔离性,衍生出对流量隔离的稳定性诉求。

运维的复杂性、动态编排的诉求、流量隔离以及对性能的极致要求,推动着AServer接入网关不断演变和成长,紧跟业务的发展步伐的同时,逐步降低运维成本的,增强系统稳定性,能够一次又一次经受住双十一的考验。

1.业务背景

作为阿里集团AServer接入网关,承载整个阿里集团入口流量,最开始支持域名转发策略的tengine网关,根据域名 转发到后端不同服务,业务形态相对简洁。

来到All in无线时代,为优化手机端侧的用户体验,同时降级服务端人员的开发成本,集团自研了MTOP(Mobile Taobao Open Platform)API网关,为客户端和服务端提供了一致的API平台,相同的域名,仅通过URI携带的API信息转发到对应业务,接入网关需要支持按照API(通过URI区分)的路由转发能力,几年时间迅速增加到数万规则。

随着业务发展越来越精细化,期望对同一API下的不同业务场景进行细分,如针对双十一大促会场的来源,手淘、支付宝、其他外投页面等场景进行更精细化控制,为适应业务发展,网关需要支持精细化的管控能力,根据业务请求参数、请求头进行管控和分流。每一个请求都要从上万灵活的配置规则中匹配出唯一的路径,同时又要保持极高的性能,是一件极具挑战性的事情。

image.png

(业务模型图)

2.运维体系背景

最开始基础配套的基础设施并不完善,网关层基于tengine搭建,最简单快速的方案便是使用物理机,部署进程和配置即可完成服务搭建。随着业务增长,配置管理就成为瓶颈,网关层需要一个强有力的配置管理平台,通过标准化的方式生成业务配置,配套自研的配置管理平台把配置划分为应用配置、公共配置管理、证书配置三部分。

  • 公共配置:通过Git版本管理方式生成tengine运行的基本配置,如启用模块配置,tengine运行逻辑配置
  • 应用配置:通过标准的模板生成业务所需的tengine配置
  • 证书配置:由于证书存在有效期,为了防止过期时忘记更新,还承担了证书自动更新任务

最初的系统部署架构:

image.png

该方案可以实现业务自助接入,通过配置管理平台的模板生成 tengine 配置,再由定时推送到网关机器并进行进程的reload,生效配置。

通过这种运维方式,不依赖基础设施,可以快速演进,但随着业务增长以及集群规模的上涨,物理机的运维方式弊端逐步显现,野蛮生长的时代过去,作为阿里服务入口,稳定性成为了重中之重,物理机的二进制发布依赖人工部署,需批量执行命令安装rpm包,并且分批restart进程,这一切都是黑屏操作完成。

此种运维方式显然无法满足现在的稳定性需求,通过手工发布,极易出现误操作导致系统性故障。另外物理机运维很难进行一致性保障,包括二进制的一致性,机器本身环境的一致性检查(如内核参数等),过去的手工运维方式显然已经跟不上时代的步伐。

解决发布和环境一致性问题的最优方案便是容器化技术,随着集团基础设施的完善,接入网关容器化改造扫除了障碍,把不变量(系统配置、二进制)打包成一体进行发布,把变量(应用配置、公共配置、证书)继续沿用配置管理平台进行管理,配合容器化技术进行调整。

容器化改造后的发布和配置变更流程:

image.png

容器化架构,简化了建站、扩缩容操作,发布效率有了极大的提升,增加审批流程,系统化卡点,避免了人为操作可能导致故障,发布流程还可对接监控系统,自动告警并暂停发布。

3.核心问题

随着电商业务发展越来越快,规模化达到瓶颈以后,业务就会有更多的横向扩展,精细化程度越来越高,迭代速度也随之变高,网关层适应业务的变化的成本也来越高,由此带来的核心问题:

  • 运维操作复杂性:由于对性能的极致要求,网关集群对机器有着特殊的要求;由于网关配置管理的特殊性,导致了运维操作的复杂性;特殊性的存在无法很好对接集团现有运维体系,需要进行运维体系的升级;
  • 动态编排能力不足:随着接入业务的增多,所支持的业务场景扩宽,业务对路由策略的灵活性、实时性要求越来越高,静态配置不论生效的实时性还是策略灵活性都难以满足业务发展需求,需要支持路由策略的动态编排能力;
  • 流量隔离成本较高:缺乏轻量级业务范围隔离能力,通过新建集群实现的成本过高,为支持业务线不同封网节奏,以及支持故障隔离性,需要轻量级的多集群流量隔离方案。

云原生近年来的飞速发展,也为网关层提供了更好的架构选择。

二、云原生架构

为解决接入网关现存问题,结合集团业务场景以及云原生的开源体系,开启了AServer接入网关的云原生演进之路,为了分步验证,分解三个阶段逐步实现:运维体系升级,服务治理&网关Mesh化,南北向架构拆分。接下来对每一个步骤进行详细的演进说明。

1. 运维体系升级


1.1 待解决问题

通过容器化升级部署,极大的简化了部署运维方式,能够解决当时最突出的问题,但仅仅改造部署方式还远远不够:

  • 由于接入网关有着特殊性(如需要对接配置管理平台,有着大量的VIP需求),无法直接对接集团的基础设施,开发了独立的定制化化的运维工具,扩缩容流程需要多个基础组件通过非标接口配合进行,极大的影响了运维产品的迭代效率
  • 故障机置换机器等操作,依赖外部系统轮询检测,并且集团基础设置系统跟定制运维平台对接才能处理,有较大时延
  • 运维操作脱离集团运维体系

1.2 演进思路

随着集团内针对云原生应用设计的统一基础设施ASI(Alibaba Serverless infrastructure)的逐步完善,提供了基于原生K8S API的完整云原生技术栈支持。

云原生方案可编排能力很强,通过自定义实现k8s扩展,非常容易抹平网关层的特殊性,ASI 原有的自动化运维手段,可直接应用于网关层。

网关层对机型的特殊性,可以通过节点池划分来实现,网关机器节点池可自定义机型以及内核参数,消除网关运维上的特殊性,统一管理运维。

1.3 演进方案

通过 k8s 自身的 Controller 扩展能力,自定义容器编排,在扩缩容时可以监听Pod变更事件对配置管理平台进行机器增删操作,同时也可以挂载/卸载VIP,抹平运维上的特殊性,并且所有资源都通过声明式API定义,方便运维。

对于网关运维,还需要保留一个非常简单的运维平台,仅做建站之用,对比普通应用,网关建站需要在对应区域创建VIP,进行域名绑定等操作,轻量且易维护:

image.png

通过进行ASI化改造,使得接入网关的运维融入集团ASI云原生体系(提升交付效率,去除特殊化运维),通用能力下沉至ASI和基础系统,同时具备了风险隔离、自恢复、弹性能力

  • 风险隔离:使用Sidecar能力隔离安全和工程能力,避免二者的互相干扰,安全能力出现异常,只影响流量清洗,降级安全能力后,不至于服务整体不可用;
  • 自恢复:对于容器自愈能力,原有容器化方式依赖外部应用的轮询检测,不论是准确性和实时性达都有所欠缺,升级ASI后,通过容器自身的检测,可在3-5分钟内识别并置换故障容器;
  • 弹性能力:自动弹性能力,通过ASI的改造,各系统的对接方式可以使用标准的声明式API,整合集团内各组件,极大的简化了扩缩容操作,为自动弹性提供了支持;
  • 屏蔽机型差异:通过节点池划分,针对网关应用可使用特殊的机型,底层配置屏蔽差异,无需特殊操作。

2.服务治理&网关Mesh化

2.1 待解决问题

随着网关层接入的业务类型增多,需要支持上万条API路由规则,而且路由策略也越来越精细化,使用tengine原生能力无法满足业务需求。通过定制开发tengine模块,非标的定义方式,过去几年中可以很好适应业务的发展,但随着业务诉求愈发精细化,定制开发tengine模块的成本也逐步变大

image.png

原有架构

  • 路由配置通过模块配置+原生配置组合而成,多个模块配置共同决定路由策略,分散的配置无法对一个请求完整的路由路径的识别;
  • 通过功能模块划分,想要按照业务粒度的进行增量更新较难实现;
  • 基于tengine架构,动态变更能力不足,域名变更每日定时推送配置并生效,无法满足业务快速迭代需求;
  • 非标准协议直接跟不同管控平台直接对接,对接成本较高,并且不容易收口管控;
  • 对于不同业务线(如淘系、优酷),要做到资源隔离,由于多数模块配置使用静态的公共配置,建站成本较高。

2.2 演进思路

如何动态编排、精细化的控制路由策略,是在云原生体系下首要考虑的问题。参考对比业界网关层做法,如Kong,Ambassador等,主流网关数据面实现都是基于nginx或者envoy,不同产品的扩展性、动态编排能力、成熟度的对比情况:

image

从动态性、标准性、性能方面综合考虑,使用envoy作为数据面更适合云原生演进方向:

  • 动态性和灵活性
  • envoy实现的标准xDS协议足够灵活,并且可全部动态配置和变更
  • envoy扩展性足够好,可通过实现filter扩展实现集团内特有的路由逻辑
  • 标准性
  • istio标准组件,社区支持力度大,发展迅速
  • 阿里集团mesh化使用istio技术方案,使用envoy作为数据面选项能够跟集团业务管控的统一化
  • 性能
  • C++实现,性能足够好,而开发效率比tengine高

而envoy不足之处在于作为istio标准组件,东西向路由能力较强,作为南北向需要进行一定性能和稳定性优化,但长远来看,动态性和标准性更为重要。

2.3 演进方案

复用集团Pilot作为统一的控制面组件,实现网关自身的Mesh化:

image.png

控制面为提供各透出的业务产品写入,需提供一层管控逻辑进行权限的收口,各产品通过k8s声明式api写入路由策略,再由Pilot控制面转换为xDS数据面协议,实时同步给数据面Envoy,南向路由网关的实现架构:

image.png

由于集团的配置规模较大,数十万的路由规则和数千应用,几十万业务节点,开源体系鲜有如此规模。Pilot + Envoy方案应用于南北向网关后,需要对原生组件做一定的优化和定制,以解决规模化引起的性能和稳定性问题:

  • Pilot支持SRDS协议:解决大规模API配置导致的线性匹配性能问题
  • 增量配置更新:实现并完善控制面增量更新能力,避免全量更新导致变更半径扩大风险
  • 节点变更优化:解决几十万业务节点的状态变更对控制面和数据面性能影响
  • 扩展定制:针对集团特有的路由规则,定制filter实现

通过对开源体系进行定制和优化,可以很好的对接集团内的需求,通过灵活的配置组合,通过快速迭代控制面透传的能力,实现集团内不同业务的特殊需求。

3.南北向拆分

3.1 待解决问题

网关作为用户跟业务的桥梁,对用户端保活长链,协议优化,让用户尽可能快速稳定的连到集团;对业务支持灵活的路由和熔断限流策略,负载均衡。虽然连接保活跟路由转发作为网关的整体能力透出,但二者的迭代效率的诉求,以及业务特点都有较大差异。

在一些大促活动场景,即使有预期外的流量洪峰,网关层作为保护业务服务的屏障,仍然可以做到稳如磐石,依赖于高性能和水位的预留。考虑到保活长链,协议优化有这较长的迭代周期,性能极高;路由转发和流量清洗由于策略灵活复杂,资源消耗自然相对较高,如把二者进行架构拆分,可以极大的提升整体资源的使用率。

3.2 演进思路和方案

把协议卸载、长链保活等跟客户端交互,并且能够保有极高性能的模块,单独拆分为北向集群,由于性能很好,只需要少量的机器,便可筑高坝挡洪流;对于跟业务路由策略相关,以及安全清洗能力,消耗性能较多,拆分到南向集群,通过北向的高坝保护南向集群不会过载,南向集群可减少预留水位,进而提升整体的资源利用率,如此可做到即能够提升资源利用率,又可进行灵活配置适应业务快速发展的需求。

image.png

4.整体架构

通过三个阶段演进,终局架构图如下:

image.png

AServer接入网关云原生架构

  • 统一控制面:通过集团统一控制面进行服务接入、服务发现、熔断限流控制,起到变更收口统一处理的作用;
  • 北向连接层:基于tengine承载亿级在线用户和流量洪峰,起到高水坝作用,提升南向路由层资源利用率;
  • 南向路由层:基于Envoy通过Pilot转换xDS协议动态下发路由策略,实现动态编排路由、轻量级流量隔离方案;
  • 云原生基座:运维操作建立在集团统一基础设施ASI,屏蔽网关差异性,降低运维复杂性。

三、未来

阿里AServer接入网关一步步向云原生演进,每次演进都是基于长久以来困扰我们的问题,但又不仅仅止步于解决问题,同时基于当前时代的解决方案,云原生架构改造也远不是终点,云原生的优势也尚未完全发挥。技术的升级最终是为产品服务,云原生升级之后,让我们有了一个强有力的引擎,接下来需要做的就是利用这个引擎改造产品形态,让基于网关之上的开发者最终受益。

1.产品整合

什么样的状态才是一个网关产品最好的状态呢?开发者每天都在使用,但又无需关心网关的存在,这样存在感最低的状态或许就是最优的状态。当前接入网关从产品形态上暴露了一些实现细节,一个入口应用上线需要通过若干不同系统交互才能完成接入,在云原生改造完成后,可以更好的实现All in One,产品上做到一体化和闭环。

2.快速弹性

虽完成ASI Pod升级改造,可自动化执行故障机置换,机器迁移等操作,降低了运维成本,但上云最重要的一项能力就是快速弹性,如可以在双十一峰值大促前快速扩容,大促过后快速缩容,可极大减少为准备大促所保有的机器资源,从而节省巨量的成本。当然其中要解决的问题也很多,如安全性可靠性,弹性的实时性,这都需要配合云的基础设施共同建设,真正发挥云上的优势。

加入我们

淘系架构与基础服务团队

致力于为淘系和阿里提供基础核心能力、产品与解决方案:

  • 下一代网络协议QUIC的实现与落地 - XQUIC
  • 自适应高可用解决方案与核心能力 - Noah
  • 新一代业务研发模式平台 - Gaia
  • 支撑整个阿里的移动中间件体系(千万级QPS接入网关、API网关、推送/消息、移动配置中心等)

团队大牛云集~~ 想要加入我们,请邮件简历至:miaoji.lym@alibaba-inc.com

(更多干货请关注【淘系技术】公众号,每日更新阿里工程师技术干货)
查看原文

赞 1 收藏 0 评论 0

阿里巴巴淘系技术 发布了文章 · 11月24日

在千亿的成交额背后,前端工程师是如何做“资损防控”的?

前言

资损 —— 顾名思义就是平台发生了与用户或客户心理预期不符、直接或间接产生经济损失的场景。

一直以来,资损问题就在我们的生产环境中不断发生,而且随着业务的规模和疆土不断扩大,经济损失的规模也在不断扩大,这直接对平台、客户和用户都产生了非常不良的影响。尤其在某一时间段连续发生高资损风险问题,恶劣程度上升到集团,对平台的生产和运营产生很高的负面影响,所以大家高度重视资损风险的防控。

本文希望通过我们的思考以及淘系双 11 的实践为大家提供一些资损防控的经验参考,也欢迎大家提出宝贵的意见。

(更多干货内容请关注【淘系技术】公众号,每日更新阿里工程师技术干货)

探索之路

在资损防控方面,服务端比前端起步要早,而且做得也非常专业,比如各种离线或实时的容灾幂等检查、链路对账告警、关键配置巡检、关键标巡检等等。

然而对于前端而言,阿里淘系技术部是从 2019 年双 11 前夕开始才开始重视起前端资损防护问题,所以一年前并没有沉淀什么产品化方案,当时能采取的手段就是对案例的总结、对问题的定义、对程度的定级、对红线的定论,通过一些规章制度、学习考试的手段来强化资损防控的文化意识,通过一些人肉盘点、case by case 的人工预演方式来规避资损风险保障业务的稳定。比如下文,就是人工预演这个很直接的土办法的介绍。

人工预演

由于缺少产品化手段,去年的双 11 、双 12 等大促,前端采用的都是人肉盘点、人工预演的土办法来做保障。我们分析了前端所有可能出现的资损风险点,并制定了一套前端的专属资防规章制度和风险编码表,并围绕这些资损风险点,盘点所有参与双11的业务前端代码,对资损问题的识别、预防、止血和恢复过程进行详细的人工预演。

印象中 2019 年双 11,前端 C 端资损防控,总共进行 6 天,每天 2 场(下午与晚上),每场平均 3.5 小时,大概 4 位评委,共进行 73 例预演,每例预演大概 15 分钟且至少 2 位预演者参与,耗费人力总成本均值在 200 小时(折算 25 人日),这个数字相比双 11 整体的人力投入水平来说,也是非常恐怖的。

通过上述方式,过程中我们属实提前发现了一些资损风险问题,虽然最后每场大促线上都没有出现资损问题,但这个土办法在过程中人力和时间消耗还是非常恐怖的,而且防控效果如何完全依赖当时现场的评委 review 的效果好坏。由此可见,人工预演这种方式不仅时间和人力成本过高,而且防护效果有限,并不适合作为长期的防控手段。所以,我们向前探索准备通过一些产品化的手段来解决防控效果和成本问题,就有了如下的一些尝试。

前后端对账

如上文所提,受人工预演方式的成本、防控效果限制,我们去年双 12 之后开始尝试资损防控的产品化方案设计。根据以往权益营销活动出现过的资损案例来看,当消费者看到的权益信息与实际到账的权益信息不一致时,容易引起大面积客户投诉。譬如:

  • 某短视频业务在权益发放时,在消费者领取成功单品优惠券时错误地表达成了红包;
  • 某红包发放业务错误地使用红包列表接口作为中奖结果表达,发现时长长达10.5小时

对于上述这类权益信息前台展示和后端发放不一致的问题,及时的监控报警对于止血、控制资损规模至关重要。为此,我们针对类似问题为业务产品的生产阶段设计了一套前后端对账的产品化方案。

前后端对账的整体思路如下:

image.png

对账方案整体涉及采集层统一接入、数据实时处理对账以及报警订阅,具体如下:

  • 接入层:前端封装统一的 SDK ,覆盖 web、weex 和 miniapp,在页面端采集权益的关键信息;
  • 数据层:基于 Blink 进行数据实时处理,存储到 SLS 日志以及 METAQ 消息,并通过后端平台订阅日志消息进行实时对账;
  • 应用层:订阅权益的对账消息并打通实时报警流程,以及通过 SLS 日志,查看权益的实时大盘以及模块治理。

然而,项目上线一段时间后,我们发现效果并不如预期:

  • 一方面,由于前端 SDK 对业务代码是有一定侵入性的,所以各方业务在接入前后端对账时,或多或少还是存在一定的成本。尤其是对一些稳定的线上老业务,反而容易在改造时引入新的问题;
  • 另一方面,前端 SDK 采集的权益信息无法直接从 UI 展现层识别(金额可能被截断),从报警情况来看,发现的问题均是各方的业务开发同学上报错权益字段而非真的前后端权益不一致导致的误报。

从实际表现来看,我们原本期望用前后端对账的方式能够及时发现业务产品在生产阶段中权益信息在前端表达和服务下发不一致的情况,然而这套方案由于前端拿不到 UI 的利益点字段、问题发现率很低且存在一定接入成本等原因,并不能满足我们的需求,我们只能继续探索其他的资损防控手段。所以我们把目光聚焦到业务产品的研发阶段,看看能否从产品的研发阶段中探索出一些资损预防的产品化手段出来,所以就有了以下的尝试。

静态代码扫描

在尝试前后端对账方案不足预期后,我们开始重新思考:人工预演的方式可以帮我们发现潜在的资损风险问题,但其主要问题在于需要投入大量人力和时间成本,那么为什么不想办法降低这个成本呢?

为此,我们从代码的 CcdeReview 过程中摸索出了一种 基于 AST(Abstract Syntax Tree,抽象语法树)的前端代码静态扫描方案,可以在一定程度上规避金额计算、数字造假、数字歧义、文案过期等问题。这种机器替代人为 CodeReview 的方式,不仅省去了人力成本,而且还为 CR 的质量提供了一道基准保障。

静态代码扫描的整体方案思路如下:

代码扫描.png

其背后具体的原理介绍如下。

AST

在计算机科学中,抽象语法树(Abstract Syntax Tree,AST)或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。

这是摘自百科上对 AST 的一段解释,我们再来看一个 code ⇌ AST 相互转换的简单示例:

image

如上所示,代码片段 var str = "hello world" 被拆解成了多个部分,最终以一棵树的形式表示出来(如果想查看更多源代码对应的 AST,可以使用神器 astexplorer 在线尝试)。

代码扫描的基础正是建立在仓库代码的 AST 解析和遍历之上的,为此,我们需要借助 Babel 来完成这部分工作

Babel

Babel 其实是一个 JavaScript 编译器,主要用于在旧的浏览器或环境中将 ECMAScript 2015+ 代码转换为向后兼容版本的 JavaScript 代码。

简单来说,为了将 ES2015+ 代码转换成向后兼容版本代码(比如 ES5),Babel 每次都需要先将源代码解析成 AST,然后修改 AST 使其符合 ES5 语法,最后再重新生成代码。总结一下就是 3 个阶段:

parse -> transform -> generate。

由上可以看到 Babel 不但完成了 AST 的解析工作,而且由于其编译 js 代码的使命,它还提供了一套完善的 visitor 插件机制用于扩展。有关 『如何自定义 Babel 插件』,可以查看这份 Babel 插件手册。根据手册,我们就可以使用以下代码添加自定义规则来完成代码扫描任务:

image

自定义规则

介绍完 AST 和 Babel 后,我们再回到资损防控问题上来。根据以往的经验来看,前端容易造成资损/舆情的代码往往有:

  • 金额赋默认值
  • 金额计算
  • 数字造假、固定金额/积分
  • 过期时效文案
    ...

因此,我们就可以根据上述这些 case 自定义规则来编写 Babel 插件。就拿 『金额赋默认值』 为例,我们可以列举日常代码中的一些 bad cases,然后使用 astexplorer 分析其 AST,最后再针对性地编写匹配规则即可。

image

case 1: 直接赋默认值

image

根据上面的 code vs AST 关系图可以看到,我们只要找到 VariableDeclarator 节点,且同时满足 id 是金额变量,init 是大于 0 的数值节点这两个条件即可。代码如下:

image

case 2: ES6解构语法赋默认值

image

观察上面的关系图,我们可以得出结论:找到 AssignmentPattern 节点,且同时满足 left 是金额变量,right 是大于 0 的数值节点这两个条件。代码如下:

image

case 3: "||"运算符赋默认值

image

上图的规则同样也不复杂,但需要注意一点:实际代码中,= 右侧的赋值表达式可能会复杂的多,甚至包含了一些逻辑运算。因此,我们需要改变策略:遍历右侧的赋值表达式中是否包含 "|| 正数" 的模式。代码如下:

image

通过上述的3个例子,我们就已经能把绝大部分 『金额赋默认值』 的代码给扫描出来。其他的一些场景也是如此,只要根据代码生成的 AST 找到规律,然后编写对应的 Babel 插件即可。

小结

然而,静态代码扫描工具虽然能够帮助我们从代码层面上发现一些共性问题,但面对不同的业务逻辑仍然是没有感知的,以至于不容易挖掘出代码中深层次的问题。因此,在面对 UI、多态、复杂交互逻辑等场景时,纯靠静态代码扫描不足以完全解决问题。所以在第一道防护工序之后,我们又设计了第二道防护工序,具体介绍如下。

UI 测试扫描

根据以往发生的资损故障来看,问题往往多发生在代码变更时,开发同学的新改动影响到了业务的原有功能,而测试同学又恰好没有回归到这点。对测试同学而言,业务每次的全量回归工作量是巨大且重复的。就拿领取红包的例子来说,不同的账号(人群)、领取成功、网络超时、重复领取、没有资格、服务故障等等都是资损通常需要考虑在内的测试用例。此时,如果能有一个 UI 自动化回归测试工具,既能为业务提供一个保障,又能解放测试同学。然而,传统的 UI 自动化测试需要开发同学编写对应的自动化测试代码,不但有上手成本,而且还造成了额外的工作负担。

为此,我们又提出一种 基于录制/回放的 UI 测试扫描方案:开发/测试同学只需提供一个可正常访问的页面地址,正常的功能测试录成测试用例,在项目发布的时候就会进行一次页面回放,最后再通过 UI 测试用例快照比对的方式判定本次功能回归是否通过。

UI 测试扫描的整体思路如下:

image

其背后的原理介绍如下。

页面代理

代理页面本质是一个 web 服务,它通过 url 参数方式接收原始页面链接和注入脚本地址,由服务器请求原始页面返回对应的 html 文档,并且在返回文档头部注入接口拦截脚本、调试工具脚本以及url参数中取得的自定义注入脚本。代理页面拥有和原始页一样的 html ,同时也会添加上原始页的 query 参数,直接访问代理页除了 js 的 location 变量,其他环境和原页面相差无几。至于 location 变量,试了很多方案,发现都改写不了,一重写页面就跳转,多次尝试无果后我们发现可以换个思路解这个问题,既然重写不了我们就替换掉它,我们将页面所有的 script 脚本包了一层 with,如下图所示,我们将页面内所有的js脚本的上下文改写,使之读取的 location 是被我们重写的,从而达到代理页的渲染运行结果和原始页一致的效果。

image

录制脚本

通过上述的页面代理,我们就可以在访问原页面的时候注入我们的录制脚本。为了能够支持页面的回放,录制的时候就要提供两份数据:

  • 录制期间产生的所有网络访问数据
  • 用户操作数据(包括点击、滚动等)

要想记录网络访问的数据并不难,此处不展开多述,可以借用 AOP 的思想,在网络请求的回调中增加一个 interceptor ,同时保存下本次请求的 url,param,response,以便回放的时候匹配使用。

再来看下又该如何劫持用户的操作数据,其实在 h5 页面中,用户的任何触摸操作都会依次触发 onTouchStart、onTouchMove、onTouchEnd 事件,所以我们只需拦截这三个事件对应的 targetEvent 参数即可。就拿拦截 onTouchStart 为例:

image

如上可以看到,我们记录下了触发事件的事件类型、节点选择器、时间戳、页面距离顶部高度以及坐标位置等信息,这些都是回放时必不可少的数据。

再来看页面的滚动拦截,只要劫持 onScroll 事件即可。不过这里需要注意一点,页面滚动分两种:手指接触屏幕时的拖动,手指离开屏幕后的惯性滚动。前者会同时触发 onTouchMove 和 onScroll,而后者只会触发 onScroll。

image

回放脚本

回放脚本同样依赖代理页面的注入能力,但做的事刚好和录制脚本相反:

  • 拦截请求,使用录制时记录的网络数据 mock
  • 按照时序依次派发 touchEvent 事件

类似地,拦截请求和录制时的原理大体一致,只需根据本次请求的请求参数从录制时拦截的数据中找到对应的匹配即可。

再来看下如何根据时序派发 touchEvent 事件来模拟回放,核心代码如下:

image

派发事件是基于 dom 的 dispatchEvent 方法,可以参考 MDN 文档,代码如下:

image

快照对比

难点分析

根据前文的介绍,我们已经可以分别拿到录制和回放的最后一帧快照,所以接下来我们就希望设计出一套算法对这两个快照做内容一致性的自动化判断。从不同的输入案例来看,我们主要面临以下的几个难点:

  • 相同文字在不同型号的手机上会有不同的字体字号显示,像素级比对会将相同文字误判为不一致。
  • 对于红包等弹层图片,只需关注红包弹层信息是否一致,无关的背景会导致模型误判。
  • 由于回放/录制在时间戳上无法保证严格一致性,两张快照往往存在位置上的位移偏差。

算法设计

整体的算法流程如下图所示,下面我们分步骤阐述算法思路。

image.png

  1. 首先对两张快照计算 SIFT 相似度进行初筛。匹配的核心问题是将同一目标在不同时间、不同分辨率、不同光照、不同方向的情况下所成的像对应起来。图像的局部特征,对旋转、尺度缩放、亮度变化保持不变,对视角变化、仿射变换、噪声也保持一定程度的稳定性。相似度低于阈值的两张快照判为不通过,通过快照会做进一步精细比对。
  2. 针对弹层图片,需要预先对背景等无关信息做去除,仅保留弹层信息。这边先将图片从 RGB 空间转换成 LUV 空间。L 分量会保留图片的亮度信息,便于根据亮度值二值化图片,去除无效背景,效果如下。

img2.jpg       tmp_img0.jpg

  1. 将预处理好的干净图片送到 OCR(光学字符识别) 模型,提取出文字内容及相对应的坐标信息。针对像素过小的文字信息进行删除,往往是噪声产生的错误信息。
  2. 按照返回的坐标信息进行文字的位置还原,方便下一步做内容比对。
  3. 由上一步产出的结果进行内容比对,在图上标注出两张快照不一致的地方作为输出,算法结束。

效果演示

不通过:

25.jpg&27 (2).jpg.jpg")

通过:

1111.jpg&2222 (2).jpg.jpg")

img2.jpg&img3 (8).jpg.jpg")

小结

诚然,我们通过 UI 扫描工具改变了传统编写 UI 测试代码的方式,测试同学只需在功能测试的时候顺便录制一份测试用例即可,这不但降低了测试同学的自动化的学习成本和回归的时间成本,而且还为每次业务的发布提供了一道自动化回归保障。不过,在本次双 11 前端资防工作实际落地中,我们仍然遇到了一些问题:

  1. UI 测试扫描目前暂时只支持 h5,还不兼容淘系内的其他一些前端技术栈(比如 weex、直播、小程序等),导致这些业务仍然只能通过人工 review 的方式保障;
  2. 我们虽然对快照对比的算法进行了优化,但在实际应用中仍遇到一些由于算法判断不准导致误判的情况。因此,我们还将继续优化快照对比算法,进一步提升判断的准确度。
  3. 目前的快照对比只校验了录制和回放的最后一帧(即最终状态),大量的中间状态信息没有被利用起来,从而丢失了过程的校验。因此,后续我们将考虑引入视频的对比算法,达到真正的录制/回放全对比。
  4. 基于目前的页面代理机制,录制功能只支持当前页的操作录制,对于页面跳转类的测试用例还无法覆盖。因此,我们接下来也将继续升级页面代理和录制/回放脚本,支持链路层面的测试用例覆盖。

以上遇到的这些问题均是我们接下来继续重点突破的挑战。

总结与展望

如前文所述,淘系的前端资防工作一年内悄然变化着,从最初的人工预演到目前的三道递进式的产品化防控手段:

  • 【已产品化】针对可以在代码级别静态扫描分析出来的资损风险问题,做了第一道产品化防控手段——资损/舆情风险代码扫描工具;
  • 【已产品化】针对 UI、多态、复杂交互逻辑等不能从代码级别分析出来的资损风险问题,与测试团队合作做了第二道产品化防控手段——资损/舆情风险 UI 测试扫描,通过 UI 测试用例快照比对预防资损风险;
  • 【兜底方案】针对上述产品化手段不能覆盖的特殊场景,暂时先依赖人工预演作为兜底防护方案。

相比于去年的双 11 资防工作,今年我们依靠上述方案甚至取消了人工预演的环节。预演者也从去年需要准备相关文档(如止血方案、预案等)变成今年录制 UI 测试用例,其中需要准备的时间成本几乎打平,但大大节省了预演的参会时间;除此之外,预防效果也因其范围更聚焦、防护组合更全面,要比去年效果更佳。当然了,目前的这些方案都还只是预防手段,无法百分之百保障线上不会发生资损故障,每个人对于资防的态度仍不能掉以轻心。

在接下来的工作中,考虑到目前的资防方案仅能做代码缺陷方面的预防,产品设计、运营配置等方向还没有实质性的防控方法,所以后续我们将在构思链路级别的、生产环境以及运营环境上的防控手段,建设一些告警和自动止血机制为平台保驾护航。

(更多干货内容请关注【淘系技术】公众号,每日更新阿里工程师技术干货)
查看原文

赞 3 收藏 1 评论 0

阿里巴巴淘系技术 发布了文章 · 11月23日

人机协同时代,AI助力90.4%双11前端模块自动生成

背景介绍

2017 年,一篇论文 pix2code: Generating Code from a Graphical User Interface Screenshot 引起业界关注,论文讲述了使用深度学习技术实现从一张 UI 截图识别生成 UI 结构描述,然后将 UI 结构描述转成 HTML 代码。有人认为这种从 UI 截图直接生成代码的意义不大,AI 和 Sketch 软件本来就是用数据结构保存设计文件的结构描述,不需要通过机器学习来获取,而且生成的代码不确定性很大。也有一部分人对这个思路给予肯定,提出让深度学习模型学习 UI 界面特征,还可以做 UI 智能设计。

随后基于 pix2code 开发的 Screenshot2Code 项目进入 Github 排行榜第一名,该工具能够自动将 UI 截图转成 HTML 代码,该项目作者号称 3 年后人工智能会彻底改变前端开发,对此也有不少用户表示质疑,认为前端技术复杂框架各异,仅 HTML 代码无法满足需求。

2018 年,微软 AI Lab 开源了草图转代码工具 Sketch2Code一些人认为生成代码效果不理想不适用于生产环境,但也有人认为代码自动生成还处于初级阶段,未来发展值得想象。

2019 年,阿里巴巴对外开放智能生成代码平台 imgcook,可以通过识别设计稿(Sketch/PSD/图片)智能生成 React、Vue、Flutter、小程序等不同种类的代码,并在同年双 11 大促中自动生成了 79.34% 的前端代码,智能生成代码不再只是一个线下实验产品,而是真正产生了价值。

每当这些新的自动生成代码产品发布,网络上总会出现“人工智能会不会取代前端”“一大批前端程序员要失业了”这些讨论。

那人工智能到底会不会取代前端?人工智能在未来很长的一段时间内不会取代前端,但是会改变前端。一是会改变在前端智能化方向的前端领域探索者,他们除了可以成为 Nodejs 服务端工程师,还可以成为机器学习工程师,为前端智能化领域创造更多的价值和成果;二是会改变享受前端智能化成果的前端开发者,改变他们的研发方式,例如代码智能生成、代码智能推荐、代码智能纠错、UI 自动化测试等可以帮助他们完成大量简单重复的工作,可以把更多的时间放在更有价值的事情上。

本篇文章将给大家分享作为前端智能化领域的探索者,我们是如何看待人工智能在前端领域的未来发展方向,如何推进智能化能力在智能生成代码平台 imgcook 上的应用落地和迭代升级助力今年双 11 会场 90.4% 新模块的代码智能生成,编码效率提升 68% 的。

(更多干货内容请关注【淘系技术】公众号)

阶段性成果

======

imgcook(https://www.imgcook.com)官网首页平均每月 PV 6519, 平均每月 UV 3059。相比于 2019 年, 2020 年月平均 PV 和 UV 均是 2019 年的 2.5 倍。

imgcook 用户共有 18305 个,其中社区用户占比 77%,阿里集团内用户占比 23%。imgcook 模块共有 56406 个,其中外部模块占比 68%,内部模块占比 32%。相比 2019 年之前总量,2020 年用户增长 2.7 倍,模块增长 2.1 倍。

社区覆盖公司至少 150 家,集团内部覆盖 BU 10 个以上,双 11 会场新增模块覆盖度 90.4%,无人工辅助情况下智能生成的代码被保留发布上线的占比 79.26%,编码效率(模块复杂度和研发耗时比值)提升 68%。

与 2019 年相比,用户感官提效提升 14%;和完全不使用 D2C 相比,固定人力单位时间模块需求吞吐量提升约 1.5 倍。与传统研发模式相比,使用 imgcook 研发链路编码效率可提升约 68%。

更多详细数据请看 2020 年 imgcook 研发效能报告

image.png

(Imgcook 研发效能数据概览)

技术产品体系升级

技术原理简介

我们先来了解下 imgcook 智能生成代码的原理, imgcook 能够自动生成代码主要是做了两件事:  从视觉稿中识别信息,然后将这些信息表达成代码。

本质是通过设计工具插件从设计稿中提取 JSON 描述信息,通过规则系统、计算机视觉和机器学习等智能还原技术对 JSON 进行处理和转换,最终得到一个符合代码结构和代码语义的 JSON,再用一个 DSL 转换器,转换为前端代码。DSL 转换器就是一个 JS 函数,输入是一个JSON,输出就是我们需要的代码。例如 React DSL 的输出就是符合 React 开发规范的 React 代码。

image.png

(D2C 智能生成代码使用动线)

其中核心部分在于 JSON to JSON 这部分。设计稿中只有图像、文本这些元信息,位置信息是绝对坐标,并且设计稿中的样式与 Web 页面中的样式表现存在差异,例如 sketch 中透明度 opacity 属性不会影响子节点,但在网页中 opacity 会影响子节点,而人工编写的代码具有各种布局类型、DOM 结构需要合理可维护、代码需要语义化、组件化、循环等信息。

如何能智能生成像人工编写这样的代码,这是智能还原这部分要解决的事情。我们把 D2C 智能还原部分做了能力分层,每一层的输入和输出都是 JSON,智能还原部分的本质是一层一层的做 JSON 转换,这就是整个智能还原的流程。如果需要对生成的 JSON 做修改,可以通过 imgcook 编辑器可视化干预,最终通过 DSL 开放层将得到的符合代码结构和语义的 JSON 转换为代码。

image.png

(D2C 智能还原技术分层)

智能还原的核心链路构成了 D2C 的核心技术体系,并通过度量体系来衡量核心还原能力和研发提效效果。下层依托算法工程体系提供核心技术体系中智能化能力的底层服务,包括样本制造、算法工程服务、前端算法工程框架,上层通过 D2C 研发体系承接智能还原的后置链路,通过提供可视化干预能力满足用户二次迭代的需求,并通过将工程链路内置到 imgcook 平台实现一站式开发、调试、预览和发布来提升整体的工程效率。再加上支持自定义 DSL、自定义开发物料等扩展性很强的自定义能力形成的开放体系一起构成了整个 D2C 架构,服务于阿里内部 C 端、小程序、中后台等以及外部社区各种不同的业务场景。

image.png

(D2C 技术架构图)

今年在前端智能化大背景下,对 D2C 技术体系全链路进行了智能化能力升级,并为前端同学带来了让前端工程师能成为机器学习工程师的前端算法工程框架 Pipcook 和解决样本收集问题的样本制造机 Samplecook。同时带来了营销模块研发链路产品化升级,助力全链路研发提效。

智能化能力升级

智能化能力分层定义

《汽车驾驶自动化分级标准》基于驾驶自动化系统能够执行动态驾驶任务的程度,根据在执行动态驾驶任务中的角色分配以及有无设计运行条件限制,将驾驶自动化分成 0 至 5 级。在高级别的自动驾驶中,驾驶员的角色向乘客转变。这种明确的标准有助于各类企业更有针对性展开研发和技术部署的工作。

image.png

(自动驾驶分级标准)

参考自动驾驶分级标准,基于 D2C 系统能够自动生成代码的程度,根据编码的角色以及是否需要再人工干预和验证,我们定义了一个 D2C 系统交付的分级标准,用来帮助我们认识 D2C 系统当前所处的级别以及下一阶段的发展方向。

image.png

(D2C 系统交付分级参考标准)

目前 imgcook 的能力处于 D2C 的 L3 级别,智能生成的代码还需要可视化干预或人工兜底开发后验证上线。未来期望达到 L4 级别,我们需要对 UI 信息架构进行拆解,对从 UI 信息自动生成代码的智能化能力进行细分。

image.png

(UI 信息架构拆解)

一个应用由多个页面组成,每个页面中按 UI 颗粒度划分可以分为模块/区块、原子模块/区块、组件(业务组件、基础组件)、元件。每一个颗粒度的 UI 我们都需要识别到它的布局结构和语义,才能生成像人工编写一样模块化、组件化、语义化的可维护性较高的代码。

根据对 UI 信息架构的拆解,我们结合 imgcook 生成代码的技术体系从不同颗粒度对智能化能力进行分级 I0-I5(I 是 Intelligent 的首字母)。

image.png

(D2C 智能化能力分级)

其中涂色部分是目前已具备的能力,从这个维度来看 imgcook 的智能化能力目前处在 I3 和 I4 级别,并与 I2 级别的能力协同运作于生产环境。 I3 级别的智能化能力需要不断优化和迭代模型,当线上真实场景准确率达到 75% 以上或模型具备自我迭代能力则进入 I4 级别。如果达到了 I5 级别的智能化能力,根据 D2C 系统交付分级参考标准,D2C 系统交付分级可以从 L3 进入 L4, 生成的代码将不需要人工干预和验证即可直接上线。

当然我们可能会长期处于 L4 级别这个人机协同编程的阶段,这种分级的定义是为了促进智能化落地的进程,可以指导 我们提升 D2C 智能化能力,对 D2C 智能化有个更清晰的认识。

我们以生成代码的可用度作为总体技术指标,并根据代码生成链路的技术分层给出各阶段的技术指标以及对代码可用率影响的权重,其中生成代码的理论准确度 = (各个环节准确度 * 权重)之和,而真实的代码可用率 = imgcook 生成的代码在最终上线的代码中留存的占比。

image.png

(各分层技术指标与权重定义)

D2C 的智能化能力分布在还原链路的各个阶段,我们以提升代码可用率为目标,对全链路进行智能化能力升级,将技术方案细化到如何让各阶段模型识别准确率提升以及如何能将识别结果最终应用到智能还原链路生成代码,如何做到从样本收集、模型训练、模型部署到模型应用到工程链路整个流程能够自动化、自我迭代优化,不断优化和迭代模型能力。

智能化能力的应用还需要工程链路的支撑,例如模型识别结果的应用、线上用户行为召回、前端开发组件对 UI 组件识别结果的承接等,整体的 D2C 技术体系也需要同步升级。

image.png

(D2C 技术体系升级大图)

各阶段智能化能力升级

图层解析阶段

imgcook 通过解析设计稿图层信息,并通过规则系统、智能化技术等识别和生成代码,但由于设计域与研发域的表达方式、结构和规范等差异,设计稿的图层结构对生成代码的合理性影响较大,一些设计不规范的设计稿需要用 imgcook 的“成组”和“图片合并”协议对设计稿进行调整。

开发同学在开发代码时也经常会有写多余的 console.log、没有注释、变量重复声明等代码不规范的问题,为了解决这些问题,提供了 ESLint、JSLint 等工具来保障代码规范的统一。

在设计域,我们也同样可以开发一套设计稿规范智能检查工具来保障设计规范,智能审查设计稿的规范性,提示错误并辅助调整。我们把这套工具称为 Design Lint(DLint),具体的实现方案可以查看 设计稿生成代码 Imgcook 3.0 系列-设计稿规范智能检查篇

image.png

(设计规范检查)

物料识别阶段

UI 物料可以分为模块/区块、组件和元件,从 Sketch/PSD 中直接提取的信息只有文本、图片和位置信息,直接生成的代码都是由 div、img、span 组成,实际开发中组件化、代码语义化必不可少,如何从设计稿中提取组件和语义信息,这是 NLP、深度学习等智能化技术非常适合解决的问题。

去年我们在组件识别、图片识别、文本识别这几个方向都有探索和实践,识别的结果最终用于语义化和字段绑定,但使用的技术方案对识别的效果限制较大,今年我们做了如下改进:

组件识别

原本使用目标检测的方案来识别 UI 组件,但这种方案既需要识别出正确的组件类别还需要识别出正确的位置,以整个视觉图片作为输入,复杂的图片背景很容易被误识别,并且由于识别出的位置偏差导致很难挂载到正确的节点上,模型识别结果在线上的应用准确率较低。

基于这些原因,以及 imgcook 能够从视觉稿中获取每个图层位置信息的优势,我们将方案转换成了图片分类,并能将识别结果真正的应用到线上,这其中依托一套组件可配置、可识别、可渲染、可干预、可出码的智能物料体系。具体实现方案可以查看 设计稿生成代码 Imgcook 3.0 系列-组件识别篇

image.png

(组件识别应用全链路)

以下是组件识别应用到线上的演示,识别视觉稿中的视频信息,并用 rax-video 前端组件承接生成组件粒度的代码,需要配置自定义的组件(组件库设置)、组件识别模型服务(模型服务设置)、支持渲染 video 组件的画布资源(编辑器配置-画布资源)以及应用组件识别结果的业务逻辑点(业务逻辑库配置)。

组件识别全链路.gif

(组件识别全链路演示)

Icon 识别

Icon 识别其实是一个图片分类的问题,依然沿用图片分类的方案,但为了能够让模型的泛化能力能自我增强,我们设计了一个 Icon 自动收集、处理数据、自动训练模型、自动发布模型的模型闭环链路,让模型能够自我迭代优化。

image.png

(Icon 识别模型闭环链路)

自上线以来,新增训练集总数达到了 2729 个,平均每月回捞有效数据 909 个, 模型经过几次自我迭代测试集的准确度从 80% 提升到了 83%。具体实现方案可以查看 设计稿生成代码 Imgcook 3.0 系列-Icon识别篇

图片/文本语义识别

在 imgcook 智能化系统中有一个很关键的部分,就是如何对 UI 界面内的元素绑定语义化信息,之前解决方法是基于图片和文本分类模型识别,该方法有很大的局限性:仅对文本进行分类,没有考虑与整个 UI 界面内的上下文语义,导致模型效果不好。

举个例子:$200,这个字段文本分类是没办法对其进行语义识别的,因为它放到不同的场景中有着不同的意思,如:活动价、原价、优惠劵...,正确的做法是考虑该字段与在 UI 界面的联系(即独特的样式)来对它进行语义分析。

因此,我们引入了一种能结合 UI 中上下文语义的方案来进行语义识别,采用图片元素决策+文本分类两步走的方案解决界面元素语义化问题,具体流程是:先基于强化学习对界面元素按样式“过滤”一遍,识别出有样式的非纯文本字段,再对纯文本的字段进行文本分类。具体框架如下。

image.png

(强化学习 + 文本分类)

以下是模型算法训练结果。

语义分析结果演示.gif

(基于上下文的语义分析)

布局还原阶段

布局即是代码中每个节点与节点之间的关系,是父子关系还是兄弟关系。从颗粒度大小上划分,可以分为页面间模块/区块之前的关系、模块/区块内原子模块/区块之间的关系以及原子模块/区块内组件、元件之间的关系。

目前 imgcook 已具备了循环识别与多态识别的能力,识别设计稿中的循环体生成循环代码,识别同一个节点有多种 UI 状态时生成多状态的 UI 代码,并定义了布局可维护度衡量方式来衡量还原阶段的准确度。

image.png

(布局还原阶段识别能力升级)

逻辑生成阶段

在业务逻辑生成阶段优化原有的配置链路,将业务逻辑库与算法工程链路解耦,并承接所有识别结果的应用和表达。物料识别阶段只关心 UI 中有什么物料,不关心识别的结果如何用于生成代码,布局还原阶段的循环识别和多态识别同理。这样做的好处是我们可以自定义识别结果的表达,并且可以让用户感知智能识别的结果并选择是否使用。

除了从业务逻辑库生成逻辑代码也可以从需求稿生成部分逻辑,或者来源于代码片段推荐,或者来源于代码智能推荐( Code to Code,C2C)。

image.png

(通用业务逻辑库配置)

算法工程体系升级


样本制造机

算法工程服务提供了 UI 特征识别的模型训练产品,为所有想使用业务组件识别的小伙伴打造一个玩弄机器学习的链路。为了解决使用算法工程服务的关键痛点,所以有了新的衍生产品:样本制造机,为前端 UI 识别的模型提供样本制造捷径。

前端算法工程框架

有很多同学会觉得,让前端同学用机器学习技术去解决前端领域的问题,会不会难度很大。为了降低前端工程师使用机器学习的门槛,我们开发了前端算法工程框架 Pipcook。前端工程师可以用熟悉的 JavaScript 来完成机器学习任务。

Pipcook 通过提供通用的模型能力,比如图片分类、目标检测、文本分类等,减少了在 imgcook 中从开发到上线这些模型的门槛,使得如此多的底层识别能力也具备快速迭代的可能性。imgcook 全链路的识别能力,如组件识别、Icon 识别、字段语义识别等都是基于 Pipcook 训练。

image.png

(前端算法工程框架 Pipcook)

我们可以这样理解 Pipcook, Node.js 的出现可以让前端工程师成为一位服务端工程师,做服务端同学能做的事情, Pipcook 的出现可以让前端工程师成为一位机器学习工程师,可以做机器学习工程师做的事情。

image.png

(前端与机器学习)

研发链路升级

天马模块研发链路

淘系营销以模块开发为主,模块开发的完整链路是从模块管理平台创建模块 ⇥ 进入 imgcook 平台智能生成代码&可视化研发 ⇥ 开发完成后进入 IDE 调试预览 ⇥ 测试完成后进入工程平台发布。整个研发流程需要切换多个平台,开发链路体验和工程效率都有待提升。

创建模块后进入 imgcook 平台智能生成代码&可视化研发,如果能够直接在 imgcook 平台开发、调试、预览和发布,一站式的 D2C 研发模式是提升整体研发效率和研发体验的一个不错的选择。

所以我们自定义了具有可视化模式和源码模式的营销版本 imgcook 可视化编辑器,在可视化模式智能生成代码和可视化研发,并将生成的代码一键同步到源码模式的 WebIDE,在 WebIDE 中支持界面化的调试、预览、发布。

image.png

(天马模块 imgcook 可视化研发动线)

我们通过计算使用传统研发模式开发的模块与使用 imgcook 可视化研发模式开发的模块的效率值(复杂度与研发耗时比值)看到,使用 imgcook 可视化研发链路开发的模块编码效率提升 68%。

Imgcook 可视化研发链路1.gif

(天马模块 imgcook 可视化研发全链路演示)

智能 UI 研发链路

智能 UI 是一种通过分析用户特征为用户提供个性化 UI 的方案,因此需要开发大量的 UI 界面,在淘系智能 UI 平台鲸幂中开发智能 UI 的原始链路是在上传视觉稿解析物料之后会批量创建 imgcook 模块,但每种物料都需要进入对应的 imgcook 可视化界面单独开发、创建仓库、单独发布,并且看不到智能 UI 整体的视觉效果。这样导致智能 UI 所需要的大量物料的开发成本很大,业务接入智能 UI 的成本比较大。

image.png

(智能 UI imgcook 可视化研发动线)

这次升级了智能 UI 的研发链路, D2C 可视化研发链路承接了智能 UI 的批量化生产。在上传设计稿解析出 UI 物料之后,创建 imgcook 模块,批量生成物料 UI 代码,同时创建代码仓库与 imgcook 模块关联,并支持将已创建的物料批量导入 imgcook,批量生成 UI 方案(不同类型的 UI),在生成的 UI 方案中集中式对物料进行开发,最后还将支持物料的批量发布,整个链路集中高效了很多。

落地结果

今年前端智能化助力前端研发模式升级,数个 BU 共建前端设计稿识别算法模型和数据集,并于双 11 会场大规模应用落地。

设计稿生成代码技术体系全面升级(如对 UI 多态、直播视频组件、循环的智能识别增强等)带来了营销模块研发链路产品化升级:双十一会场有 90.4% (高于去年)新模块的代码智能生成。升级设计稿智能检查能力,在可统计范围内,无人工辅助的情况下智能生成的代码被保留发布上线的占比 79.26%。

相比传统模块开发模式,使用设计稿生成代码技术后编码效率(模块复杂度和研发耗时比值)提升68%,固定人力单位时间模块需求吞吐量增加约 1.5 倍。

目前还需要人工改动代码的主要原因有:循环未被识别、条件展示逻辑代码未自动生成、字段绑定猜测错误(字段标准化情况不佳)、业务特性必须的图片合并问题等,这些问题也都是接下来需要逐步完善的。

代码生成示例.gif

(D2C 代码生成用户更改情况)

同时,imgcook 支撑了天猫淘宝的主会场和行业会场智能 UI 的批量化生产,极大的提升了智能 UI 的生产效率。

智能UI批量化生产.gif

(智能 UI 批量化生产结果)

未来展望

智能化方式无论是使用计算机视觉还是深度学习技术,都会有准确率的问题,准确率低在线上环境可能无法被接受。需要建立一套与线上用户使用数据形成闭环的算法工程链路,实现样本自动化收集、算法工程链路的闭环才能让模型线上识别准确率不断提升。目前在 imgcook 的系统中,Icon 识别从样本收集到模型识别结果的最终应用已经形成了完整的链路闭环,开发同学不需要花太多精力用于模型的优化。对于其他的模型,后续也会用同样的思路让模型具有自我迭代的能力。

另一个 D2C 智能化的难点是模型识别的结果最终如何用于生成代码,例如组件识别模型能识别组件的类别,但最终生成代码使用哪个组件库的组件、如何识别 UI 中的组件属性值这些问题,imgcook 的平台能力与智能还原技术分层架构具备解决这些问题的能力,未来会有更多的智能化方案用于生产环境。

后续我们会继续根据对 imgcook 的 D2C 智能化能力拆解,探索更多智能化解决方案,优化现有模型能力,建立算法工程闭环机制实现每一个模型的自我迭代,不断提高模型的泛化能力和线上识别准确度,辅助生成可维护性更高语义更强的前端代码。

(更多干货内容请关注【淘系技术】公众号)
查看原文

赞 3 收藏 2 评论 0

阿里巴巴淘系技术 发布了文章 · 11月23日

手淘双11最新实践:PopLayer弹层领域业务研发模式升级

背景

近年来,各大APP内的弹层需求逐渐增多,以手机淘宝为例,日常的弹层上线频率为单端每月50次左右,而在大促期间可以达到240次以上。在手淘内,各类弹层业务都会通过PopLayer中间件的能力进行管理。但业务往往会遇到开发弹层难、慢、稳定性差的种种困难。对比于往年业务研发成本较高的现状,PopLayer在今年提出了【低研发搭建模式】来解决这类问题,形成一套快速搭建+可视化+多端多场景通用的解决方案,在日常与大促期间得到了广泛应用:

  • 研发效率升级:弹层业务的上线成本从3天+,降低到2小时左右
  • 业务覆盖率高:双11大促期间的业务覆盖率达到75%
  • 稳定性极佳:大促期间线上0故障

在各类APP都逐渐走向存量时代,精细化流量运营的今天,弹层作为一个可以随时随地产生内容并带来高流量的强运营手段,已经从低频需求,变成了面向各类人群触达的高频需求。作为业务支撑方向的中间件,如何为业务提效,将业务的关注重点从开发转向内容运营,助力其完成触达矩阵,成为了一件非常值得探索的事情。

(更多干货内容请搜索关注【淘系技术】公众号)

PopLayer

弹层,是一种强触达用户的交互形态。PopLayer的定义,则是一个可以在任何APP页面上,在指定时间内,对页面无侵入地弹出任何内容的弹层中间件。其业务定位,则为触达各领域用户的重要流量场。

为了便于理解,下面以手淘首页近期Pop为例,将手淘内的Pop业务分类举例介绍(本文中Pop即指弹层):

  1. 大促氛围打造

image.png

开售倒计时提醒

  1. 增强用户体验

死亡恢复.jpg

死亡恢复浏览飘条

  1. 红包发放&提醒

互动权益.PNG

星秀猫开奖

催用倒计时.png

红包催用提醒飘条

  1. 用户指引

可以看到,弹层业务的交互形态是灵活多变的,业务目标诉求也各有不同。其背后有着各自业务层面的复杂诉求和增长目标。PopLayer为此提供了一套端侧弹层管理SDK+任务管理系统的整体解决方案。

image.png

PopLayer常规任务管理流程

注:PopLayer是以端侧中间件为核心进行建设的,其中每个环节都有比较复杂的链路可以展开,本文不展开讨论端侧细节,主要讨论研发效率方面。

在这套流程中,对业务方负担最重的,也是研发耗时最重的,便是前端页面的研发以及服务端接口的研发。且各个业务的曝光预判接口不断累积,也带来了非常大的资源浪费与QPS压力。随着弹层业务逐年增多,这套模式的弊端越来越凸显:

  • 研发效率低下以日常期间观察,研发一个图文类型弹层,至少需要一个前端人员投入三天以上时间+一个后端人员投入三天以上时间+测试人员投入一天以上。
  • 运营效率低下。运营策略往往受限于研发成本、资源调控、以及上线时间等等问题,而无法灵活展开与快速迭代。尤其在大促期间,很多快速决策的运营玩法无法及时且稳定地落地,丧失了关键时刻获取流量的机会。
  • 研发质量难以保证。不同于整页研发,弹层存在一些特殊需要注意的问题。而研发人员接入PopLayer的流程熟悉程度往往有限,很容易因缺乏经验而产生线上异常,比如只有背景黑色遮罩弹出而内容加载失败(可以想一想会是什么状况)
  • 业务数据指标没有统一标准,无法形成客观统一的业务指标,无法通过数据快速定位问题,无法形成有效的数据沉淀与对比。
  • 整体方案难以沉淀复用。

这样的研发成本,对于Pop这类往往需要快速响应的业务需求,是远远不能满足的。尤其在大促期间,对时效性要求很高,一个Pop从决策到上线,可能仅仅只有1-2个小时的响应时间,一旦错过时机对业务的流量损失是巨大的。

经过建设搭建模式,这套陈旧野生的研发流程终于得到了改变。如今,通过新模式,一个常规的单图Pop几分钟就可以完成搭建。业务方可以彻底解放双手,集中精力在更加优质的内容编排与制作上。

模板全域触达技术模型111.png

PopLayer搭建模式对研发流程的影响

-

PopLayer搭建模式

Pop业务背景分析

经过长期与业务深入合作,我们发现弹层的需求往往有一定的规律可循。PopLayer领域下的业务特征大体如下:

  • UI结构轻量:主要为底图+内部图文混合的UI结构,视觉复杂度有限
  • 点击交互可枚举:跳转页面、关闭Pop、发送后端接口、切换内部子页面等
  • 组件复用性低、整体复用性高:每个Pop内部可复用的组件几乎不存在,更应该以一个完整的Pop作为一个模板进行维护和复用
  • Pop特有逻辑较多,比如疲劳度规则、各类数据来源变量解析等

那么实现一套统一标准的搭建方案,从前后端等各个方面逐个击破,来承载业务的大部分高频需求,支持其快速、低研发迭代上线,便成了解决这类问题的首选方案。

得益于这套标准化的前端协议规则,我们可以将PopLayer的触发范围,从APP站内触达,向其他流量场横向扩展,比如Android桌面、H5环境等,这部分后文将会展开讨论。

搭建模式架构

模板全域触达技术模型.png

搭建模式方案框架图

我们通过锁定 低研发搭建+多端多领域统一触达 的解决方案,支持运营与业务快速完成各类弹层小时级上线。其链路主要包括如下几个部分:

  • 搭建
  • 设计一套Pop业务域内的统一业务描述DSL,来描述Pop的全部UI架构、数据提取规则、交互逻辑等等内容。以其为核心,完成搭建与各端各领域的解耦
  • 搭建IDE,提供友好的编辑界面、实时动态预览、真机预览等业务服务,最终产生标准DSL内容
  • 解析
  • 探索除APP站内之外的更多触达领域,包括Android桌面环境、H5环境
  • 研发DSL运行时解析引擎,并完成统一体验的Pop渲染及交互
  • 任务管理服务
  • 提供一体化人群曝光预判
  • 提供权益、AB与模板搭建的打包配置能力,无需业务方自建实验、自研权益对接
  • 将单场景多Pop情况下的预判QPS压力,降低为单场景组合预判模式,有效降低服务端压力

搭建

搭建与DSL

DSL,即领域特定描述语言,是为了解决特定领域问题而形成的编程语言或规范语言。在Pop业务域下,我们无需形成编程语言,甚至追求尽可能低研发,所以这里的DSL即为一种Pop业务域范围内的规范描述语言。

Pop的DSL格式为常用的JSON格式。其整体结构为pages-UI动线、props-变量解析、requests-请求接口、env-环境全局配置。

image.png

下面我们从交互动线结构、变量解析、事件结构、疲劳度几个方面分别介绍DSL描述的主要内容。

  1. 交互动线与UI结构

交互动线

对应到DSL,我们提供了多子页面+多版本的描述方案,即通过创建多个子页面+每个子页面的多个版本来完成动线素材,并通过设置事件动作,完成动线串联。对应到DSL的结构,即通过pages+vers以树形结构分别描述各个子页面版本。其整体示例如下:

模板全域触达技术模型.png

布局版型

Pop的布局版型是多种多样的,但基本可归类为如下几种:居中、四角挂角、四边贴边。DSL设计中,每一个子页面都可以单独设置其布局版型。不同的版型,会以不同的布局逻辑计算其大小位置。

模板全域触达技术模型1231.png

UI组件

Pop形态下的UI组件,基于围绕着如下几个类型展开:图片、文本、视频、容器、倒计时、点击热区等。即通过提供大图或视频为背景,并通过容器+内部组件形成内部复杂的界面布局。我们针对各个组件提供了统一的布局配置+各自不同的素材配置。以一个倒计时组件为例:

2231313.png

  1. 变量数据提取与绑定

变量数据提取

Pop的内容与服务端数据做绑定时,需要提供一套提取数据的描述方案。而数据来源因Pop的整体链路设计,存在多个可能来源。我们通过 指定数据来源+提供插入式Mtop接口配置+接口数据提取Function 完成数据提取的设置,形成一个变量。仍以上述Demo为例,其中红包金额的变量为服务端Mtop接口返回数据。其提取流程示例:

模板全域触达技术模型11111.png

即通过预判MTOP接口数据源,通过JSONPath,并指定其数据位置完成提取。在某些较为复杂的情况下,有时数据来源需要多层解析(JSONPath+URLDecode+URLParse),那么也支持其设置串行多层解析。

变量绑定

解析结束的变量,即视为一种全局资源,其可以绑定到各种内容与其他数据上,哪里需要哪里搬。比如图片地址、文本内容、toast内容、跳转地址、MTOP请求参数等等。其实现方案为常用的字符串模板表达式${prop_name},进行运行时替换。

  1. 事件结构

大多情况下,Pop内的事件,即为用户点击事件,但随着业务复杂度的提升,例如视频播放结束、视频加载失败、倒计时结束等时机也需要响应事件,我们便提供了统一的事件描述,方便挂载到各个组件事件配置上。而事件的类型。即为跳转场景、切换子页面、发送MTOP接口、关闭Pop等,我们分别对这些事件提供了对应的封装描述。此处细节较多暂不展开。

  1. 疲劳度

疲劳度是Pop的重要组成部分之一。疲劳度的设计分为疲劳度规则+疲劳度消耗规则。例如Pop需要用户每天曝光不设限,但点击后当天不再弹出。那么其疲劳度规则为一天一次,而消耗规则即为点击时消耗。通过这样的实现方式,则可以非常灵活的实现各类疲劳度需求,做到想怎么弹就怎么弹。

在DSL的曝光、关闭、以及每个事件结构中,均有疲劳度消耗规则,而疲劳度整体规则,则通过不同的疲劳度表达式完成配置。

搭建IDE

IDE的核心功能,即为业务用户提供一个实时可视化、随时可真机预览的一站式搭建编辑器。其产出,则是产生一份描述业务完整需求的DSL内容。目前已为业务提供包括页面搭建、数据管理、曝光判定、疲劳度规则、降级策略、埋点配置等方面的搭建功能。

20201113135045.jpg

搭建IDE

解析

如方案框架图所示,搭建模式的目标不仅仅是在APP站内完成Pop触达,还需要在Android桌面、站外H5这样的环境里完成一站式多端触达。我们可以把目前涉及的几个流量域,称为触达领域。

APP站内的触发流程,即PopLayer端侧中间件,功能上有非常丰富的积累,可支撑几乎所有Pop业务的各方面诉求,此处不进行展开,本文将从弹出Pop后的解析引擎、Android桌面的触达领域支持方面进行介绍。

运行时解析引擎

针对不同的触达环境,需要形成各自的运行时解析引擎,目前我们完成了APP站内引擎:负责站内+Android桌面的解析渲染,以及H5站外引擎:负责H5环境下的解析渲染。这里我们主要针对站内引擎进行介绍。

PreDisplay + Running

解析引擎的主体工作流程,分为PreDisplay阶段:获取DSL、获取各环境数据、解析变量、完成UI渲染并曝光,以及Running阶段:在曝光后的事件交互处理。

模板全域触达技术模型121231312.png

解析引擎工作流

在执行display之前,Pop为隐形状态,用户无感知。经过如上图的DSL解析、同步各类环境数据、变量解析、曝光判定、素材加载等流程后,通过display接口,完成最终曝光。

为了达到双端统一的渲染效果、高适配性、以及高性能渲染的要求,站内引擎的底层载体目前为Rax方案。基于Rax完善的工程化支持,我们得以完成一系列上层方案,无需过度关注动态性、适配性等问题。

Android桌面弹层

对于手淘这样日活流量足够大的APP,其Android桌面的触达流量价值同样是巨大的。相比APP站内的Pop触达,其更加拥有包括加强唤端、二方流量交换这样的独特价值。在有规则规范的前提下,我们可以通过端侧中间件建设,把Pop搭建的能力无差别的输出到桌面环境,使其成为Pop触达生态的一环。其具体的触达形态,则可以是顶部消息、挂角提醒等。其底层实现方案为Android悬浮窗。

桌面Pop的效果Demo如下:

20201115180521.jpg

模板全域触达技术模型111.png

桌面Pop方案框架

首先,我们将桌面与站内进行了搭建能力对齐,使一个搭建产生的页面,即可以在手淘里弹出,也可以在桌面上弹出。为此我们抹平了底层方案不同带来的差异,包括:

  • 搭建模式与站内一致,同样采用标准DSL+解析引擎完成渲染
  • 通过控制Window添加次序来对齐层级管理
  • 通过控制视窗大小位置,控制其可绘图区域;通过搭建输出可视区域位移量,对视窗内容进行位移还原窗口内容

另外,我们提供了桌面环境的特殊处理:

  • 增加了切换桌面触发时机(计划触发,适合计划常驻),并打通了ACCS消息触发时机(即时触发,适合消息类型)
  • 增加了自由拖拽、边侧自动吸附功能

由于桌面环境的特殊性,应避免对用户形成严重的干扰。那么桌面触达的规则管理则十分重要。目前我们设计了如下避免过度干扰的规则:

  • 桌面环境的Pop必须有明确明显的关闭按钮
  • 切换其他APP时,需要将Pop内容进行隐藏,对于Android高版本则进行倒计时后自动关闭设置
  • 桌面的弹出管理底层与站内一致,采用分层分优先级管理,并对一次桌面切换的曝光次数进行上限设置

任务管理服务

从上述任务管理流程图可以看到,业务对于曝光预判、业务数据方面都是需要服务端的人力投入的。即除前端的研发成本问题,服务端同样面临类似的问题。我们梳理业务目前痛点如下:

  • 人力消耗大,大促时效性差
  • 机器资源消耗大
  • 全量配置下发+全量接口预判的模式,导致单活动机器资源消耗大
  • 单场景(比如手淘首页)下的Pop往往存在多个,活动之间筛选独立进行,导致机器消耗总量增长快(QPS总量随活动数线性增加且无上限)
  • 稳定性风险高
  • 临时开发的模式,加上人员开发质量层次不齐,稳定性很难保障。
  • 业务需要自己投入精力维护稳定性,特别是每次大促的时候应对突发流量

为此我们实现了对业务进行一站式托管。核心目标为:

  • 实现权益、导流这两个业务领域的低研发极速上线
  • 降低机器资源消耗,在线活动数量不再受机器资源限制
  • 托管业务全年0故障

通过拆解上文的任务管理流程图,可以看到服务端的工作主要包括曝光预判接口,以及页面内的业务数据接口。我们针对两部分分别进行部分托管建设,架构图设计如下:

1587024041829-d573d633-5736-4b3b-9939-8b2285049b82.png

任务管理服务架构

  • 针对曝光预判接口,我们提供了单场景多活动的人群预判复用能力,即将人群圈选的预判模式统一集中管理,底层与奥格人群平台二方包打通,上层单场景仅透出一个整合接口。从过去每次切换页面触发N次预判接口,变为仅触发一次。业务也无需自研人群接口,仅需把人群包ID进行配置即可。
  • 针对内容数据接口,我们仍在建设中。计划通过底层打通了拉菲权益平台二方包,将权益类型(红包、优惠券等)直接整合进搭建体系中,业务无需进行复杂的权益能力对接,仅需提供权益ID配置即可。

整体效果

除文章开头提到双十一期间的业务覆盖率已经达到75%之外,得益于搭建模式对研发效率的提升,今年双十一期间,手淘内Pop的业务量和整体流量也有了大幅度飞跃:

image.png

除此之外,今年我们快速稳定地响应了大促期间的全部紧急需求,避免出现过去几年因封网、研发效率等问题带来的无法上线Pop的情况。

写在最后

PopLayer目前除手淘外,已经服务了集团众多APP,包括天猫、淘宝特价版、闲鱼、淘宝直播、饿了么、Lazada、零售通、AE等等。后续也将继续以手淘为核心,服务更多的集团业务。

通过双十一大促期间以及日常的业务覆盖率,我们印证了搭建模式对业务的价值。站在业务的角度思考,Pop这类“既轻量又复杂”的业务域,经过一番深挖的底层支持,可以大幅度破除业务的桎梏,让其解放双手,去快速通过“提出idea-搭建-AB-看数据-再次迭代”的模式得到最佳的业务结果。这套业务研发模式的优化,从思考如何研发变为如何尽可能封装研发,对于相对轻量级的业务域来说也是有输出价值的。

后续,我们一方面将会继续完善相关建设,将AB、标签+推荐系统、引擎加载页面性能优化等等进行深度挖掘,从研发效率提升,升级到业务价值提升;另一方面也会将Pop的建设经验沉淀成流量域方法论的一部分,输出到其他流量域中,为业务探索与构建更有价值的流量增长矩阵。

手淘平台技术

我们背靠淘系基础架构和厂商,既有立足5G适配、网络加速、图片体验、网关调用、大内容上传下载等核心技术支撑业务体验升级和改造,

又为用户增长提供消息推送、浮层搭建、厂商触达、外链拉端等流量端能力,并沉淀一系列如最小核、全链路数据等架构能力,为手淘及产品升级提供平台支撑,并成为集团移动端基础设施。

职位:Android研发工程师、iOS研发工程师

感兴趣的同学可将简历发送到:yangqing.yq@alibaba-inc.com,获取优先内推资格!

查看原文

赞 2 收藏 1 评论 0

阿里巴巴淘系技术 发布了文章 · 11月20日

史上最快破5亿用户的互动 - 2020双11养猫技术大揭秘

前言

在电商领域,互动是一个重要的用户增长方案,在提升用户黏性、活跃以及拉新上都发挥着重要的作用。今年双11,淘系互动团队推出了“超级星秀猫”,我们不盖楼、不开车,全民参与养猫出道,3只风格各异的萌猫咪一经问世,瞬间俘获了无数消费者的心。通过 EVA 互动体系一整套解决方案,大幅提升研发效率,支撑全民养猫猫在手淘、猫客、支付宝等多个 APP 互通。借助客户端能力及 EVA 互动体系将性能与内存良好控制,让多数用户体验高清稳定的互动,实现 0 故障及秒开,同时星秀猫参与人数再创新高。这篇文章将主要从页面渲染基建、EVA 研发体系和全局稳定性方案 3 个方面,来具体阐述淘系互动前端团队是如何做到双11互动又快又好又稳的。

image.png

(更多干货请关注【淘系技术】公众号)

页面渲染基建

不知道大家有没有发现,今年的双11养猫互动(以下简称双11互动)页面打开特别快,具体可看下面与去年双11互动主页在 iPhone 11 PRO 机器手机淘宝上的主页加载对比视频。不仅如此,还有个明显的变化是以往互动页面的标配--进度条没有了。

image.png

见多识广的你也许会问,是不是今年双11互动使用了 Native 版本?是不是今年双11互动使用了缓存方案?是不是今年双11互动也使用了预渲染技术?然而,答案是,都没有,今年双11互动与历年狂欢城一样,仍然是 web 页面,且资源全部走 CDN 无额外缓存。

那么,我们是如何做到如此顺滑的加载体验呢?这就要从 Solution 说起。

Solution 是天马搭建体系的概念,主要解决的问题是将模块+数据组合成页面,简单理解就是负责页面渲染 Layout

自去年618起,淘系互动团队全部业务都开始迁移到天马搭建体系,Solution 也使用了官方推荐的通用 Solution。但是,通用 Solution 由于其通用性,冗杂了淘宝/天猫 60% 以上业务逻辑(粗略估计),体积大的同时易受其他业务影响导致稳定性风险高;而互动由于其业务特殊性,很多优化甚至稳定性保障方案的实现也需要在 Solution 层面进行定制。基于此,淘系互动团队定制了自己的页面渲染方案,即互动专用 Solution,这也是今年双11互动之所以那么快的核心原因。

得益于天马团队提供的新版 Solution 解决方案,既提供了标准化端渲染机制,又提供了基于插件进行业务定制的能力,还提供了产品化平台。互动专用 Solution 是在上述解决方案的基础上扩展实现,主要做了以下事情:

  • 精简基础依赖/逻辑,去除非必要依赖及非必要逻辑
  • 根据互动场景定制模块加载顺序,提供分批加载能力(当前主要是首屏/非首屏)
  • 提供数据处理能力,通过去除渲染无关字段实现数据自动瘦身
  • 内置基于客户端评分的稳定性保障方案,保障互动页面稳定性,详见下面稳定性方案章节
  • 增加资源及模块加载监控,保障稳定性
  • 集成互动通用能力,包括规范化 CSS/通用的渲染干预能力/常用的移动端调试方案/页面上下线能力等

image.png

EVA 研发体系

今年双11互动,非常多的用户反馈猫猫们太好看了、太萌了、特别可爱,很多人都纷纷来咨询小编是如何开发出来的。

image.png

接下来将重点阐述双11星秀喵加工厂--EVA 研发体系,TA 是淘系互动团队提供的从素材上传到端上渲染的互动研发的一整套解决方案,以引擎、框架、工具、平台为支点,致力于为广大前端带来简单舒适的互动研发体验。

EVA 研发体系,提供互动研发一条龙服务,我们是认真的

EVA Store:素材上传服务

大家看到的星秀喵,并不是3D模型,而是如假包换的2D骨骼动画。它使用 Spine 制作,通过网格自由变形和蒙皮技术在视觉上呈现“3D轴”的偏转,应用此类技术的动画软件还有大名鼎鼎的 Live2D。在 Spine 强大动画创作的支持下,双11的星秀喵才有了“3D化”的动画化表现力。一个标准的Spine动画文件包含一张雪碧图、一份骨骼数据以及一份动画数据,那么,我们应该如何上传到 CDN 呢?

EVA 为了解决互动业务中常见且频繁的动画和模型素材,提供了一站式的素材上传服务 EVA Store,包括帧动画、雪碧图、DragonBones、Spine、音频等,这些互动素材的协议标准是由阿里巴巴经济体互动小组统一制定。

image.png

EVA JS:2D 互动引擎

互动引擎是互动研发的基础,一款好的互动引擎能大大降低研发成本,EVA JS 应运而生。EVAJS 是一款轻量级,用于开发互动游戏的前端框架。EVA JS 支持插件体系,所有的互动游戏能力都是由插件提供的。EVA JS 一方面能够让前端互动游戏开发更加专业,另外一方面帮助前端开发者无需深度学习互动游戏技术即可开发互动游戏。TA 的整体设计是以游戏行业最佳实践的 ECS 设计模式为基础,拆分核心功能和组件能力,按需使用。

image.png

EVA JS 引擎

值得一提的是,EVA JS 还提供了无障碍化的支持。以往,游戏区实现无障碍需要手动在图层上添加辅助 DOM 来指定无障碍内容。今年双11,EVA JS 研制了 Canvas 上的无障碍技术,能够在手机淘宝/支付宝客户端上自动识别无障碍对象上的交互事件,降低研发成本的同时,让广大有障碍人士也能全方位体验到撸猫的乐趣,真正做到了互动无障碍体验。

640.gif

双11养猫无障碍体验

EVA JS 计划在2021年6月份前完成开源,了解更多,可参考 淘系前端互动引擎EVAJS架构与生态实现

Rax EVA:Rax 解决方案

素材和引擎都准备好后,就可以上手开始写代码了。市面上大多数的游戏引擎无法和 JSX、Hooks 结合在一起,这样,开发者就需要学习“两套框架”,再加上游戏引擎的学习成本也不低,整体上增加了开发门槛。为解决门槛高、上手难的问题,淘系互动前端团队设计了一套用于开发互动的 Rax 解决方案--Rax EVA,TA 是一个能够在Rax技术体系下,利用 EVA JS 的游戏研发能力,开发动画、游戏类场景的框架。它可以让开发同学用熟悉的 JSX 和 Hooks 语法编写动画、游戏场景的代码。

例如,我们把上一章节上传好的 Spine 动画显示出来(此处为示意版伪代码)

image

另外,对于前端来说,DOM 和 CSS 有天然的排版能力,这也是它们的优势。而游戏引擎是通过图形引擎渲染的,并不具备 CSS 那样高级的排版能力。于是在整个游戏互动的项目里,即存在 Canvas 又存在 DOM+CSS,也就是所谓的混合开发。Rax EVA 也为这类混合开发提供了方便快捷的方式,在 EVA 组件内,使用background / hud 这两个原生标签划分了游戏区域Z轴方向的三层布局,在这两个标签内以及 EVA 组件外,任何DOM 标签或其他熟悉的 JSX 都可以照常使用。

image.png

互动项目分层最佳实践

EVA Ware:弹窗规模化生产

除了基础的游戏研发外,EVA 研发体系还提供了一系列的低代码工具或服务,其中表现尤为突出的就是在今年 618 互动中就表现优异的弹窗规模化生成方案(以下称 Super Modal)。

互动研发最大的工作量之一就是弹窗的开发,相比今年 618,今年双11互动弹窗数量更甚。得益于 Super Modal 在弹窗研发上的抽象,所有的弹窗样式都是在平台上简易拖拽复制生成,通过 DSL+Runtime 提供端上稳定的渲染服务。弹窗的样式、文案可以作为页面配置项快速修改,前端在开发弹窗功能时,不用过多关注弹窗的样式问题,专注于弹窗的显示、关闭逻辑即可。除此之外, Super Modal 还在今年 618 功能的基础上,增加了相对定位布局、自定义组件、弹窗队列管理器插件等功能,并提供了简单的项目管理能力,进一步降低了弹窗开发的成本。

image.png

Super Modal 核心理念

了解更多,可参考 2020年618淘系技术分享-互动生产力进化之路

全局稳定性方案

细心的同学会发现,今年双11互动主页动效特别多,除了开场视频外,养猫和比拼的主界面上每个区域都在各种动。你一定在好奇,为什么你没有感觉到卡或者出现闪退的情况呢?这一切的背后,除了手机淘宝客户端架构组底层升级外,也有全局稳定性方案在护航。

互动场景中存在大量动效、视频,而过高的内存占用可能会引发客户端 crash 影响业务结果。一边是客户端需要更炫酷的玩法去支撑业务发展,一边是一些设备性能较差的用户反馈卡顿,如何让所有设备都能流畅的参与互动呢?比起不顾一切的上动效或是一刀切的砍玩法,显然存在一个更合理的选项--体验分级。淘宝技术质量团队提供了名为 Kite 的获取设备评分的统一降级 SDK,结合互动特性,如下图所示,我们将设备划分为 4 个等级,其中,容灾等级时页面将进入到一个异常兜底页面,用于应对一些低版本或者兼容性较差的机器场景。至此,我们完成了体验分级。

image.png

互动设备分级

接下来,就是针对不同设备等级的机型做不同降级方案,这也是互动的稳定性保驾护航重要的一环。基于客户端架构组提供的稳定性指标,我们需要整体考虑页面的内存、帧率、CPU 3 个指标,而动效、图片尺寸、游戏区画布尺寸、FPS 等配置则直接影响这 3 个指标的结果。然而,众所周知,在实际的开发过程中,对每张图片、每个动效做针对性的降级往往需要各种配置项,且人人参与,操作起来非常繁琐和耗时。因此,淘系互动前端团队在上面体验分级的基础上,通过 1 份静态全局降级规则 + 1 个运行时获取配置的稳定性保障 SDK,设计了一套完整的全局稳定性保障方案。

image.png

全局稳定性保障方案

正是这套稳定性方案,让双11互动在极大程度做到了高清互动、符合了架构组验收标准而且在线 22 天全程 0 故障。TA 让互动稳定性保障更加系统,也已经成为营销互动的标配。

总结展望

今年双11整体节奏从之前的“光棍节”到今年的“双节棍”,在这样变化的背景下,今年双11互动依然做到了参与人数再创新高。未来,我们希望完善 EVA 体系,通过不同的技术方案不断地优化我们的开发方式和生产关系,逐渐让更多的人来开发互动,实现“人人可开发,处处有互动”。

image.png

加入我们

淘系互动团队目前负责“芭芭农场”、“金币小镇”、“淘宝人生”等手淘内千万级的互动产品,重点打造双促、春节、市场PR等S/A级营销互动,同时为商家、达人、主播等沉淀和提供私域内的互动玩法。如果你对 工程/搭建/低代码研发方向 或者 WebGL/图形渲染/特效方向 等存在兴趣,欢迎微信联系/钉钉进群了解更多,完整 Job Model

image.png

查看原文

赞 6 收藏 2 评论 1

阿里巴巴淘系技术 发布了文章 · 11月19日

双十一SSR优化实践:秒开率提升新高度

前言

会场是每年双十一的主角之一,会场的用户体验自然也是每年最关注的点。在日趋复杂的业务需求下,如何保障我们的用户体验不劣化甚至能更优化是永恒的命题。

今年(2020)我们在不改变现有架构,不改变业务的前提下,在会场上使用了 SSR 技术,将秒开率提高到了新的高度(82.6%);也观察到在用户体验得到优化的同时,业务指标如 UV 点击率等也有小幅的增长(视不同业务场景有不同的提升,最大可达 5%),带来了不错的业务价值。

本文将从服务端、前端两个角度介绍我们在 SSR 上的方案与经验

  1. 前端在解决工程化、业务效果评估上的具体实践与方法论
  2. 服务端在解决前端模块代码于服务端执行、隔离和性能优化上的具体实践与方法论

(更多干货欢迎关注【淘系技术】公众号)

页面体验性能的核心指标

在正文开始前我们先介绍一下衡量的相关指标,从多年前雅虎 yslow 定义出了相对完整的体验性能评估指标,到后来的谷歌的 Lighthouse 等新工具的出现,体验性能的评估标准逐渐的统一且更加被大家认同。

会场的评估体系

基于 Web.Dev 以及其他的一些参考,我们定义了自己的简化评估体系

image.png

TTFB(Time to First Byte): 第一个字节的时间 - 从点击链接到收到第一个字节内容的时间

FP(First Paint): 第一次绘制 - 用户第一次看到任何像素内容的时间

FCP(First Contentful Paint): 第一次内容绘制 - 用户看到第一次有效内容的时间

FSP(First Screen Paint,首屏可视时间): 第一屏内容绘制 - 用户看到第一屏内容的时间

LCP(Largest Contentful Paint): 第一次最大内容绘制 - 用户看到最大内容的时间

TTI(Time To Interactive): 可交互时间 - 页面变为可交互的时间(比如可响应事件等)

大体上来说 FSP 约等于 FCP 或 LCP

会场的现状

我们的会场页面是使用基于低代码方案的页面搭建平台产出的,一个由搭建平台产出的会场页面简单而言由两部分组成:页面框架(layout)和楼层模块。

image.png

页面框架有一份单独的构建产物(即页面的 layout html 以及基础公共的 js、css 等 assets 资源)。每个楼层模块也有单独的一份构建产物(模块的 js、css 等 assets 资源,基础公共 js 的依赖版本信息等)。

页面框架的任务比较繁杂,负责页面的 layout、根据页面的搭投数据加载具体哪些楼层模块并组织分屏渲染模块。

会场原有的 CSR 渲染架构如下图,可以分成三部分:

  1. 客户端,包括手机淘宝等阿里系 App
  2. 文档服务,用于响应页面的主文档 HTML 清求
  3. 数据服务,用于响应页面的数据请求

image.png

原有的CSR渲染流程如下图

image.png

针对会场的性能,除了基础的大家都知道的前端优化手段之外,还结合客户端能力做过很多优化方案,比较具有代表性的有两个:

  1. 客户端主文档/Assets 缓存
在客户端内,我们利用了端侧提供的静态资源缓存能力,将 HTML 和基础公共的 JS 等资源,推送下发至用户侧客户端缓存。当客户端的 WebView 请求资源时,端侧可根据规则来匹配已下发的缓存包,在匹配成功后直接从本地缓存中读取对应的 HTML 和 JS 资源,而无需每次都请求网络、大大缩短了页面的初始化时间
  1. 数据预加载
从用户点击跳转链接到页面开始加载数据,中间还要经过客户端动画、WebView初始化、主文档 HTML 请求以及基础公共 js 的加载和执行这些过渡阶段,加起来有 几百ms 的时间被浪费掉。通过客户端提供的数据预加载能力,在用户点击后就可以立即由 native 开始页面的数据加载,等页面的基础公共 js 执行完需要使用页面数据时,直接调用 jsbridge 接口即可从 native 获取已经预先加载好的数据

在这些优化工作的基础上会场的体验性能已经可以达到不错的水准。

随着时间的推移,基于我们 CSR 渲染体系下的优化存在一些瓶颈:

  • 在线上复杂网络环境下(低网速、虚假的 WiFi)、Android 中低端机上的页面体验还是不尽人如意,特别是模块的加载和执行时间比较长,且这部分用户的占比有增长趋势
  • 作为拉新的一个重要手段,外部唤起淘宝或者天猫客户端因为需要时间来初始化一些功能组件,比如网络库等,页面的体验从体感上不能追平端内的会场
  • 会场是营销活动性质的业务,页面的复访率相对较低,且页面内容全面个性化。离线的 HTML 快照等用户侧缓存手段会因为缓存的数据过期导致出现重复渲染(打开更慢)、页面元素跳动(渲染闪烁、重排)等伤害体验的问题

还有没有优化手段呢?以一个 2020 年双十一会场页面,使用 PC 上的 Chrome DevTools 的 performance 离线分析结果为例,我们看一下重点的问题

image.png

可以看到页面从 FP 到 FCP 这段过渡的时间较长且只有背景色。FCP 到 LCP 这段时间处于等待图片加载的时间,优化空间较小,且难以衡量。

离线分析尚且如此,线上更有着复杂的网络环境/差异化的手机机型等,这样的“背景色”时间对用户的体验有很大的伤害,可能会让用户更加容易跳失。

我们的 CSR 渲染体系依赖前端+客户端的能力,从工作机制上已经很难再有比较大的提升。怎么才能让会场页面的体验更上一层楼呢,我们想到了服务端渲染(SSR), 针对 FP 到 FCP 这段时间进行攻坚优化

image.png

SSR 的线下测试结果,FP 到 FCP 从 825ms -> 408ms

SSR 要怎么做?

大的方向

SSR 本身意为服务端渲染,这个服务端可以在 任何地方 ,在 CDN 的边缘节点、在云上的中心机房或者就在你家的路由上。

实现一个 SSR 的 demo,熟悉的人应该都知道套路:

搞一个 Rax Server Renderer,传入一个 Rax Component,renderToString,完事了

业界也已经有很多实践的案例,但就像“把大象装进冰箱里”一样,看似简单的事情在双十一所要求的复杂场景稳定性下,需要有稳妥可实施的执行方案。

如何在现有的这套模块化、成熟的渲染架构之上使用SSR呢,一开始我们往常规的思路去想,直接在文档 HTML 响应中返回服务端渲染完成的 HTML,看下来存在几个问题:

  • 改造成本高,对现有的服务端架构改动比较大(CDN 缓存失效,文档服务的要求更高)
  • 无法复用现有的客户端性能优化能力,比如客户端主文档/Assets 缓存和数据预加载能力,会劣化完全可交互时间
  • CDN 缓存无法利用,TTFB 的时间增加,带来了新的 “完全白屏阶段”
  • SSR 服务不稳定因素较多,自动降级为CSR的方案复杂,无法保证 100% 能够降级
  • 主文档 HTML 的安全防护能力较弱,难以抵御黑产的恶意抓取

基于以上的问题,我们考虑是否还有其他的方案可以 低风险 、 低成本 地实现SSR呢?经过短暂且激烈的讨论,我们设计了「数据 SSR」架构方案,分享给大家。

数据 SSR 渲染架构如下,文档服务返回的内容保持静态化不变,数据服务新增调用一个独立的 SSR FaaS 函数,因为数据里有这张页面包含的模块列表和模块需要的数据,SSR FaaS 函数可以直接根据这些内容动态加载模块代码并渲染出 HTML。

image.png

这套方案在客户端内的场景下可以很好的将 前端 + 客户端 + 服务端三者的能力结合到一起。

有人可能会问,为什么这个方案会带来性能提升呢?不就是把浏览器的工作移到了服务端吗?我们举个例子(数据仅为定性分析,不代表真实值)。在正常 CSR 渲染流程下,每段消耗的时间如下,首屏可视时间总共耗时1500ms。

image.png

在SSR渲染流程下,在「调用加载基础js」之前的耗时都是一样的,由于下面两个原因,在服务端渲染的耗时会比客户端低几个数量级。

  • 服务端加载模块文件比在客户端快很多,而且服务端模块资源的缓存是公用的,只要有一次访问,后续所有用户的访问都使用这份缓存。
  • 服务端的机器性能比用户手机的性能高出几个数量级,所以在服务端渲染模块的耗时很小。根据线上实际耗时统计,服务端单纯渲染耗时平均 40ms 左右。

由于 HTML 被放到了数据响应中,gzip 后典型值增加 10KB 左右,相应的网络耗时会增加 30~100ms不等。最终 SSR 的渲染流程及耗时如下,可以看到 SSR 首屏的可视时间耗时为660ms,比CSR提升了800ms。

image.png

总而言之,「数据 SSR」的方案核心哲学是:将首屏内容的计算转移到算力更强的服务端

核心问题

大方向确定了,我们再来看看 SSR 应用到生产中还存在哪些核心问题

  1. 如何做到 CSR/SSR 的平滑切换
  2. 开发者如何开发出“能 SSR”的代码
  3. 开发者面向前端编写的代码在服务端运行的不可控风险
  4. 低代码搭建场景下,在服务端解决楼层模块代码加载的问题
  5. 服务端性能
  6. 怎么衡量优化的价值

别急,我们一个一个的来看解法

如何做到 CSR/SSR 的平滑切换?

在我们的页面渲染方案中,有两个分支:

  1. 页面未开启数据SSR,则与原有的 CSR 渲染流程一样,根据数据中的模块列表加载模块并渲染
  2. 页面开启了数据SSR并且返回的数据中有 SSR HTML,则使用 SSR 的 HTML 塞入到 root container 中,然后根据数据中的模块列表加载模块最终 hyrdate。

image.png

优点很明显

  • 风险低,能够无缝降级到CSR,只需要判断数据接口的响应中是否成功返回 HTML 即可。如果 SSR 失败或者超时(未返回 HTML),通过设置合理的服务端超时时间(例如 80ms),不会影响到用户的最终体验
  • 能够利用端上成熟的性能优化能力,比如客户端缓存能力,数据预加载能力。有客户端缓存能力,页面的白屏时间与原CSR一致;有了数据预加载能力,能够在页面加载之前就开始请求数据服务

在线上服务时,我们可以通过 HASH 分桶的方式对流量进行划分,将线上的流量缓慢的切换到 SSR 技术方案,既能保证稳定性,同时还可以方便的进行业务效果的进一步评估。

比较好的字符串转换为数字的 HASH 方法有 DJBHash,验证下来分桶效果较为稳定

开发者如何开发出“能 SSR”的代码?

很多做 SSR “demo”分享的往往会忽略一个重要点:开发者

在双十一的场景下,我们有百+的开发者,三百+的楼层模块,如何能推动这些存量代码升级,降低开发者的改造适配成本是我们的一个核心方向。

我们原有的楼层模块构建产物分为 PC/H5/Weex 三个,业界通用的是针对 SSR,单独构建一个 target 为 node 的构建产物。在实际 POC 验证过程中,我们发现其实绝大部分的模块并不需要改造就可以直接适配 SSR,而新增构建产物会牵扯到更多的开发者,于是想找寻别的解决方案。

复用现有 Web 构建产物的一个问题是,Webpack 4 默认会注入一些 Node 环境相关变量,会导致常用的组件库中的类似 const isNode = typeof process !== 'undefined' && process && process.env 的判断异常。不过还好这个是可以关闭的,开发环境下其他的类似 devServer 等的注入也是可以关闭的,这给了我们一点慰藉,最终复用了 Web 的构建产物。像更新的 Webpack 5 中把 target 的差异给弱化了,也可以更好的定制,让我们未来有了更好的社区化方向可以继续靠拢。

解决完构建产物的问题,在本地开发阶段,Rax 团队提供了 VSCode SSR 开发插件,集成了一些 best practice 以及 lint 规则,写代码的时候就可以发现 SSR 的相关问题,及时规避和修复。

image.png

同时我们模拟真实线上的环境,在本地提供了 Webpack 的 SSR 预览调试插件,直接 dev 就可以看到 SSR 的渲染结果。

针对开发者会在代码中直接访问 windowlocation 等变量的场景,我们一方面开发了统一的类库封装调用抹平差异,另一方面在服务端我们也模拟了部分常用的浏览器宿主变量,比如 windowlocationnavigatordocument  等等,再加上与 Web 共用构建产物,所以大部分模块无需改造即可在服务端执行。

接下来的模块发布阶段,我们在工程平台上增加了发布卡口,若在代码静态检查时发现了影响 SSR 的代码问题就阻止发布并提示修复。

image.png

由于实际的业务模块量较大,为了进一步缩小改造的范围,测试团队联合提供了模块的批量测试解决方案。具体的原理是构造一个待改造模块的 mock 页面,通过比较页面 SSR 渲染后的截图与 CSR 渲染后的截图是否一致,来检测SSR 的渲染结果是否符合预期

image.png

开发者面向前端编写的代码在服务端运行的不可控风险

尽管我们在开发阶段通过静态代码检查等方法极力规避问题,实际上仍然存在一些针刺痛着我们的心

  1. 开发者把全局变量当缓存用造成内存泄露
  2. 错误的条件结束语句导致死循环
  3. 未知情况页面上存在不支持 SSR 的模块

这些疑难点从 SSR 的机制上其实很难解决,需要有完善的自动降级方案避免对用户的体验造成影响。

在说更详细的方案前要先感谢我们自己,前端已经提前做到了 CSR/SSR 的平滑切换,让服务端能每天不活在恐惧里 = =

对于机制上的问题,可以引申阅读到之前分享过的 在 Node.js 中 ”相对可靠” 的高效执行可信三方的代码。我们这里主要聚焦在如何快速止血与恢复。

image.png

FaaS 给服务端降低了非常大的运维成本,“一个函数做一件事”的设计哲学也让 SSR 的不稳定性局限在了一块很小的部分,不给我们带来额外的运维负担。

低代码搭建场景下,在服务端解决楼层模块代码加载的问题

业界分享的一些 SSR 场景基本都是整页或者 SPA 类型的,即 SSR 所使用的 bundle 是将整页完整的代码构建后暴露出一个 Root Component,交由 Renderer 渲染的。而我们的低代码搭建场景,由于整个可选的模块池规模较大,页面的楼层模块是动态选择、排序和加载的。这在前端 CSR 情况下很方便,只要有个模块加载器就可以了,但是在服务端问题就比较复杂。

image.png

还好我们的模块规范遵守的是特殊的 CMD 规范,有显式的依赖关系声明,可以让我们在获取到页面的楼层组织信息之后一次性的把页面首屏的全部 Assets 依赖关系计算出来。

image

在服务端加载到代码后,我们就可以拼装出一个 Root Component 交给 Renderer 渲染了。

服务端性能

性能上主要是有几个方面的问题

  1. 机制问题
  2. 代码问题
机制问题

由于楼层模块很多,在实际执行的过程中发现存在一些机制上的性能问题

  1. 代码的 parse 时间较长且不稳定
  2. 流量较低情况下难以触发 JIT

优化方案的话比较 tricky

  1. 缓存 vm.Script  实例,避免重复 parse
  2. 期望一致性 HASH 或自动扩缩容(本次未实现)

巡检的时候还观测到存在小范围的 RT 抖动问题,分析后定位是同步的 renderToString 调用在微观上存在排队执行的问题

image.png

在这种情况下会造成部分渲染任务的 RT 为多个排队任务的渲染 RT 叠加,影响单个请求的 RT(但不影响吞吐量)。这种问题要求我们需要更精确的评估备容的资源。机制上有效的解法推测可以让 renderToString 以 fiber 的方式执行,缓解微观排队造成的不公平的问题。

代码问题

性能问题的分析当然免不了 CPU Profile,拿出最爱的 alinode 进行分析,很快的可以找到热点进行针对性优化。

image.png

上图中标蓝的方法为 CMD 加载器计算依赖的热点方法,对计算结果进行缓存后热点消除,整体性能提升了 80% 》.》

怎么衡量优化的价值

这么多的投入当然需要完善的评价体系来进行评价,我们从体验性能和业务收益两个分别评估。

体验性能

基于兼容性较好的 PerformanceTiming (将被 PerformanceNavigationTiming 替代),我们可以获取到前端范畴下的一些关键的时间

  • navigationStart
  • firstPaint

其中 navigationStart 将会作为我们的前端起点时间所使用。在前端之外,对用户的交互路径而言真正的起点是在客户端的点击跳转时间 jumpTime ,我们也联合客户端进行了全链路埋点,将客户端 native 的时间与前端的时间串联了起来,纳入到我们的评价体系中。

在最开始的核心指标中,我们看到有 FCP、TTI 这几个指标。目前的 Web 实现中,还未有兼容性较好的可以线上衡量的方案(线下可以使用 DevTools 或者 Lighthouse 等工具),因此我们通过其他的方式来做近似代替

image
线上取到的数据通过 tracker 的方式进行无采样上报,最终我们可以通过多个维度进行分析

  • 机型
  • 网络条件
  • 是否命中 SSR
  • 是否命中其他前端优化

主要的衡量指标有

  • 从用户点击到 FCP 的时间(FCP - jumpTime)
  • 从 NavigationStart 到 FCP 的时间(FCP - NavigationStart)
业务收益

这部分很忐忑,体验的优化是否会带来真金白银的收益呢?我们直接通过 AA 和 AB 实验进行业务数据的分析。

基于之前的切流分桶,我们可以通过类似 hash 值 % 10 的方式将流量分为 0~9 号十个桶,首先通过 AA 实验验证分桶是否均匀

image

统计指标举例

这一步是保证分桶的逻辑本身不会有数据的倾斜影响置信度。接下来我们再进行 AB 实验,逐步增加实验桶验证业务数据的变化。

最终的效果

搞了这么多,得看看产出了。在这次双十一会场中,我们切流了多个核心的页面,拿到的第一手数据分享给大家。

image

循环.gif

小米5 骁龙 820 处理器

可以看到,在 Android 碎片化的生态的下,带来的提升甚至超出了预期,这也给了我们未来更大的动力,将前端 + 客户端 + 服务端的能力更有效的结合到一起,带给用户更好的体验,给业务创造更大的价值。

未来的渲染架构还会更复杂吗?

为了更好的用户体验,当然会了!我们可以简单的看看短期和长期的一些事情

电商体验指标的统一定义

长期以来,业务在用户侧的实现有 Web、Native、Hybrid 混合开发等多种选择,每个体系都有着自己的封闭体验衡量标准,这就造成了一些“鸡同鸭讲”的问题。而 Web.dev 中所定义的 FCP、LCP 通用评价体系也并不适合电商场景,能展示出核心的商品/店铺其实对一张页面来说就完成了它的使命。

后续我们可以将体验指标评估标准对齐,将起点时间、绘制完成时间等在多个体系对齐概念与实现,达到互相之间可以横向比较良性竞争的状态。

工程上还有更多的事情要做...

在 Webpack 5 的 Release Note 中,我们可以看到 Webpack 正在弱化 target 的一些特殊处理,将 Web 描述为了 browserlike 的环境。同时还提供了自定义 browserlist 的能力,可以给予开发者更方便处理跨端的兼容性问题的能力。这一变化将推动我们更快的拥抱社区,获得更好的开发体验。

现有的 SSR 静态代码检查方案会有一些漏网之鱼,还有没有更完善的方案能从工程上前置解决代码风险(性能、安全)问题也是未来的一个方向。

ServiceWorker Cache 等离线缓存快照

复访率高,变化不太大的页面可以利用 ServiceWorker Cache 等方案,将之前的渲染结果缓存下来,命中缓存直接用,未命中缓存 SSR。降低服务端压力的同时可以让体验更好。

SSR 的性能优化与安全

现阶段的 Node.js 或者说 V8,对于动态加载代码的情况支持并没有特别的完善,缺失了安全相关的保护逻辑。并且从性能上来说,SSR 属于 CPU 密集型的 workload,纯异步的优势并不明显,也可能需要一些特殊的解决方案来配合。

外部投放场景的覆盖

「数据 SSR」的方案是端内的最佳方案,却是外投场景的最劣方案。外投场景下由于用户是在第三方 App 中打开页面,相应的缺失了客户端的定制化优化能力,SSR 调用会造成数据服务的 RT 增加,反而推后了 FCP。

这时候古老的 HTML 直出方案又可以再捞回来了。

image.png

核心在于

  1. 利用 CDN 的边缘计算能力,可以较好的做到“动静分离”以及容灾
  2. 使用中心化的 SSR 函数,可以将 SSR 的不稳定性与 CDN 的可靠性分离,保证近端链路的可靠,避免出现近端直接不可用导致的无法恢复

近端的流式方案经常被提及,但是在实际的使用中会遇到当流式输出遇到错误时,用户侧无法有效容灾的问题(HTML 损毁,无法补救)。通过“动静分离”可以将页面分为

image.png

仅将 Root Container 进行动态化,进而在享用流式输出带来的 TTFB 提前的好处的同时又能兼顾容灾 SSR 的不稳定。和业务团队更可以一起探讨下如何将页面更好的从业务上做到“动静分离”,而不是仅从技术的角度出发。

总结

渲染架构的不断改进实质上是我们在有限且变化的环境下(终端性能、复杂网络和多变业务)自发做的适应,也许有那么一天,环境不再是问题,性能优化的课题将会消失。我们项目组有时候还开玩笑,等明年手机叒换代了,5G 100% 普及了,是不是这些优化都可以下线了😝

但是!现在看理想还有点远,在 2020 的双十一会场我们走进了一个新的深水区,期待未来技术与业务结合能带给广大用户更棒的体验!

查看原文

赞 8 收藏 7 评论 1

阿里巴巴淘系技术 发布了文章 · 11月18日

淘宝直播“一猜到底”——移动端实时语音识别技术方案及应用

双11淘宝直播App·一猜到底

过去一年淘宝直播快速发展,截止2020年9月底,80个淘宝直播产业基地在全国落地开花,从农村走出10万农民主播,直播真正意义上成为帮助商家和消费者完成交易的利器,同时通过各种互动玩法让直播购物变得有趣好玩。在2020年双11开始阶段,淘宝直播App升级了18年直播答题「点题成金」的玩法,推出「一猜到底」新玩法。如果说传统的直播答题是「选择题」,一猜到底的玩法更像是几万人同时在线的「抢答题」,将答题方式从文字选择升级成语音抢答,给出猜中价格高低提示,让用户增加了更多的参与的乐趣。

为了实现比肩综艺现场的直播竞猜体验,我们一次压上了由达摩院语音实验室阿里云PAI团队、淘系技术直播App和端智能MNN团队组成的全明星阵容,通力协作之下,一举实现了工业界首个用于直播的移动端语音识别

(更多内容干货可关注【淘系技术】公众号)

业务流程和技术挑战

image.png

「一猜到底」整体玩法链路如上图所示,主播口播开始后,用户需要在人数和时间未满前,按住按钮,通过语音报出价格,系统通过本地语音识别能力进行识别和结果比对,提示用户所报价格“过高”还是“过低”,直到答对或者超时结束。在每一关有限的作答时间内,用户往往需要多次竞答,才能逼近商品的真实价格。于是,实时语音识别能不能准确且快速地识别用户的报价,直接决定了「一猜到底」的成败。

不同于一般的语音识别应用,一场顶流的淘宝直播,可以聚集百万乃至千万的用户围观。这么多用户同时进行语音识别,会出现非常多的请求,如果采用云端识别对服务压力和服务质量都有非常大的挑战。项目开始时实验了端侧和云侧识别的两种方案,发现云侧方案难以支撑这样的活动,最终选择了端侧方案,确定端侧识别方案之后,发现也不是康庄大道,主要存在以下技术难点:

  • 高精度高性能的本地语音识别

目前行业比较成熟的是服务端的语音识别方案,完全照搬服务端方案到移动端也不现实,需要创建一套适合移动端运行的语音识别方案。同时,直播场景下的语音答题噪声较大,对语音识别的准确度要求较高,语音识别速度也会对用户的答题速度造成巨大影响。

  • 语音模型和资源包体积过大

考虑到活动特性,端侧的语音识别引擎需要内置在包内,而且越小越好。经过客户端研发评估,如何做到15MB以内甚至更小的语音模型是关键,因此需要极致的模型压缩能力支持。

  • 端侧资源有限,性能压力大

直播场景本身就已经很占用资源,叠加直播场景下做语音识别,对语音识别过程中的CPU、内存占用,都有很大的要求,高性能的推理和优化成为模型落地的最大拦路虎。

移动端实时语音识别技术大揭秘

image.png

阿里达摩院语音实验室早在2015年就研发出了第一代移动端离线语音识别方案,近来结合PAI模型压缩、MNN高性能推理引擎,实现了移动端离线和流式端到端语音识别方案,满足语音指令、语音识别、实时翻译等场景需求。根据「一猜到底」项目需求,我们选取"基于SAN-M的离线端到端语音识别"方案,通过极致的模型压缩和性能优化,最终实现模型大小小于15MB、内存占用低于60MB、1s语料识别快于50ms的高性能方案。

基于SAN-M的离线端到端语音识别

目前,最具代表性的离线端到端语音识别模型LAS[1]和Transformer[2]都是基于Attention-Encoder-Decoder的。LAS采用基于BLSTM的Encoder和基于单向LSTM的Decoder;而Transformer则采用Multi-head Self-Attention模块组建Encoder网络,采用Masked Multi-head Self-Attention组建Decoder网络。

在公开评测任务集上,Transformer较LAS在性能上有优势,同时由于采用了Multi-head,训练并行化效率更高。我们分析了Self-Attention和DFSMN memory block[3,4]之间的关联性:Self-Attention可以理解为采用了context-dependent系数进行全局建模,而DFSMN的memory block则采用了context-independent系数进行局部建模。对于语音识别,局部声学建模和全局语义建模都非常重要,因此我们提出了如下图所示的SAN-M模型结构,高效地融合了Self-Attention和DFSMN memory block。

image.png

SAN-M模块如上左图所示,将Self-Attention和DFSMN memory block融合一个模块,有效的结合了Self-Attention的全局长时建模能力和memory block的局部长时建模能力。基于SAN-M模块构建了如上右图的Encoder-Decoder离线语音识别系统(SAN-M-E2E-ASR),并在开源的1000小时AISHELL-2中文识别任务中获得了当前该任务的最优性能(CER=5.61%);在工业量级的2万小时中文识别任务中,该系统也显著优于我们之前线上的CTC系统和标准Transformer系统。

针对本次识别场景,我们最终实现了不到40MB的端到端模型,而识别性能则可以媲美上一代整体超过100GB大小的云端DFSMN-CTC系统。我们在finetune数据上进行了不同维度的挑选和搭配,并做了不同策略的数据扩增来覆盖多样的识别情况。针对模型输出的token,也进行了一定压缩,并拉低了与本次任务无关的token概率来降低误识别率。在ITN模块,我们采用精小的FST(Finite State Transducer)来实现规则网络,用状态转移来实现文字到阿拉伯数字的转换,通过边上权重来控制其转换方向,并在简略读法、谐音、容错上也做了一系列路径优化。

基于PAI-MNN云端一体化模型压缩

虽然达摩院语音实验室通过定制化语音识别模型设计,将原有的170MB模型裁剪至不到40MB,但是考虑到移动端的资源情况,我们还需要通过PAI-MNN云端一体化模型压缩方案,进一步将模型基本无损地压缩到15MB以内。

image.png

从训练、模型压缩到优化部署的PAI-MNN云端一体方案

PAI混合精度量化流程

image.png

PAI混合精度量化流程

上图显示了PAI团队 (PAI: Platform of A. I. in Alibaba)研发的无数据标注干预的自动混合精度量化流程Label-free AMP Pipeline,AMP: Automatic Mixed Precision),包括量化误差预补偿、离线标定、量化噪声分析与混合精度决策四个阶段,主要创新点包括:

  • 支持端到端Transformer的离线后量化:
  • PAI团队的后量化方法,引入了循环张量探针,以支持端到端Transformer的离线后量化。
  • 相比于拆图量化、量化训练等,端到端后量化具备快捷、高效的优势;
  • 集成了丰富的后量化策略,为后量化的精度鲁棒性提供了坚实保证,基本策略包括:
  • KL算法的改进,能够有效减少输入/输出张量的量化噪声;
  • EasyQuant参考文献 [5])的使用,可进一步减少输入/输出张量的量化误差,尤其能改善INT7等更低精度量化的效果;
  • Bias Correction参考文献 [6])通过补偿网络权重的量化偏差(均值与方差的偏差),以减少权重量化噪声;同时对Bias Correction的适当改进,增强了对SAN-M ASR模型的补偿效果;
  • ADMM参考文献 [7])亦可优化权重量化参数,减少权重量化噪声;也适当改进了ADMM的使用,从而在交替方向迭代范围内,确保权重量化误差最小;
  • Weight Adjustment参考文献 [8])在Kernel weight按Per-tensor量化时,通过Per-channel形式的等价均衡变换,可以减少Weight量化误差。
  • 无Label干预的混合精度量化流程:
  • 该流程从模型输入到混合精度决策,无需数据标注(Label)的干预,简洁易用、快捷有效;
  • 量化误差按逐层统计,且能准确反映每个网络层的量化敏感度,为混合精度(INT8/FP32混合)决策提供了可靠基础;
  • 通过控制回退的网络层数,可选择出精度与模型容量折中最佳的帕累托最优解,完成多目标优化;
  • 生成的混合精度量化表,能够对接移动端推理框架MNN,以生成低延迟、高推理精度的运行时推理引擎;从而构成了完整的工具链路,即从混合精度量化、到移动端的推理部署;
  • AMP Pipeline不仅适用于移动端,也适用于CPU/GPU优化部署,体现了PAI云端一体的优势所在。

基于PAI AMP Pipeline,有效实现了SAN-M模型的离线后量化(PTQ: Post-training Quantization)。为了保持算法模型识别精度,经AMP INT8量化之后(回退3个Op,分类层保留为FP32实现)。

为了解决压缩率的问题,MNN模型转换和优化工具对回退的算子统一使用权重8bit存储、float计算的方式进行优化,进一步压缩模型大小。通过一套统一格式的模型压缩文件,经过PAI AMC优化的模型可以顺滑无缝地转换到MNN的格式。

MNN模型转换工具基于现有的图优化流程,根据该模型压缩文件将float模型转换成MNN模型的同时完成离线量化,具体过程如下:

  • 根据量化表中提供的tensor name,在TensorFlow的计算图中生产和消费该tensor的边上同时插入一个自定义的量化和反量化算子。
  • 将TensorFlow的计算图转换成MNN的计算图,其中自定义的量化和反量化算子转换成MNN量化(FloatToInt8)和反量化(Int8ToFloat)算子。
  • 算子融合:将支持量化的算子、输入的反量化算子和输出的量化算子融合成一个Int8的算子。
  • 最后消除成对的MNN量化和反量化算子。

image.png

最终,SAN-M模型在众包测试集上的WER绝对损失低于0.1%、SER绝对损失低于0.5%、理论压缩比约为3.19倍。

基于MNN推理引擎的实时高性能计算

image.png

为了在移动端上实现实时的端到端语音识别模型推理计算,MNN在全链路上做了诸多优化。

端到端语音识别模型基于Transformer结构,包含一个对输入音频特征编码的Encoder和一个自回归解码的Decoder。这类模型结构要求MNN支持Control Flow、Dynamic Shape和Zero Shape等特性,因此,MNN首先在框架层面对这些特性进行了支持和完善:

  • MNN重构了Control Flow支持方案,提供用户透明的functional control flow实现,并支持了TensorFlow 1.x的控制流模型转换,为用户提供一站式的部署体验。
  • 对于Dynamic Shape的支持,MNN将整图按照动态形状算子划分为多个分段子图。在代码层面,一个子图对应一个Module,Module支持嵌套,即整图被表达为一个由Module组成的调用树,树的每个叶子节点可以使用一个Session来执行,Session每次执行前resize,重新进行shape推理和分配内存。
  • Zero Shape指的是模型中某些Tensor的shape存在0值,比如 (1, 0, 256),这种情况大多是为了给while-loop中某些循环变量提供初始值而引入的。MNN在形状推理和执行逻辑上对Zero Shape进行了支持。

之后,MNN根据达摩院模型新增了LayerNorm FuseConstant Folding、重复Reshape算子消除等图优化方法。图优化之后的计算图更容易和其他优化方法组合使用,比如,Constant Folding后MatMul的一个输入可能被替换成一个Constant节点,因此就可以转换成FullyConnected或Conv1x1进行加速,并且也更容易利用模型压缩方法对权重进行量化。

而后,语音模型的耗时重点仍然是矩阵乘法。MNN通过更优矩阵乘分块、基于 NC4HW4 布局优化前后内存布局转化、Strassen 算法改进等策略,优化了整体的卷积和矩阵乘的性能,ARM 架构上性能提高了 10%-20% ,保障了语音模型的高效运行。

同时,MNN最新提出的几何计算机制也在实时语音识别起到了重要作用。几何计算是MNN为了解决设备碎片化问题而提出的一种新机制,其核心在于把坐标映射标准化,以便统一实现与优化。在几何计算的支持下,我们可以较简单地合并相邻的纯形变算子,从而降低访存需求,提升模型运行性能。

最后,在PAI-MNN云端一体化模型压缩的加持下,我们利用量化表和有限回退机制,在精度损失可控的前提下,进一步降低了移动端上的计算总量。

RTF (real time factor),即实时率,表示识别一秒钟音频需要的耗时。

image

在这一系列组合拳之下,我们才最终在目标设备上,将RTF降低到了目标值0.02以下,从而实现实时语音识别,让「一猜到底」得以走到每一个用户的面前。

总结与展望

通过这次项目合作,基于高性能推理引擎MNN,结合一流的语音模型设计和模型压缩技术,我们已经能在移动端上实现实时的语音识别,并通过了双11核心场景的考验。

但我们并未止步于此。

达摩院语音实验室在千人千面的个性化语音识别上的研究工作业已展开,在保护用户隐私的前提下实现如联系人、住址、搜索历史等词汇的识别。PAI团队会继续携手MNN团队,进一步探索围绕端侧设备的精简模型设计和自适应模型架构优化方案。而MNN团队,则会持续建设流式识别、混合计算、编译优化等机制,为ASR、NLP等AI应用在端侧的发力提供最高效、最稳定的坚实后盾。

相信在不远的未来,我们就能为用户带来更加有用、有趣的AI交互体验。

参考

===

[1] Chan W, Jaitly N, Le Q, et al. Listen, attend and spell: A neural network for large vocabulary conversational speech recognition[C]//2016 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP). IEEE, 2016: 4960-4964.

[2] Vaswani, Ashish, et al. "Attention is all you need." Advances in neural information processing systems. 2017.

[3] Zhang S, Lei M, Yan Z, et al. Deep-fsmn for large vocabulary continuous speech recognition[C]//2018 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP). IEEE, 2018: 5869-5873.

[4] Zhang S, Lei M, Liu Y, et al. Investigation of modeling units for mandarin speech recognition using dfsmn-ctc-smbr[C]//ICASSP 2019-2019 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP). IEEE, 2019: 7085-7089.

[5] Di Wu, Qi Tang, Yongle Zhao, Ming Zhang, Ying Fu, Debing Zhang, "EasyQuant: Post-training Quantization via Scale Optimization", arXiv  preprint  2006.16669, 2020.

[6] Ron Banner, Yury Nahshan, Elad Hoffer, Daniel Soudry, "Post-training 4-bit quantization of convolution networks for rapid-deployment", arXiv  preprint 1810.05723, 2018.

[7] Cong Leng, Hao Li, Shenghuo Zhu, Rong Jin, "Extremely Low Bit Neural Network: Squeeze the Last Bit Out with ADMM", arXiv  preprint 1707.09870, 2017.

[8] Markus Nagel, Mart van Baalen, Tijmen Blankevoort, Max Welling, "Data-Free Quantization Through Weight Equalization and Bias Correction", arXiv preprint  1906.04721, 2019.

查看原文

赞 2 收藏 0 评论 0

阿里巴巴淘系技术 发布了文章 · 11月17日

2020天猫双11前端体系的建设与挑战

今年双十一整体节奏从之前的“光棍节”到今年的“双节棍”,具体业务上也有很多变化和调整,应了阿里的土话“唯一不变的是变化”。面对这些变化,是挑战也是机会,我们要做的就是,“既要”高效支撑保障业务先赢,“又要”确保体验和稳定性带给用户极致体验,“还要”追求创新让前端持续演进。为了实现“既要、又要、还要”,包括技术方案、流程机制、人员组织等各方面都进行了大量的设计和保障。最终第一次双峰的双十一圆满结束,淘系前端也实现了自己的目标,包括应用大量优化手段和创新方案带来业务转化提升;将FaaS、PHA、ESR等技术应用在更多场景,分别向服务端、客户端、CDN节点进一步拓展了前端的能力和边界;应用视觉还原、一体化研发等提升研发效率,大幅缓解资源瓶颈等等。下面会整体介绍一下淘系前端在今年双11的思考和沉淀,希望对大家有所助益。后续也会有各个专项的系列文章,希望大家持续关注。

(更多干货内容可关注【淘系技术】公众号)

变化 & 挑战

今年的双十一,首先感受到的就是源源不断的变化。

单峰变双峰:双十一从之前的一个波段变成今年的两个波段,大促的三个阶段预售、预热、正式也都对应的翻倍。首先带来的是研发工作量的大幅增加,在时间排期不变、工作量增加、人员不变的情况高效的完成需求研发是第一重挑战;其次面对6个阶段的状态变化,如何保持准确切换、稳定运行、体验流畅是在双峰期间要重点保障的内容;最后面对超过20天的超长作战期,安全生产、人员状态保持、快速反应都需要有强力的组织和机制进行保障。

image.png

图:双十一节奏

首页大改版:最新的淘宝首页首屏内容有颠覆性的变化,比如首屏内容简化,推荐提前,频道作为内容嵌入推荐等。各个业务在缺少固定的流量入口的情况下,包括运营策略、产品策略、设计方案、技术方案都需要积极调整。同时在各个场景的推荐能力也需要持续增强,今年双十一通过将坑位数扩展到1000+,理论可达无限扩坑;通过智能UI提升用户点击率。

Group2.png

图:手淘版本对比

业务变化:业务创新和新玩法层出不穷,包括mini详情、旗舰店、价格表达、笔笔返、芝麻购等在内的很多业务都是全新的表达、颠覆式的升级。即是业务上新的尝试,在技术上也要解决架构选型、对账、一致性表达、排期等问题。

做好本职

首先要做的就是做好本职工作,保障需求研发和稳定性。需求研发方面,我们通过D2C实现了大部分UI模块自动开发、通过建设Eva互动体系降低互动研发成本、通过Serverless的一体化研发提升研发和运维效率,使前端不再成为资源瓶颈。稳定性上,也通过一系列机制和工具体系进行保障。同时增加一块大家平时可能不太关注的资损防控的策略和方案。

D2C研发提效

去年双十一我们设立了研发效率专项,核心就是通过 设计稿生成代码(Design to Code, D2C)平台Imgcook 来提升研发效率。最终在去年的双十一大促会中承接了 78.94% 的新增模块代码自动生成,代码可用率达到 79.34%。

今年前端智能化助力前端研发模式升级,数个 BU 共建前端设计稿识别算法模型和数据集,设计稿生成代码技术体系全面升级,如对 UI 多态、直播视频组件、循环的智能识别增强等。今年双十一会场承接了 90.4% 的新模块代码智能生成,代码可用率达到 79.26%(对比去年升级设计稿智能检查能力,视觉稿无需人工辅助调整)。得益于D2C的研发提效,今年并没有出现往年借调资源投入会场开发的情况。相比传统模块开发模式,使用设计稿生成代码技术后编码效率(模块复杂度和研发耗时比值)提升68%,固定人力单位时间模块需求吞吐量增加约 1.5 倍。

image.png

图:D2C操作流程

互动研发升级

在电商领域,互动是一个重要的用户增长方案,在提升用户黏性、活跃以及拉新上都发挥着重要的作用。今年双11,淘系互动团队推出了“超级星秀猫”,我们不盖楼、不开车,全民参与养猫出道,3只风格各异的萌猫咪一经问世,瞬间俘获了无数消费者的心。通过 EVA 互动体系一整套解决方案,大幅提升研发效率,支撑全民养猫猫在手淘、猫客、支付宝等多个 APP 互通。借助客户端能力及 EVA 互动体系将性能与内存良好控制,让多数用户体验高清稳定的互动,实现 0 故障及秒开,同时星秀猫参与人数再创新高。后续的系列文章将具体阐述淘系互动前端团队是如何做到双11互动又快又好又稳,内容涵盖互动基础、EVA研发体系和全局稳定性方案3个方面。

image.png

图:互动效果图

Node FaaS一体研发

Serverless云+端研发模式通过打通页面代码和服务代码进行一体研发,使得前端可以从前台页面到后端服务完整支撑,节省中间沟通和联调成本。在天猫榜单以及V榜的落地,使得双11 Node FaaS 相关业务整体研发效率提升38.89%。行业导购双十一需求也在云+端的新模式下支撑外包快速入场,使得整体提效约20%。

稳定性保障

稳定性保障贯穿从项目启动到结束的整个双十一周期,下面从几个重点方面进行简单的介绍:

变化评估:每年的双十一都是站在巨人的肩膀上,都经过了上一次双十一的考验。主要的风险就变成新增的部分以及变化的部分,这里的变化既包括技术上的变化也包含人员上的变化。要做到对变化的充分评估,在99大促进行验证,并且保证99大促后不再进行变化,以一个稳定的状态迎接双十一。

压测:首先要进行流量评估,借鉴去年数据的同时结合今年的变化,进行相应的机器、带宽等资源准备。完成单线路压测,保证在预估流量模型下,自己的服务和上下游都能够运转正常。进行全链路压测,核心验证在0点高峰时各业务并发的情况的运转情况,尤其是一些底层公共服务,以及优先级的保障情况。

兜底&预案:兜底一般指在大流量或其他不可控因素的情况下,如何将用户体验和业务损失降低到最小。预案需要评估可能遇到的各种情况,以及对应的处理方案。

验收:功能预演,按照用户的所有使用路径进行操作,目前这个工作仍是人工。时间穿越,将页面和系统的状态都调整为活动时间来验证,需要打通上下游的各个系统并形成联动。机型验收,基本分为高端机、中端机、低端机,分别进行验收,很多业务都需要针对低端机做功能降级。稳定性验收,单独页面的性能和稳定性各自保障,但业务叠加后很可能存在问题,尤其像会场、互动、直播、旗舰店等内存消耗大户,互相之间都有引流,切换后很难保证,需要整体全链路验收。

变更&应急:历次的故障数据表明,大部分的问题都是由于变更导致的,如何做好变更管控尤为重要。根据时间分为弱管控、强管控期;根据业务等级分为集团核心应用、BU核心应用、非核心应用等;建立变更的CR和审批的机制。应急主要指在核心活动期间,问题、舆情、故障等流转机制,针对问题发现、定位问题、修复问题时间作出要求,不同等级如何决策作出安排。

监控:淘系前端持续进行监控能力的建设和升级。需要保障大促高峰的可用性以及报警的实时性,覆盖所有的业务场景。针对越来越复杂的场景,需要端到端的监控和数据分析平台。灰度过程缺少度量和定点监控。根据这些问题和需求,jstracker提供了安全生产的整体解决方案,打造端到端的前端监控与数据分析平台,打造实时监控、多端覆盖、数据分析、智能化的数据平台。同时根据页面情况、错误日志、源站数据、FaaS日志等打造了双十一的前端数据大盘。

资损防控

一直以来前端资损防控是平台非常薄弱的一环,前端触发的资损和舆情问题不在少数。之前全靠开发同学的经验和意识来保证,缺少体系化的资损防控能力。去年开始组织了团队层面的集中筛查和人工预演,对人力和时间的消耗非常巨大,并且很难保证质量并进行积累和沉淀。所以为了能有一种成本更低、预防效果更好的方式进行资损防控,2020年 S1 伊始,就重点对资防做相关产品化的设计和实现。同时今年也重点增加了商家、运营中后台侧的资损防控。

我们将资损防控氛围了三个阶段,研发阶段、操作阶段、运行阶段。研发阶段给存在资损风险的仓库打标,将常规的价格、优惠、默认文案等case进行枚举,通过静态扫描、UI测试用例扫描等方式进行防控。操作阶段,主要是指商家、运营进行优惠、权益等设置的阶段,通过表达方式统一(避免5折、0.5折造成理解差异)、二次确认、限定边界值、低价预警等进行防控。运行阶段有快照对比、服务端数据对账等方式,运行阶段的防控相对滞后,发现时很大概率已经造成实际的影响。

然而,目前仍是预防为主,不能百分之百保障没有资损故障发生,接下来我们还在构思链路级别的、生产环境上的防控手段,建设一些告警和自动止血为平台保驾护航。

业务价值

做好本职的基础上,我们希望给业务带来增量价值。本章从会场性能优化提升转化、基础链路新方案提升转化、唤端技术定制策略提升精准率、智能UI为不同人群提供不通过UI提升点击等4个方面来介绍。

性能提升

会场是每年双十一的主角之一,会场的用户体验自然也是每年最关注的点。在日趋复杂的业务需求下,如何保障我们的用户体验不劣化甚至能更优化是永恒的命题。今年分别使用了预渲染方案和SSR方案进行优化,首先是重新定义了秒开的标准,从原来的前端时间升级到从用户点击经过跳转到页面可视的时间,增加了客户端路由、webview启动等时间,使体验的衡量更贴近用户真实的体感。覆盖了包括主会场、行业会场、外投会场等数十个场景。

预渲染

预渲染是在今年双11会场中使用的技术方案,用于提升用户打开会场的体验。将原有H5页面渲染流程中的WebView的初始化、页面资源加载、部分JS的执行等耗时的操作,提前执行,在离屏状态下完成页面“渲染”。当用户真正点击进入会场的时候,复用这个提前“渲染”的页面,大大节省打开会场的时间。用户打开会场的整体平均耗时缩短了200ms~700ms左右,秒开率提升10%-14%。优化对中低端机绝对收益更高,已实现在低端机上实现秒开会场。让用户逛会场体验更流畅了,尤其中低端手机效果更加明显。在后续的文章也会讲述包括预渲染、数据快照、并行请求等性能优化方面的实践与思考。

Android y67 对比视频.gif

图:中低端机型预渲染效果对比图

SSR

今年在不改变现有架构,不改变业务的前提下,在会场上使用了 ServerSideRendering 技术,将秒开率提高到了新的高度(82.6%);在用户体验得到优化的同时,业务指标如点击率等也有明显的增长,带来了不错的业务价值。后续的系列文章汇中会详细介绍前端在解决工程化、业务效果评估上的具体实践与方法论;服务端在解决前端模块代码于服务端执行、隔离和性能优化上的思考和方案。

循环.gif

图:中低端机型 SSR 效果对比图

基础链路

基础链路是电商核心的链路,包含首页、商品详情、微详情、交易(下单、订单、购物车、支付成功)、信息流、我的淘宝等基础业务。现有的技术方案是手淘内使用Native版本,追求极致的体验和稳定性;站外流量、包括支付宝在内的阿里系App使用H5版本,追求灵活性和可用性。随着支付宝容器化体系的完善,在其他App中的内聚,基础链路新的容器化版本具备了孵化的土壤;同时H5的一些弊端,比如资源都在远端、Native能力使用限制等也可以得到优化。

借助之前的“新奥创”和“DinamicX”方案(主要解决业务定制以及安卓、iOS、H5的三端一致,实现一处开发、三端生效),容器化版本得以快速扩展,实现四端一致。性能数据上,加载时间对比H5版本有2s的提升,基本达成秒开的目标;业务数据上,容器化版本对比H5版本UV转化率提升70+%。

目前已覆盖支付宝、特价版、优酷、高德、淘小铺、一淘等App,以及通过百川SDK集成在众多外部媒体App。业务上也接入了每日必抢、大牌直降、淘宝特价、淘宝直播、百川媒体、优酷、小铺、轻店、花呗等业务。

唤端技术

随着流量见顶、电商大战进一步升级,如何做好用户增长是各大公司必须完成的命题。用户增长涉及的面非常广泛,今年淘系前端聚焦在唤端技术,即外部流量拉起手淘App的技术体系。唤端技术的门槛很低,简单到只需要拼一个类似 URL 的 scheme 就可以触发唤端。唤端技术又很复杂,不同的渠道、不同的OS、不同的 App 都有可能针对唤端协议有限制,并有各种各样的兼容性问题;唤端链路中不同业务可能都有自己的业务定制需求,例如参数的透传;唤端链路的效率更是被关注的核心点,不同场景不同业务在效率上可能都不一样,因此还需要对唤端效果进行监测和对比。为了解决这些复杂的问题,我们在唤端技术上进行了又一次升级,建设了可定制的唤端策略,打造了详细的唤端AB测试链路。从本次双11 的效果看,不同场景下的唤端效率(唤端成功率)相对提升了 25~40%不等。

image.png

图:唤端策略图

智能UI

随着移动互联网和推荐系统的发展,人和商品的精准匹配为业务带来了效率的大幅提升。越来越多的精细化手段逐渐应用于个性化推荐领域,比如场景化推荐、人群定投技术等。同时商品的信息比以往任何时候都要丰富(买家秀,品牌背书,无忧购服务等),不同的用户对于内容的UI表达有着差异化的诉求,因此通过为不同人群找到合适的UI表达一定能带来业务效果的提升。

项目的最早期,我们通过AB实验直接定量测试,明确了相同的UI方案在不同的场景会产生差异,不同的UI方案在相同场景下也会产生差异。也就是说,针对不同场景使用不同方案是有意义的。2020年双十一大促我们第一次大规模采用智能UI产品化方案落地了多个前端模块,包括猜你喜欢模块、商品模块、店铺模块等,覆盖了双十一的预售和正式开卖阶段,承受了流量洪峰的考验,且带来了稳定的增长。覆盖300多个会场,最高的会场PV点击率相对提升10%+。

技术升级

伴随业界的技术演进和业务的发展,我们在技术上相比去年也有了新的尝试和迭代升级,其中典型的包括FaaS的深度使用、PHA渐进式的体验增强、边缘节点渲染的应用等。

FaaS

Serverless,一块深水的坚冰,逐步从深海付出了水面,阿里淘系从去年在大促实践开始,逐渐将 Serverless 应用到前端领域方方面面。今年双十一首先是在覆盖场景方面,FaaS从淘宝行业拓展到会场和营销业务,业务的复杂度得到极大的丰富。能力进一步提升,支撑的业务量级也从2k QPS提升到5W QPS,CPU水位从去年的高 QPS 规模时,精力花费降低约50%。在研发体验方面,打造解决方案体系,单元保障、大促管控、专家系统、函数盘点等能力,运维提效约50%。在研发体验方面,打造解决方案体系,降低研发门槛,支持外包快速入场。

PHA

PHA 全称 Progressive Hybrid App,是提升 Hybrid 体验的一种应用框架。提升页面加载速度和交互体验的渐进式 Web 应用,使用 PHA 开发的应用本质上没有脱离前端开发和 W3C 标准,但依然拥有原生应用的特性和体验。或许你有想到 PWA,但 PHA 有比 PWA 更强的 UI 能力和更快的加载速度。目前已经在手淘、特价版、Lazada、CBU 等多个客户端落地,支持了618、双11等多个大促。PHA联合客户端、前端团队、数据分析团队,跨栈协同,在性能优化方向上也做了很多优化工作,梳理全链路性能埋点、定义新的性能口径(从用户点击到可视),使用了预加载、预渲染、资源加速下载、离线资源等优化手段。

ESR

现在的渲染节点主要是在终端或是服务端,对应CSR(Client Sider Rendering)和SSR(Server Side Rendering),分别有适用的场景以及优势和弊端。现在借助阿里云的能力可将渲染转移到CDN节点,也就是我们要介绍的ESR(Edge Side Rendering),即能为前端提供渲染能力,同时也能将大量CDN机器上的计算资源利用起来。

阿里云推出了CDN轻量编程环境——EdgeRoutine,这为我们提供了一个新的尝试方向。我们可以在CDN节点去做提前渲染的事情。CDN的访问策略是会去寻找离用户最近的节点,就像快递运输的最后一公里一样,总会派送到离客户最近的分拨点。这么看来页面的网络调度时长是非常有优化空间的。并且我们还可以利用CDN节点资源共享的特性,将部分数据缓存到CDN节点上,减少远程的数据请求。

这套方案对于数据刷新率不高、访问量极大的页面,ESR搭配CDN的缓存能力是非常适合用的。以达人页为例,首屏时间约能提升50%左右。现在ER的技术才刚刚起步,应用场景比较局限,能力上还有很多不足,体系也需要不断地建设,但这个新技术为前端提供了更多可能,需要我们不停的去探索和完善。

双十一PM初体验

双十一作为电商年度最核心的节日,各方面投入的力度和资源都是最大的。作为参加过8次双11的老兵,作为前端PM是第一次,有很多不一样的感受。

复杂:首先是业务上,有双十一定制和特有的主会场、主互动、猫晚等,还有淘系内部本身就有导购、行业、营销、直播等数十个业务,同时联动支付宝、优酷、本地生活、阿里妈妈、菜鸟等多个集团BU,与商家、ISV、物流、媒体等的协同和合作。技术上同样复杂,前端的页面从开发、搭建、源站、CDN的全部链路,以及Node FaaS的容器、中间件、容量准备、流量调配、机房部署等。管中窥豹,对于整个体系的认知还需要更进一步的探索。

流程:双十一作为电商业务每年的大考,已经摸索出一套成熟的流程机制。包括人员的组成、沟通机制、时间排期、组织保障等各个方面都有很细致的机制进行保障。

协同:双十一是非常好的节点,可以让各团队、各岗位、各BU之间形成联动,集中力量将如此庞大的体系进一步完善。很多技术的升级和突破都是在双十一落地并进一步推广的。这次预渲染的方案就是客户端和前端紧密协同,在很短的时间内实现并验证的。

多维:看问题的视角可以更多维,不同技术岗位视角,全链路视角,业务的视角。以一次变更的审批为例,之前更多关注变更的代码实现上,对上下游的影响、对稳定性的影响、对业务的影响、是否引入新的风险、影响的范围等等都需要进行综合衡量,做一个判断往往需要从中进行取舍,而不单单是技术上的1和0。

招兵买马

最后的最后,招聘贴!

image.png

淘系前端由淘宝前端、天猫前端、手淘前端三大前端团队融合而成,在业务上负责淘宝、天猫的所有业务,如:双11&双12大促、聚划算、天猫新品、有好货等营销导购产品、淘宝直播&短视频业务、商业千牛以及开发、用户增长、互动&游戏等等,囊括了新零售域下最复杂、最多形态的业务场景;在技术上在前端工程、多端架构、Node架构、互动架构等基础体系上有着深厚的沉淀,同时在多媒体、前端智能化、云手机等新兴体系上布局&发展,在搭建&投放、小程序开放、工作台等应用体系上直接助力业务。

网址:https://fed.taobao.org/

邮箱:taobao-fed-zhaopin@list.alibaba-inc.com

职位:前端开发专家-杭州/北京端架构 TL前端技术专家(IDE方向)前端技术专家(Node.JS)互动技术专家Web多媒体领域专家-杭州/广州云手机解决方案架构师中后台领域架构师用户增长领域专家投放技术高级专家软硬件技术专家开发者平台产品经理

查看原文

赞 8 收藏 3 评论 2

阿里巴巴淘系技术 发布了文章 · 10月28日

AI for everyone,阿里淘系MNN工作台正式公测!

阿里巴巴淘系技术开源轻量级深度学习推理引擎 MNN 以来,得到了业界的普遍认可 —— 数十家企业成为 MNN 的用户,不乏有一线科技企业;此外,MNN 还与上海交大等一线院校展开合作,深度连接产学研。

除 MNN 引擎建设外,MNN 团队还深度参与了阿里内部的端AI应用实践。AI 应用门槛高、算法模型部署链路长是长期困扰我们的问题。为了解决这两个问题,我们将上百次实践中长期积累的方案沉淀为一站式 AI 研发范式 —— MNN 工作台

☞  文末可点击进入官网下载体验!

今天正式推出 MNN 工作台,这将极大降低AI应用门槛、将AI研发的效率提升数十倍,让“技术小白”也能快速上手,轻松设计自己的AI应用。

image.png

要打通AI应用的“任督二脉”,需要“十八般武艺” —— 你需要同时熟悉AI和业务,要搜得到数据、啃得了论文、改得动模型,末了还得会移动开发,打通业务流程。道阻且长,任一环节出了问题,都可能断送AI应用探索之路。

市面上其实不乏有一些云端模型训练平台,但大多只在流程中的数据和模型上下功夫。相较之下,MNN 工作台是第一个同时应对 AI 应用启蒙、无门槛训练和一键多端部署的一站式 AI 平台。

AI 应用启蒙最好的办法是参考行业的最佳实践,并且动手玩一玩。

MNN 工作台中,提供了人像分割、文字识别等主流应用的实例,无需训练就可以直接使用。通过 MNN 工作台,可以方便地在电脑和手机上体验AI的效果。AI 的视觉效果会直接叠加在相机视频流上,改变相机机位,就可以看到效果的变化。同时,还可以通过开关、滑块等来调节算法参数,同样可以实时观察到调整的影响。随手改、随心玩的即时体验,可以帮忙用户理解算法,打开想象的空间,更好地寻找AI和业务的结合。

在帮助用户无门槛训练自己的AI算法模型方面,MNN 工作台也下足了功夫。

MNN 工作台支持图像分类、文本分类等模型的训练,而且,所有的操作都可以通过图形化界面来完成。用户不需要了解模型训练的细节,只需要按照提示,提供训练所需的数据,就可以完成模型的定制。同时,MNN 工作台使用了迁移学习技术,用户仅仅需要少量的训练数据,就可以训练出效果上佳的专属模型。MNN 工作台还提供了自动化标注工具和手工标注工具,来进一步简化训练数据的准备工作。最后,在模型训练完成时,MNN 工作台还会提供模型测试报告,涵盖模型的大小、性能、精度信息,辅助决策。

应用多端部署方面,MNN 工作台为电脑和手机都提供了强大的 Python 运行环境 —— 三端一致的开发体验。

但更友好的,还是 MNN 工作台上所有的模型,都可以在电脑和手机上直接体验。是的,无需任何一行代码,试玩模型或训练模型都有对应的、已经编写好的代码!如果你需要修改算法实现,我们也提供了 Numpy、OpenCV 等常用库,尽可能降低图片、数据处理的成本。同时,在工作台上,扫码真机调试,断点、console 一应俱全,更有多端文件实时同步这样的黑科技等待你的解锁。

下面是 MNN 官网,欢迎安装下载~有疑问可联系我们

http://www.mnn.zone/

————————————————————————————————

阿里巴巴集团淘系技术部官方账号。淘系技术部是阿里巴巴新零售技术的王牌军,支撑淘宝、天猫核心电商以及淘宝直播、闲鱼、躺平、阿里汽车、阿里房产等创新业务,服务9亿用户,赋能各行业1000万商家。我们打造了全球领先的线上新零售技术平台,并作为核心技术团队保障了11次双十一购物狂欢节的成功。我们的愿景是致力于成为全球最懂商业的技术创新团队,让科技引领面向未来的商业创新和进步。

查看原文

赞 0 收藏 0 评论 0

阿里巴巴淘系技术 发布了文章 · 9月14日

聊聊鸿蒙系统与开发者生态前景

来自于阿里淘系的安卓开发同学之羲,站在开发者角度,给大家聊聊华为鸿蒙系统2.0版本后对鸿蒙生态、消费者端厂商、芯片厂商以及二三方应用开发&应用市场带来的影响。

本篇回答仅为开发者个人角度观点,欢迎大家一起讨论交流。

从1.0到2.0?

近日,中美关系的不确定性再次加大,国家层面提倡科技创新,强调把原始创新能力提升摆在更加突出的位置,努力实现更多”从0到1”的突破。在这样科技强国的大背景下,华为作为中国科技的领跑者之一,华为开发者大会9月10日在松山湖召开,再次提到举世曙目的鸿蒙操作系统,并发布了鸿蒙2.0以及最近的发展路线图。

从去年鸿蒙系统发布之始,鸿蒙系统就备受争议,其相关话题在知乎,贴吧等社区也火了一把。而最近发布的2.0,再次激发了行业内的关注。实际上,在鸿蒙开源官网,当前开源的版本仍然是标记为OpenHarmony 1.0 baseline的TAG。2.0的源码是否在路上,我们不得而知。

image.png

不可否认,去年的开源,那是千呼万唤始出来,犹抱琵琶半遮面,今年的相关文档与源码比去年完善了许多,似乎是一个可玩的版本了,可以烧在开发版上运行。 但相比Android/iOS等成熟的开发者工具链,略显简陋。确实是刚启步,我们也不能要求华为一出来就是成熟的产品。今天,笔者将从开发者生态的角度来聊聊鸿蒙系统。

鸿蒙生态的层次化

作为开发者,最近切的希望是了解未来能支持哪些设备,从鸿蒙2.0的路线图看,现在主要还是智慧屏,车机,手表等专有领域上,并没有类似手机这样的应用市场,自由上架的完整意义上的开发者生态。而据说今年年底会有可运行在手机上的beta版本(一定不要忘了beta这个词),我们再试目以待。

其实蛮喜欢华为的一句话,"没有人能够熄灭满天星光,每一位开发者,都是华为要汇聚的星星之火。"愿望很美好。华为开源的初衷,应该是为了让更多的友商,包括设备商,oem商,芯片厂商,iot商,应用开发商等一起进来合作,所以,明显华为对生态的设计上,是进行了分层的,在不同的成熟期,主要推动相应的生态合作伙伴。

消费者端厂商

分析一下,不难得出一个结论,开源的版本和商用的版本,应该是两个不同的分支,商用的分支,应该会完善很多,如果按华为上线的智慧屏是采用鸿蒙系统来看,它们之间,猜测还是有个代差,而且未来会一直保持这个代差。当然我们也不期望华为一下子把投入多年的软件资产开放出来。 因此,在当前的状态下,并不能奢望其他的消费者端的厂商开发出基于鸿蒙系统的电子产品,他们一定是等着这个系统成熟或者某个外因(众所周知的如华为中兴)而不得不用。这一层的厂商,应该是在观望中。

芯片厂商

而对于芯片厂商,如果华为鸿蒙系统有电子产品面世,必然会有一些与华为合作的厂商参与进来,目前来说,我更愿意相信,如果有,还是主要存在于华为内部。而方案集成厂商的合作,想必会更加遥远,需要基于鸿蒙的前景更加明确后,才会有厂商进来解决更大规模化的问题。

二三方应用开发&应用市场

华为当前主要推动生态参加与者,我相信更多是有合作的二方以及少量的三方应用开发商。主要以解决某些特定场景的应用为主。从目前华为提供的开发资料看,目前支持Java和JS,未来可能有更多的语言。

image.png

鸿蒙的应用,以.hap结尾,类似于android的.apk。从目前的资料看,hap的编写很类似android的开发,无论是ide或是api,都有一定的相似性。对android开发者的学习成本看起来不高。

image.png

而另一种方式,则是以小程序为代表的前端技术栈开发方式。

image.png

像阿里淘宝这样的三方开发者,要融入鸿蒙这样的生态,相信华为还有很长的一段路要走,目前还没有看到类似应用市场的发布渠道。笔者认为,目前鸿蒙上的应用开发方式,虽然类android,类小程序,好像即照顾了Android开发者,又照顾前端开发者,但终归不是兼容的。如果不能兼容android系统的runtime环境,与现有的android生态作衔接,鸿蒙的路将会非常艰难。

写在最后

尽管与国外多个优秀的操作系统相比,仍存在一定差距,不管怎样,鸿蒙作为能够运行在电子设备上可商业化的国产操作系统,的确是意义非凡。不必妄自菲薄,客观的看待它,了解它。期望鸿蒙操作系统能如同像它的名字一样,为中国科技的腾飞,开创一片天空,在科技世界的舞台上有它一席之地。

——————————————————————————————————————————

本账号主体为阿里巴巴淘系技术,淘系技术部隶属于阿里巴巴新零售技术事业群,旗下包含淘宝技术、天猫技术、农村淘宝技术、闲鱼、躺平等团队和业务,是一支是具有商业和技术双重基因的螺旋体。

欢迎收藏点赞关注我们!共同进步~ :)更多技术干货可关注【淘系技术】公众号

查看原文

赞 3 收藏 0 评论 1

认证与成就

  • 获得 76 次点赞
  • 获得 0 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 0 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 6月11日
个人主页被 4.1k 人浏览