本文由阿里闲鱼技术团队祈晴分享,原文参考微信公众号淘系技术,感激作者的技术分享。

OpenIMgithub开源地址:

https://github.com/OpenIMSDK/...

OpenIM官网 :https://www.rentsoft.cn

OpenIM官方论坛:https://forum.rentsoft.cn/

现状

闲鱼IM框架构建于2016-2017年,期间屡次迭代降级导致历史包袱累积多,后经IM界面Flutter化,造成架构更简单。

开发层面总结闲鱼以后架构次要存在如下几个问题:

  1. 研发效率较低:以后架构开发需要波及到Android/iOS双端的逻辑代码以及Flutter的UI界面代码,定位问题往往只能从Flutter UI表象追究到Native逻辑破绽;
  2. 架构档次较差:架构设计上分层不清晰,业务逻辑夹杂在外围的逻辑层以致代码变更危险大;
  3. 性能测试略差:外围数据源存储Native内存,需经Flutter Plugin将数据源序列化上抛Flutter侧,在大批量数据源状况下性能体现较差;

从舆情层面总结闲鱼IM以后架构的次要问题如下:

  1. 定位问题艰难:线上舆情反馈千奇百怪,测试始终无奈复现相干场景,因而很多时候只能靠景象猜想实质;
  2. 疑难杂症较多:架构不稳定性造成呈现的问题重复呈现,以后疑难杂症次要包含未读红点计数,iPhone5C低端机器架构,以及多媒体发送等多个问题;
  3. 问题差异性大:Android和iOS两端逻辑代码差别大,包含现存埋点逻辑都不尽相同,因而排查问题本源时候双端都会有不同问题根因,解决问题计划也不雷同;

业界跨端计划

为解决以后IM痛点,闲鱼往年特起对于IM架构降级我的项目,重在解决客户端中双端一致性痛点,初步构想计划就是实现跨端对立的Android/iOS逻辑架构;

在以后行业内跨端计划可初步归类如下图架构,在GUI层面的跨端计划有Weex,ReactNative,H5,Uni-APP等,其内存模型大多须要通过桥接到Native模式存储;

在逻辑层面的跨端计划大抵有C/C++等与虚拟机无关语言实现跨端,当然汇编语言也可行;

此外有两个独立于上述体系之外的架构就是Flutter和KMM(谷歌基于Kotlin实现相似Flutter架构),其中Flutter运行特定DartVM,将内存数据挂载其本身的isolate中;

思考闲鱼是Flutter的前沿探索者,计划上优先应用Flutter;

然而Flutter的isolate更像一个过程的概念(底层实现非应用过程模式),相比Android,同一过程场景中,Android的Dalvik虚拟机多个线程运行共享一个内存Heap,而DartVM的Isolate运行隔离各自的Heap,因此isolate之间通信形式比拟繁琐(需通过序列化反序列化过程);

整个模型如下图所示:

若按官网混合架构实现Flutter利用,开启多个FlutterAcitivty/FlutterController,底层会生成多个Engine,对应会存在多个isolate,而isolate通信相似于过程通信(相似socket或AIDL),这里借鉴闲鱼FlutterBoost的设计理念,FlutterIM架构将多个页面的Engine共享,则内存模型就人造反对共享读取,

原理图如下:

Flutter IM 架构设计

新老架构比照

如下图是一个老架构计划,其外围问题次要集中于Native逻辑形象差,其中逻辑层面还设计到多线程并发使得问题倍增,Android/iOS/Flutter交互繁冗,开发保护老本高,核心层耦合较为重大,无插拔式概念;

思考到历史架构的问题,演进如下新架构设计:

架构从上至下顺次为业务层,散发层,逻辑层以及数据源层,数据源层来源于推送或网络申请,其封装于Native层,通过Flutter插件将音讯协定数据上抛到Flutter侧的外围逻辑层,解决实现后变成Flutter DB的Enitity实体,实体中挂载一些音讯协定实体;

外围逻辑层将繁冗数据扁平化打包挂载到散发层中的会话内存模型数据或音讯内存模型数据,最初通过观察者模式的订阅散发到业务逻辑中;

Flutter IM重点集中革新逻辑层和散发层,将IM外围逻辑和业务层面数据模型进行封装隔离,外围逻辑层和数据库交互后将数据封装到散发层的moduleData中,通过订阅形式散发到业务层数据模型中;

此外在IM模型中DB也是重点依赖的,集体对DB数据库治理进行全面封装解,实现一种轻量级,性能佳的Flutter DB治理框架;

DB存储模型

Flutter IM架构的DB存储依赖数据库插件,目前支流插件是Sqflite,其存储模型如下:

根据上图Sqflite插件的DB存储模型会有2个期待队列,一个是Flutter层同步执行队列,一个是Native层的线程执行队列,其Android实现机制是HandlerThread,因而Query/Save读写在会同一线程队列中,导致响应速度慢,容易造成DB SQL沉积,此外缺失缓存模型,于是集体定制如下改良计划:

Flutter侧通过表的主键设计查问时候会优先从Entity Cache层去获取,若缓存不存在,则通过Sqflite插件查问,同时革新Sqflite插件成反对sync/Async同步异步两种形式操作,对应到Native侧也会有同步线程队列和异步线程队列,保证数据吞吐率;

