三代终端容器 KUN 的首次大考架构演进

Posted 闲鱼技术

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了三代终端容器 KUN 的首次大考架构演进相关的知识,希望对你有一定的参考价值。

闲鱼号在闲鱼业务中一直承担着非常重要的角色,它既是卖家组织商品的货架,又是达人自我表达的载体,既是大 V 私域运营的阵地,又是小铺开店经营的门面。它是闲鱼各产品线的交汇点,号店浑然一体,一定要类比的话,它更像是抖音/小红书个人主页 + 淘宝店的综合体。

闲鱼号是个用户高频访问的场景,产品 Feature 快速迭代,体验上备受关注,当下面临的问题:

  • • 古董级高度耦合的业务代码、多业务线并行的日常需求时常让前端成为交付瓶颈

  • • 基于 Weex 1.0 渲染附带着大量的双端不一致问题和体验顽疾,也限制了交互创新

最近我们对闲鱼号做了架构升级,相信很快就会和大家见面,这里做个小结,概括下来这次升级直接带来的收益:

体验

中高端机上维持秒开,同时:

  • • 新增微信朋友圈式的下拉封面交互,手势体感更加连贯,个人表达更加充分

  • • 新增贴近原生体验的下拉刷新交互,提升 APP 体验一致性

  • • 优化嵌套滚动的交互体验,纵划横划更加自然顺滑,逛起来更高效

(iPhone12/ios16 录制,Gif 压缩掉帧严重,实际无明显卡顿感)

  • 可维护性

可维护性的提升是「产品->设计->实现」综合优化的结果,具体:

  • • 产品侧重新梳理所有 Features,抽象并制订同类功能的表达原则,确定各业务的表达方式、优先级

  • • 设计侧综合考虑模块权重、所属角色、用户比例、扩展方式等因素确定设计框架

  • • 技术侧通过组件化拆分+全局状态的方式解耦业务逻辑,提高需求并行效率

为什么要升级

闲鱼号项目已有超过5年历史,目前业务较难向前迭代,原因主要归结为端容器能力受限和架构腐化两方面。

端容器能力受限

闲鱼号目前是前端页面,容器使用 Weex 1.0(后文统称 Weex)。Weex 两年前就少有维护,其既有问题使得承载当下业务有以下问题:

  1. 1. 难维护。闲鱼号存在较多的舆情顽疾,究其原因,Weex 不是标准前端容器,在布局、组件、动画、事件等方面与预期不一致。一部分绕道解决,一部分只能保持现状依托升级容器解决

  2. 2. 难做好体验。业务定位使闲鱼号在体验上有较高要求,但“这个交互是 Native 实现的,Weex 做不了”不时会出现在业务迭代的技术评估中。

项目架构腐化

闲鱼号有较高的业务复杂度和较厚重的历史上下文。承载了人设、电商、内容、信任等领域的业务,同时存在多维度视图(主/客态、B/C态、内容/电商态),多年下来已发展到 5.x 版本,技术架构仍未进行过本质升级,相关问题已严重影响项目日常维护和迭代,主要体现在:

  1. 1. ViewModel 过于复杂。ViewModel 是大管家,统一格式化、将数据派发到模块。在平铺了15+模块数据的场景,ViewModel 改动不时“牵一发而动全身”

  1. 2. 缺乏统一的状态共享方案,数据流混乱。组件间通信存在 Vue 事件体系、自建事件体系、全局 controller 、自建状态共享体系多种方式

升级目标

对应上述问题,闲鱼号迎来了技术架构升级。升级核心目标是,未来1-2年技术架构不成为项目迭代、维护的吞吐瓶颈,支撑业务快速、平稳、创新的发展,能持续保持高标准体验。其中:

  • • 容器能力:升级渲染容器,提升容器能力边界。明显减少存量体验顽疾,多场景协助业务、设计完成理想的交互、视觉体验

  • • 项目架构:模块解耦,打造清晰的数据流。明显提升迭代效率,减少影响面回归成本和压力,降低不同模块协作冲突次数

其中针对项目架构部分非本文重点,主要通过模块化前端后数据协议、统一状态管理方案进行了解决。后文继续介绍容器能力部分的思考和实践

为什么用 KUN 渲染?

闲鱼号端侧主要问题

