【ArchSummit架构师峰会】探讨数据与人工智能相互驱动的关系>>> 了解详情
写点什么

Flutter Worker —— 闲鱼这样实现“逻辑跨平台”

  • 2021-03-18
  • 本文字数:3191 字

    阅读完需:约 10 分钟

Flutter Worker —— 闲鱼这样实现“逻辑跨平台”

闲鱼社区主要页面采用 Native 实现,部分使用 Flutter 和 Weex 承接。帖子、话题等固定数据结构的处理,点赞、评论等用户交互和状态同步,这些数据逻辑大部分是重复的,而且在多技术栈实现性价极低。由此我们想,能否在端上实现这样的一套工具,解放劳动力的同时,摆脱对服务端 BFF 层的依赖,保证研发效能。


抽象地看,实际上我们需要的正是一个逻辑跨平台工具。逻辑跨平台概念由来已久,也有一些很优秀的方案可以参考:

  • C++语言在 Objective-C/Java 等 Native 语言都有成熟接口可以调用,这使得 C++有天然的跨平台优势。同时不可否认的,C++入门门槛会比较高,导致后期维护成本大。

  • KMM 是 JetBrains 推出的用于跨平台移动开发 SDK,提供了一个语言级别的逻辑跨平台解决方案,可以将直接代码编译为与目标平台完全相同的格式。

结合团队内现有的一些技术基建,最终我们使用 Dart 完成了这一设计,在不同平台保证数据和逻辑处理的一致性,节约人力资源的同时保证用户体验。取名 Flutter Worker。

整体架构设计

在进行整体的设计之前,首先限定 worker 的业务场景:目标是提供一个多端可复用的逻辑处理中心,端上发起数据请求,所有的逻辑处理在 FlutterWorker 收口,执行完成返回回调给端上。设想中,在 worker 写 Handler 只需要关注逻辑处理,对于数据的传入和在端上的接收,开发者只需要指定类型,worker 会自动把数据转化成该类型。


由此,在整体的架构设计中,我们主要考虑以下几个方面:

  • FlutterWorker 需要一个稳定的运行环境,由于涉及到数据处理等可能会比较耗时的操作,需要保证不影响 UI 界面的绘制。

  • 处理后的数据要供给多端使用,数据结构必须对齐。

  • 提供足够的切面,方便接入方拓展。

  • 为了保证运行时稳定可靠,需要添加监控及时发现问题,并且在上线前时,对性能进行测试评估。


整体的架构图如下:


null


  • 运行容器层:容器是 worker 运行的基础,在保证性能的前提下,要尽可能的利用闲鱼现有的技术基建。

  • 状态管理层:worker 在这里完成数据的存储和状态的同步。端上存储状态数据,通过订阅状态消息来接收数据的变动。考虑到状态管理层在目前没有业务的强需求,这部分仅停留在 Demo 阶段还未落地,后面不再进行阐述。

  • 数据处理层:包含了 worker 所有的中间层数据处理部分,主要包括 Model 对象同步、数据转换和数据类型同步。基础数据类型在 Dart 语言中天然支持,在 iOS 端 Androiddr 端都有对应的类型,因此,worker 工作主要在后两者。

  • 监控层:worker 在线上运行,需要有监控来保障,及时发现问题及时响应。


下面对各个模块进行详细的介绍。

运行容器层

FlutterWorker 的运行环境强依赖 FlutterEngine 和 Isolate,从这个角度来考虑,对以下三种方案做了梳理和对比。


值得一提的是,随着 Flutter2.0 推出,我们在更新日志中注意到有一项对多开 Flutter Engine 实例内存消耗的优化。据官方文档称,额外 Flutter 引擎的静态内存占用量降低了约 99%,使每个实例的占用量大约为 180KB。结合源码来看,这里是新提供了 FlutterEngineGroup 类来创建 Flutter Engine。


null


相较于原来的 API,FlutterEngineGroup 生成的 FlutterEngine 具有常用共享资源(例如 GPU 上下文、字体度量和隔离线程的快照)的性能优势,从而加快首次渲染的速度、降低延迟并降低内存占用。


同时 EngineGroup 本身和其生成的 FlutterEngine 不需要持续保活,只要有 1 个可用的 FlutterEngine,就可以随时在各个 FlutterEngine 之间共享资源。EngineGroup 销毁后,已生成的 FlutterEngine 也不受影响,只是无法继续在现有共享的基础上创建新引擎。