然而这里倡议查问应用异步,存储应用同步更稳当,次要怕呈现多个雷同的数据元model同一时间进入异步线程池中,存储先后顺序无奈无效的保障;

ORM数据库计划

IM架构重度依赖DB数据库,而以后业界还没有一个齐备的数据库ORM治理计划,参考了Android的OrmLite/GreenDao,集体自行设计一套Flutter ORM数据库治理计划,其核心思想如下:

因为Flutter不反对反射,因而无奈间接像Android的开源数据库形式操作,但可通过APT形式,将Entity和Orm Entity绑定于一身,操作OrmEntity即操作Entity,整个代码格调设计也和OrmLite极其类似,参考代码如下:

IM内存数据模型

FlutterIM架构在内存数据模型次要划分为会话和音讯两个颗粒度,会话内存数据模型交托于SessionModuleData,音讯内存数据模型交托于MessageModuleData;

会话内存数据有一个根节点RootNotice,而后其挂载PSessionMessageNotice(这里PSessionMessageNotice是ORM映射的会话DB表模型)子节点汇合;

音讯内存数据会有一个MessageConatiner容器治理,其外部挂载此会话中的PMessage(PMessage是ORM映射的音讯DB表模型)音讯汇合。

根据上一章节,PSessionMessageNotice设计了一个OrmEnitity Cache,思考到IM中会话数是无限的,因而PSessionMessageNotice都是间接缓存到Cache中,这种做法的益处是各地去拿会话数据元时候都是缓存中同一个对象,容易保障多次重复读写的数据一致性;

而PSessionMessageNotice思考到其数量能够有限多的特殊性,因而这里将其挂载到MessageContainer的内存治理中,在退出会话的时机会校验容器中PMessage汇合的数量,适当缩容能够缩小内存开销,模型如下图所示:

状态治理计划

Flutter IM状态治理计划比较简单,对数据源Session/Message维度应用观察者模式的订阅散发形式实现,架构相似于EventBus模式,页面级的状态治理无论应用fish-redux,scopeModel或者provider简直影响面不大,外围还是需保留一种插拔式形象更重要;架构如下图:

IM同步模型计划

如下是以后现状的音讯同步模型,模型中存在ACCS Thread/Main Thread/Region Thread等多线程并发场景,导致易呈现多线程高并发的问题;

native的推送和网络申请同步的隔离计划通过Lock的锁机制,并且通过队列降频等形式解决,流程繁琐且易出错。

整体通过Region Version Gap去判断是否有域空洞,进而执行域同步补充数据。

改良的同步模型如下,在Flutter侧人造没多线程场景,通过一种标记位的转化同步异步实现相似Handler音讯队列,架构清晰简洁了很多,防止锁带来的开销以及同步问题。

停顿以及性能比照

▐ 针对架构层面

在FlutterIM架构中,重点将双端逻辑差异性对立成同一份Dart代码,齐全磨平Android/iOS的代码差异性带来的问题,升高开发保护,测试回归,视觉验收的一半老本,极大进步研发效率;

架构上进行重构分层,实现一种解耦合,插拔式的IM架构;同时Native到Flutter侧的大量数据上抛序列化过程革新成Flutter援用传递,解决极限测试场景下的私聊卡顿问题;

▐ 针对线上舆情

补齐UT和TLog的团体日志形式做到可追踪,可排查;另外针对于很多现存的疑难杂症重点集中专项解决,比方iphone5C的架构在Flutter侧统一规划,未读红点计数等问题也在架构模型降级中修复,此外多媒体音视频发送模块进行革新降级;

▐ 性能数据比照

当IM架构的逻辑层和UI层都切换成Flutter后,和原先架构模式初步比照,整体内存水位持平,其中私聊场景下小米9测试后果内存降落40M,功耗升高4mah,CPU升高1%;

极限测试场景下新架构内存数据相比于旧架构有一个较为显著的改观,次要因为两个界面都应用Flutter场景下,页面切换的开销升高很多;

瞻望

JS跨端不平安,C++跨端老本有点高,Flutter会是一个较好抉择;彼时闲鱼FlutterIM架构降级基本目标从来不是因Flutter而Flutter,是因为历史包袱的沉重,代码层面的保护老本高,新业务的扩展性差,人力配比不协调以及疑难杂症的舆情继续反馈等等因素造成咱们不得不去摸索新计划。

通过闲鱼IM超简单业务场景验证Flutter模式的逻辑跨端可行性,闲鱼在Flutter路上会始终放弃前沿摸索,最初能反馈到生态圈;总结一句话,摸索过程在于你敢于迈出第一步,前面才会一直惊喜发现。

更多原创技术文章:

开源OpenIM:高性能、可伸缩、易扩大的即时通讯架构
https://forum.rentsoft.cn/thr...

【OpenIM原创】简略轻松入门 一文解说WebRTC实现1对1音视频通信原理
https://forum.rentsoft.cn/thr...

【OpenIM原创】开源OpenIM:轻量、高效、实时、牢靠、低成本的音讯模型

https://forum.rentsoft.cn/thr...

OpenIM服务发现和负载平衡golang插件:gRPC接入etcdv3

https://forum.rentsoft.cn/thr...

【OpenIM原创】简略轻松入门 一文解说WebRTC实现1对1音视频通信原理

https://forum.rentsoft.cn/thr...

【OpenIM原创】C/C++调用golang函数,golang回调C/C++函数

https://forum.rentsoft.cn/thr...