本文由阿里闲鱼技术团队祈晴分享,本次有修订和改动,感谢做者的技术分享。html
本文总结了阿里闲鱼技术团队使用Flutter在对闲鱼IM进行移动端跨端改造过程当中的技术实践等,文中对比了传统Native与如今大热的Flutter跨端方案在一些主要技术实现上的差别,以及针对Flutter技术特色的具体技术实现,值得一样准备使用Flutter开发IM的技术同行们借鉴和参考。react
学习交流:git
- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》github
- 开源IM框架源码:github.com/JackJiang20…数据库
闲鱼IM的移动端框架构建于2016至2017年间,期间通过屡次迭代升级致使历史包袱累积多,后面又经历IM界面的Flutter化,从而形成了客户端架构越发复杂。redux
从开发层面总结闲鱼IM移动端当前架构主要存在以下几个问题:缓存
从产品层面总结闲鱼IM移动端当前架构的主要问题以下:安全
为解决当前IM的技术痛点,闲鱼今年特起关于IM架构升级项目,重在解决客户端中Andriod和iOS双端一致性的痛点,初步设想方案就是实现跨端统一的Android/iOS逻辑架构。markdown
在当前行业内跨端方案可初步归类以下图架构:weex
在GUI层面的跨端方案有Weex、ReactNative、H五、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共享,则内存模型就自然支持共享读取。
原理图以下:
**以下图所示:**是一个老架构方案,其核心问题主要集中于Native逻辑抽象差,其中逻辑层面还设计到多线程并发使得问题倍增,Android/iOS/Flutter交互繁杂,开发维护成本高,核心层耦合较为严重,无插拔式概念.
考虑到历史架构的问题,演进以下新架构设计:
如上图所示,架构从上至下依次为:
数据源层来源于推送或网络请求,其封装于Native层,经过Flutter插件将消息协议数据上抛到Flutter侧的核心逻辑层,处理完成后变成Flutter DB的Enitity实体,实体中挂载一些消息协议实体。
核心逻辑层将繁杂数据扁平化打包挂载到分发层中的会话内存模型数据或消息内存模型数据,最后经过观察者模式的订阅分发到业务逻辑中。
Flutter IM重点集中改造逻辑层和分发层,将IM核心逻辑和业务层面数据模型进行封装隔离,核心逻辑层和数据库交互后将数据封装到分发层的moduleData中,经过订阅方式分发到业务层数据模型中。
此外在IM模型中DB也是重点依赖的,我的对DB数据库管理进行全面封装解,实现一种轻量级,性能佳的Flutter DB管理框架。
Flutter IM架构的DB存储依赖数据库插件,目前主流插件是Sqflite。
其存储模型以下:
依据上图Sqflite插件的DB存储模型会有2个等待队列:
其Android实现机制是HandlerThread,所以Query/Save读写在会同一线程队列中,致使响应速度慢,容易形成DB SQL堆积,此外缺失缓存模型。
因而我的定制以下改进方案:
Flutter侧经过表的主键设计查询时候会优先从Entity Cache层去获取,若缓存不存在,则经过Sqflite插件查询。
同时改造Sqflite插件成支持sync/Async同步异步两种方式操做,对应到Native侧也会有同步线程队列和异步线程队列,保证数据吞吐率。可是这里建议查询使用异步,存储使用同步更稳妥,主要怕出现多个相同的数据元model同一时间进入异步线程池中,存储前后顺序没法有效的保证。
IM架构重度依赖DB数据库,而当前业界尚未一个完备的数据库ORM管理方案,参考了Android的OrmLite/GreenDao,我的自行设计一套Flutter ORM数据库管理方案。
其核心思想以下:
因为Flutter不支持反射,所以没法直接像Android的开源数据库方式操做,但可经过APT方式,将Entity和Orm Entity绑定于一身,操做OrmEntity即操做Entity,整个代码风格设计也和OrmLite极其类似。
参考代码以下:
基于Flutter的IM移动端架构在内存数据模型主要划分为会话和消息两个颗粒度:
依据上一章节,PSessionMessageNotice设计了一个OrmEnitity Cache,考虑到IM中会话数是有限的,所以PSessionMessageNotice都是直接缓存到Cache中。
这种作法的好处是各地去拿会话数据元时候都是缓存中同一个对象,容易保证屡次重复读写的数据一致性。而PSessionMessageNotice考虑到其数量能够无限多的特殊性,所以这里将其挂载到MessageContainer的内存管理中,在退出会话的时机会校验容器中PMessage集合的数量,适当缩容能够减小内存开销。
模型以下图所示:
基于Flutter的IM移动端架构状态管理方案比较简单,对数据源Session/Message维度使用观察者模式的订阅分发方式实现,架构相似于EventBus模式,页面级的状态管理不管使用fish-redux、scopeModel或者provider几乎影响面不大,核心仍是需保留一种插拔式抽象更重要。
架构以下图:
当前现状的消息同步模型:
如上图所示是,模型中存在ACCS Thread/Main Thread/Region Thread等多线程并发场景,致使易出现多线程高并发的问题。
native的推送和网络请求同步的隔离方案经过Lock的锁机制,而且经过队列降频等方式处理,流程繁琐且易出错。总体经过Region Version Gap去判断是否有域空洞,进而执行域同步补充数据。
改进的同步模型以下:
如上图所示,在Flutter侧自然没多线程场景,经过一种标记位的转化同步异步实现相似Handler消息队列,架构清晰简约了不少,避免锁带来的开销以及同步问题。
1)针对架构层面:
在基于Flutter的IM架构中,重点将双端逻辑差别性统一成同一份Dart代码,彻底磨平Android/iOS的代码差别性带来的问题。
带来的好处很明显:
2)针对线上舆情:
3)性能数据对比:
当IM架构的逻辑层和UI层都切换成Flutter后,和原先架构模式初步对比,总体内存水位持平。
其中:
JS跨端不安全,C++跨端成本有点高,Flutter会是一个较好选择。彼时闲鱼FlutterIM架构升级根本目的历来不是因Flutter而Flutter,是因为历史包袱的繁重,代码层面的维护成本高,新业务的扩展性差,人力配比不协调以及疑难杂症的舆情持续反馈等等因素形成咱们不得不去探索新方案。
通过闲鱼IM超复杂业务场景验证Flutter模式的逻辑跨端可行性,闲鱼在Flutter路上会一直保持前沿探索,最后能反馈到生态圈。
总结一句话,探索过程在于你敢于迈出第一步,后面才会不断惊喜发现。(原文连接:点此进入,本次有修订和改动)
本文已同步发布于:www.52im.net/thread-3615…