为对症下药,对闲鱼号端容器(Weex)侧进行了全面的诊断。问题集中在性能、渲染质量、扩展能力、终端体验一致性四个方面

  1. 1. 性能:闲鱼号首屏(700ms)和交互性能不错,性能问题主要在内存上,Weex 页面重度访问是闲鱼客户端 OOM 的主要场景之一。启动 Weex 容器会产生较大的增量内存,部分控件无回收机制也会导致内存增加,如 waterfall 组件: 加载 5 页带来了 3000 个未释放内存节点、40M 内存增量

  1. 2. 渲染质量:在基础样式、布局、事件体系等方面和前端预期不一致,如:

    1. • 不支持 overflow: visible

    2. • 不支持 z-index,层叠只能通过节点位置先后实现

    3. • 不支持 display: inline, 替代方案 rich-text 标签不支持 line-height 等基础样式控制

  2. 3. 终端体验一致性:闲鱼号工程中充斥着大量形如 if(isIOS)xxxx else if(isandroid)xxx的代码,主要作用之一按端处理,以规避渲染差异。尽管如此,目前两端仍存在不小差异。

  3. 3. 扩展能力:前端标准和生态起源于 PC,无线设备相对于 PC 存在不少特性,无线端原生能力相对于纯前端也更加丰富。受容器扩展能力(成本)限制,前端无法(标准)实现部分业务认为理所当然的体验:

    1. • 无法在元素上屏前获取元素布局信息(宽、高、位置)。大多折叠场景需要

    2. • 高频动画性能不佳。绑定滚动的动画如 曝光、导航透明度渐变等场景

    3. • 基础控件能力缺失。如:输入框无法自动聚焦、控制聚焦时距离键盘空间;增强控件定制困难,如在嵌套滚动容器上添加回到顶部

为从根本解决上述问题,我们进行了新容器调研。

渲染容器选型

在无线前端容器演进过程中,前端侧比较固定,框架(React、Rax等)驱动业务代码生成 Virtual DOM 以抽象视图结构, 特定 Driver/容器内置 JS Module 将 Virtual DOM 翻译为容器对应的渲染指令;容器侧主要历经 Webview 容器渲染 -> 客户端渲染衍生 -> 自绘渲染(衍生)三个阶段。其中:

  1. 1. Webview 渲染容器。为解决 Native 页面 双端研发成本、双端渲染不一致、无动态化、页面与客户端耦合的问题,Webview 容器开始承载无线业务

  2. 2. 客户端渲染衍生容器(React Native 、Weex 1.0)。 Webview 解决问题的同时引入了新的问题,渲染性能和能力边界明显逊色,故在 2.0 时代诞生了客户端渲染衍生容器,对接起了前端、客户端生态,用前端生态写,用客户端能力渲染。

  3. 3. 自绘渲染衍生(基于 Flutter/完全自绘)。客户端渲染一定程度了解决 Webview 渲染性能、能力边界的问题,但将前端标准/生态 “翻译” 为 Android/IOS 标准/生态的过程,存在明显的失真,实际渲染与预期不一致,Android 与 IOS 不一致。由此,更彻底的方法是重写渲染能力以进行统一。

自绘渲染方案一方面性能优于 Webview,一方面渲染一致性优于 Weex,闲鱼号新容器往自绘(衍生)类选型便是自然的方向。 在自绘容器中,基于 Kraken,闲鱼技术团队自研了 KUN 容器,整体思路是对接前端和 Flutter 生态,用前端写,在Flutter 渲染。对于上文提到闲鱼号端侧的 4 个问题, KUN 对应的解决原理如下:

  1. 1. 性能(内存)

    1. • 对于已接入 Flutter 的客户端,打开 KUN 页面的增量内存只有 KUN 引擎本身,没有 Flutter 负担,KUN 引擎较为轻量,内存增量相对于 Webview、客户端衍生方案较少

    2. • Flutter 自身提供了良好的回收能力(sliver),在无限流(瀑布流)场景,内存占用不会随内容加载无限上涨

  2. 2. 渲染质量:借助 Flutter 像素级渲染能力,上述overflow: visible、z-index、rich-text等问题均能解决

  3. 3. 终端体验一致性。前端对接的生态从两套变成了一套,以 React Native 和 KUN 中 Text 组件渲染为例:下图中,Text 业务组件在 React Native 下被转为了 JS 元素,在 UIManager.js 中转为 RN Element RCTVirtualText。接下来就是客户端部分,RCTVirtualText 在 C++ 层通过 Bridge 将指令传递给 Native UIManager,UIManager 根据所处不同的系统环境进行组件映射,IOS 映射到 UITextView,Android 映射到 TextView。相对之下 KUN 则是一套映射,呈现 Flutter 基础组件,便能有更好的终端一致性

  1. 4. 扩展能力:经过一层 KUN Element 抽象,自定义 Flutter 组件也可视为基础组件同等公民开放给 KUN 前端。如此,通过低成本对接前端、Flutter 生态等方式,KUN 有了灵活强大的扩展能力,以嵌套滚动容器为例:

以上从理论层面推导了 KUN能解决上述问题,我们便开始了闲鱼号升级到 KUN 容器的实践。 现阶段已完成升级,经过了一轮技术灰度。回顾升级过程,也像新生事物一样充斥着标准对齐、性能等诸多细节问题,但最终都悉数解决,整体体验符合预期。

体验变化效果 

性能

  1. 首屏性能上,KUN 与 Weex 1.0 勉强持平,中高端机器上维持秒开。内存水位上初步测试较 Weex、WebView 有所降低,待补充准确数据(上图为 KUN,下图为 Weex)

渲染质量

  1. 基础样式、布局、事件体系等方面已基本对齐前端标准,overflow: visible、z-index、rich-text等均已正常渲染

  2. 扩展能力

  3. Kun 使得前端享有了闲鱼客户端 Flutter 生态。闲鱼号升级中,快速扩展了前端无法(标准)实现组件10余个,包括:

    1. • 流畅嵌套滚动

    2. • 富交互下拉封面

    3. • 滚动视频播控

    4. • 图片加载控制(裁剪、渐显等能力)

    5. • 带高斯模糊背景的弹幕

    6. (Gif 压缩掉帧严重,实际无明显卡顿感)
  4. • 借助 Flutter 能力取背景图主色的蒙层

  1. • 借助 Flutter 在上屏之前能获取布局信息,标准化实现了纯前端难以模拟的行数过多动态折叠功能

终端体验一致性

  1. 渲染引擎较少与 OS 渲染能力耦合,解决了双端组件、交互(bounce 效果)、布局等方面不一致问题。 除了文字排版和字体外,基本做到双端一致。研发过程中,渲染层面也几乎不出现 if(isAndroid)renderAndroid() if(isIOS)renderIOS()的代码。

后续思考

如果从闲鱼号端侧诉求的视角出发,我们可以这样看待 KUN 的演进:

KUN 在基础规范上会持续扩充,并且与 W3C 规范持续对齐;在扩展能力上通过 CSS 扩展、JSAPI 扩展、混合组件扩展等方式持续增强容器能力、拓展容器边界、提升用户体验。

闲鱼号架构在持续演进中。有了 KUN 的加持,我们对此充满信心。

秒级容灾,UCloud 内网高可用服务之三代架构演进

快节奏的生活,任何的业务异常 / 中断都是不能容忍的。

在无人化超市选购完成进行结账时,结账页面突然卡住,无法完成购买操作。这时该选择放弃手中的商品 or 继续等待?

酒店办理入住时,管理系统突然崩溃,无法查询预订记录,导致办理入住受到影响,酒店前台排起了长队……

高可用与我们每个人都是息息相关的,在即将到来的双十一,更是对各个电商的业务可用性提出了更高的要求。对此,UCloud 提供基于内网 VIP 的高可用服务,内网 VIP 通过前后三代广播集群的设计演进,解决了复杂异构 Overlay 网络下的广播实现问题,获得秒级高可用切换能力,并能够很好的支持物理云。

下面,本文将对 UCloud 秒级切换的内网高可用服务进行详细介绍。

基于内网 VIP 的高可用服务

1、高可用的理念和要点

从业务角度看,当然要尽可能避免应用出现故障。但要完全不出故障是不可能的。

那如何解决这个问题呢?答案就是相信任何单一节点都不可靠,要为每个节点增加备份。当任一节点发生故障时,业务自动切换至正常节点,且整个切换过程用户均无感知,这就是高可用的基本理念。而实现高可用的两个要点是备份节点和自动故障转移。

技术图片

图:一旦 A 发生故障,便会迅速切换至 B

2、传统网络的高可用方案

在传统网络中,Keepalived + 虚拟 IP 是一个经典的高可用解决方案。