虽然现在 FlutterEngineGroup 还不是一个稳定 API,但是这为 FlutterWorker 提供了另一种可能。综合考虑,目前实现选择了方案 3 来实现。

数据处理层

从用户调用开始,worker 的数据流图如下图所示:

null

数据在三端的流通,是通过调用 NatiaveWorker,执行到对应的 WorkerHandler,处理完成后再以异步的方式回调到 Native 方法。中间主要涉及 Model 对象同步和数据转换过程,worker 对这里分别实现了处理库。

Model 对象同步

worker 首先要实现的是,是 OringinDataModel ==> TargetDataModel。TargetDataModel 的定义在 iOS/Android/Flutter 三端的表现形式要保持一致,直接用代码生成是最好的选择。这里参考一些硬件协议,指定 IDL 格式来生成三端 Model 并导入工程。封装的 dartGen 库可以解析这些 yaml 节点,生成我们需要的胖 Model。


null


方便开发者使用,dartGen 打包成了 cli 工具。模仿 GsonFormat 插件,json 数据在 IDE 中可以方便转成对应的 dartGen 可以解析的 yaml 协议。对于其他生成 Model 的需求,可以以很小的代价修改模板,定制化高。

数据转换

通过 Flutter 的 MethodChannel 向 Native 传输数据,需要经过一层 messager 编码,而且编码数据为基础类型。所以在 BinaryMessager 的基础上,封装了 WorkerBinaryMessenger 方便做定制化处理。

iOS 端和 Android 端有成熟的 model 转换库(YYModel 和 FastJson)。在 Dart 这里,基于 fish_serializable 同样做了一些定制处理,在生成的 Model 里提供 toJson 和 fromJson 方法等,保证各种类型数据,包括 Map 和 List 等内包泛型类,能够很方便地进行转换。

监控方案设计

每个监控方案都有其业务场景的局限性,在目前阶段,主要考虑逻辑一致性。worker 内单次的逻辑闭环类似 tcp 握手和挥手的过程,应用内的数据流转类似消息队列,其传递过程如图:


null


由此我们确定 workerMonitor 运行的流程图如下:


null

性能监控

在该模式下的主流监控方案,会根据时间切片来观察 发起方/接收方的队列数据情况,时间切片有两种方式,第一种是设置定时器,第二种是在每次有数据调用时处理。



另外上报的方式也分为实时上报和聚合上报。考虑到目前 worker 的使用场景有闲时和忙时的明显区分,并且端上的长驻的频繁的定时上报任务对 ui 绘制会有一定影响,最终采用每次数据调用时统计队列内数据,同时在每次调用后增加超时定时器,如果有下次调用则取消超时定时器。

指标

在线上监控指标建设方面,参考 rabbitmq 监控,先定义初期需要观测的指标。初期核心关注消息丢失的情况和消息时延长的情况。由此我们确定指标如下:

null


Exception 监控

参考 ui 引擎对 crash 的监控,会在入口函数处统一接受异常信息以及异常堆栈,然后统一上报处理。这里在闲鱼公众号 Flutter 高可用相关文章中有详细介绍。

可行性验证

最后实现完成,调用代码及对应的 Handler 示例如下:

•iOS 端:


null

•Android 端:

null

•Handler:

null

为了测试我们的方案能否达到上线标准,在会玩首页场景下做暴力测试来验证。对比正常 Native 代码和 worker 处理数据,测试多次并发访问/有序访问条件下 CPU、内存以及时延等表现。


通过多次对比试验,FlutterWorker 方案在常见和高压的请求场景下短期内存和 cpu 水位增量少于 30M,长期内存和 cpu 水位增量小于 5M,并且时延低于原有方案的 5%。


三端接入后,数据处理只需要投入一个人力就可供多端使用,大量减少了重复工作,提升了研发效能。

总结和展望

当前跨平台是移动开发的趋势之一,各个公司、团队各有建树,百家争鸣。究其根本目的都是想提升研发效率,降低维护成本。各个方案都各有自己的独特优势,应该理性分析团队和业务的现状,选择适合的方案。