Keepalived 是基于 VRRP 协议的一款高可用软件,有一台主服务节点和多台备份节点,并部署相同的服务。主节点对外使用一个虚拟 IP 提供服务,当主节点出现故障时,Keepalived 发起基于 VRRP 的协商,选择备节点升级为主节点,虚拟 IP 地址会自动漂移至该节点,同时利用 GARP 宣告虚拟 IP 的位置信息更新,从而保证服务正常。

3、云计算 Overlay 网络下的高可用

云计算下的网络架构发生了巨大变化,传统的网络架构已经更新为 Overlay 网络,并出现了各类复杂的异构网络。那么在新的网络环境下,该如何解决高可用这个问题呢?

首先我们看一下云计算网络的基本原理:

技术图片

图:云计算网络的实现

如上图,云资源都桥接在 OVS 的网桥上,同时业务网卡也桥接在 OVS 的网桥上,Controller 为 UCloud 基于开源框架 Ryu 自研实现。Controller 通过与后台 Manager 的交互,拉取 ACL、路由表、VPC 联通、隔离等各类信息,并通过 OVS Message 将 Flow 固化在 OVS 的网桥上,达到 Flow 管理的目的,实现 ACL 的联通与阻断、三层转发的功能,进而完成 VPC 联通及租户隔离的能力。上层的实际业务报文,通过 GRE 封装,对下层网络保证透明。

鉴于用户在云计算网络中实现高可用的复杂性,UCloud 设计了内网 VIP 产品,为云平台上的云主机、物理云主机提供服务。作为用户自定义高可用服务的可漂移内网入口,从发现故障到自动完成故障切换,无需额外的 API 调用和机器内部配置,即可完成秒级切换。

技术图片

图:内网 VIP 控制台操作界面

内网 VIP 如何实现故障转移的秒级切换?

内网 VIP 的故障切换时长通常与以下两个步骤相关:

1、Master 发生故障后,备服务器需要选举出新的 Master;

2、需要在广播域内告知其他节点,该 IP 的位置发生了变化。

如上文所述,在 Overlay 网络中,上层业务报文的 ARP 协议解析、IP 寻址、单播、多播、广播都需要重新实现,会有不小难度。那么广播应当如何实现呢?

UCloud 基于广播的实现机制,演进出了如下的三个版本。

第一代:模拟广播

技术图片

图:模拟广播

如上图所示,一个广播报文直接复制 N 份,送到其他广播域中的节点,即可完成广播的行为。由于 OVS 支持报文的复制和传输,只需要在 Flow 中指定多个 Output 动作即可实现。Flow 的模式如下:

技术图片

图:模拟广播中 Flow 模式

这种实现确实可以满足需求,但是存在几个明显的缺点:

1、Flow 的更新。由于用户的广播域是变化的,一旦广播域发生变化,那么所有广播域中节点所在宿主机上的广播 Flow 全部需要推送更新。因此如果用户的广播域比较大,这种更新非常消耗性能。

2.、Flow 的长度数量有限制。OVS 对 Flow 的长度有要求:单条 Flow 的长度不能超过 64K bit,而广播域增加的时候,Flow 的长度一定随之增长。如果客户的子网比较大,导致超过了 Flow 的长度限制,那么就无法再进行更新,出现广播行为异常,进而影响高可用实现。

3、异构网络的广播需要单独实现。比如物理云主机底层不是基于 OVS 的架构,那么就必须重现一遍,开发和维护成本很高。

为解决上述问题,UCloud 开发出了第二代广播解决方案 —— 广播集群:

第二代:广播集群

技术图片

图:广播集群

如上图,所有的广播流量通过 Flow 指向自研的广播集群。广播集群从业务数据库中拉取广播的信息,对报文进行复制和分发。广播集群是 UCloud 基于 DPDK 自研的高可用集群,可以高性能地实现广播逻辑。

采用广播集群,我们很好的解决了第一代广播逻辑中存在的问题:

1、广播域的变化问题。广播域变化只需要通知广播集群即可,无需全网告知。

2、广播域的大小问题。广播集群通过 DPDK 来进行报文的复制和转发,理论上广播域无上限。

3、各种网络的适配问题。各类网络只需要将广播报文送到广播集群即可,无需进行额外的逻辑开发,很好的适配了各种网络场景。

随后,在第二代的基础上,UCloud 又提供了第三代的广播解决方案:

第三代:广播集群 + GARP 嗅探