Flutter Worker 从逻辑跨平台的视角切入,取得了一些不错的效果。不过我们目前只完成了小部分的工作,仍有很多未完善的地方,在未来主要会从下面几个方面继续深入研究:

  • MethodChannel 优化。数据通道的通信强依赖 MethodChannel,从目前测试结果来其性能表现可以 cover 目前的业务场景,但长远来看,通道会成为 worker 性能瓶颈。从 dart_native 库得到启发,以类型映射指针的方式来替代原生的通道是一条可行的路。

  • 单元测试。逻辑处理函数有明确的输入和输出,写单测的效率很高。而且快速迭代的产品,很多是在原有的逻辑基础上添加新的逻辑,写单测的性价比较高。

  • 前端容器支持。先行版本只支持了 iOS、Android 和 Flutter,对于 Weex 和 H5 前端页面并没有很好的支持,未来期望能够提供优雅的方式接入前端容器。


本文转载自:闲鱼技术(ID:XYtech_Alibaba)

原文链接:Flutter Worker —— 闲鱼这样实现“逻辑跨平台”

2021-03-18 08:001781

评论

发布
暂无评论
发现更多内容

linux shell 命令行移动光标快捷键之跳到行首尾

WindFlying

蚁剑的分析和利用

网络安全学海

网络安全 信息安全 渗透测试 WEB安全 安全漏洞

太顶了!华为高工用一份423页的网络协议笔记把计算机网络讲清了

热爱java的分享家

Java 架构 面试 编程语言 网络协议

🎅Less快速学习(下)🎅

空城机

CSS 大前端 less 11月日更

Can't Connect to MySQL Server on IP Address (10061) 错误的解决方案

蒋川

MySQL 数据库 MySQL 运维 MySQL 数据库

Go 语言学习查缺补漏ing Day1

Regan Yue

Go 语言 11月日更

运维体系建设思考-稳定性篇

ning

运维 云原生 监控 稳定性

Python代码阅读(第60篇):列表是否包括指定的元素

Felix

Python 编程 列表 阅读代码 Python初学者

Lenovo x StarRocks:简化数据处理链路,极大提升BI分析效率

StarRocks

数据库 大数据 数据分析 StarRocks

中国邮政邮科院 X StarRocks:统一OLAP平台,大幅降低运维成本

StarRocks

数据库 大数据 数据分析 StarRocks

跨越速运 x StarRocks:统一查询引擎,强悍性能带来极速体验

StarRocks

数据库 大数据 数据分析 StarRocks

起飞!Alibaba全新出品JDK源码学习指南(终极版)限时开源

热爱java的分享家

Java 架构 面试 程序人生 编程语言

我为什么坚持在公司开分享会?

boshi

团队管理 知识管理

技术分享 | 让实时协同的框架绘图变得丝滑起来

ShowMeBug

架构 绘图 实时消息

NLP进阶,使用TextRNN和TextRNN_ATT实现文本分类

AI浩

MatrixDB 4.3 新特性:从“持续聚集”说起

YMatrix 超融合数据库

时序数据库 分布式时序数据库 MatrixDB

自定义View:如何手动实现ViewGroup的拖拽

Changing Lin

11月日更

区块链技术如何在涉诉信访中显身手

CECBC

文本检测实战:使用OpenCV实现文本检测(EAST 文本检测器)

AI浩

如何巧妙使用Camtasia制作PPT讲解视频?

淋雨

Camtasia

金链银链不如区块链 如何利用区块链技术探索“太空世界”?

CECBC

【Three.js】随着元宇宙开启WEB3D之路

devpoint

JavaScript WebGL 3D three.js 11月日更

前端遇到的那些技术难点

CRMEB

阿里云发布云原生加速器,携手生态企业拥抱数字时代

阿里巴巴中间件

云计算 阿里云 云原生 中间件 数字化

【得物技术】基于自注意机制的图像识别算法

得物技术

算法 图像识别 识别 图像 算法实践

到底什么才是真正的区块链游戏

CECBC

clickhouse sql之Array函数

WindFlying

惊为天人!Alibaba新产SpringBoot深度历险(嵩山版)开源

热爱java的分享家

Java 架构 面试 程序人生 编程语言

StarRocks在格洛博电商系统的应用实践

StarRocks

数据库 大数据 数据分析 StarRocks

猿辅导 x StarRocks:构建统一OLAP平台,全面升级数据分析能力

StarRocks

数据库 数据分析 StarRocks

阿里云发布云原生加速器,携手生态企业拥抱数字时代

阿里巴巴云原生

云计算 阿里云 云原生 生态企业 创投

Flutter Worker —— 闲鱼这样实现“逻辑跨平台”_架构_闲鱼技术_InfoQ精选文章