技术图片

图:基于 GARP 嗅探的广播集群

在第二代广播集群已经可以很好的实现高可用服务的情况下,UCloud 为什么还要开发出第三代呢?

从前文我们可以知道,在 VIP 切换的过程中,GARP 将利用广播告知整个广播域,进而 VIP 发生漂移。但是广播域之外的服务器是没有能力获知相关信息的。这样就会出现下列问题:VIP 的切换会导致跨三层的访问失效。

而跨三层的访问则要求后台数据库必须通过某种方式获知 VIP 位置的变化。在内网 VIP 的切换过程中,GARP 报文会通知广播域内的节点 VIP 的位置信息变化,而广播集群可以获取到所有的广播流量。因此,广播集群利用 ARP_SPA=ARP_TPA 的特征过滤得到 GARP 流量,将相应的位置信息上报到后台,并更新 Flow 信息,从而保证三层的访问正常。

在第三代架构下,广播集群对公有云、物理云等多种异构网络均进行了支持,满足不同云计算高可用应用场景的需求。

应用实例解析

1、电商支付系统高可用实践

某电商在频繁的日常消费与各类促销活动中对支付系统可用性提出了很高的要求。消费者对支付系统的可用性是非常敏感的,一旦出现任何一点小小的故障,诸如 “付款失败、重新支付、支付超时” 等都会带来不好的使用体验,严重时甚至可能导致用户流失。

在不考虑外部依赖系统突发故障的前提下,如网络问题、第三方支付和银行的大面积不可用等情况,该电商希望通过提高自身支付系统的高可靠服务能力来保证消费者的可用性体验。

为了实现高可用,UCloud 基于 Keepalived + 内网 VIP 产品为该电商线上支付系统快速构建了高可靠服务,从而避免自身单点故障,大大提高系统的可用性。

技术图片

图:高可用服务构建实例

如上图,VIP 绑定在 UPHost(物理云主机)作为主节点存在,当 VIP 绑定的 Master 节点发生故障的时,便会发生 VIP 漂移。物理云网关收到 GARP 报文,并将 GARP 报文送至广播集群。广播集群分析 GARP 报文后,会将位置上报到后端,并更新物理云网关配置和公有云平台的 Flow。随后,广播集群复制 GARP 报文,并发送到广播域内的所有 UHost 和 UPHost。二层访问的信息和三层访问的信息都会在秒级内得到更新,保证业务的高可用。

2、UCloud 云数据 UDB 产品高可用技术实现

在 UCloud 云数据 UDB 产品的高可用技术实现中,也同样应用了内网 VIP 技术。如下图,UDB 产品采用双主架构,并通过 Semi-Sync 实现数据同步,由 UDB 可用性管理模块实时监控底层节点可用性,一旦监测到 Master DB 不可用,便会自动触发容灾切换机制,内网 VIP 无状态漂移至 Standby DB,保证用户 UDB 数据库服务的稳定可靠。

技术图片

图:基于内网 VIP 的 UCloud 高可用 DB 技术实现

在 UDB 高可用实现的过程中,由于采用单一内网 VIP 接入,因此可以完成应用层的无缝切换,整个过程中无需用户进行任何人工干预和配置修改。依托内网 VIP,UDB 产品为用户提供了高可用的数据库服务,目前该产品已经服务于上万家企业并提供了数万份数据库实例。

结语

高可用是一个复杂的命题,除了应用内网 VIP 产品规避可能出现的单点故障外,还需要在服务维护方面做到严格规范操作,包括事前做好服务分割,事后做好服务监控等。

但仅止于此吗?墨菲定律告诉我们:凡是可能出错的事有很大几率会出错。每日三省吾身:业务架构是否足够稳定?异常处理是否足够完备?灾备方案是否足够充分?并据此不断优化业务系统,祝愿每个运维工程师都可以睡个好觉!

以上是关于三代终端容器 KUN 的首次大考架构演进的主要内容,如果未能解决你的问题,请参考以下文章

秒级容灾,UCloud 内网高可用服务之三代架构演进

华为正式发布鸿蒙OS操作系统,分布式架构首次用于终端

淘宝,一个牛逼的高并发分布式架构演进之路!

大型分布式Web系统的架构演进

[4G&5G专题-83]:架构 - 移动通信网2G/3G/4G/5G/6G网络架构的演进历程

唯品会RPC服务框架与容器化演进(转)