首页 文章 精选 留言 我的

精选列表

搜索[模型开源],共10000篇文章
优秀的个人博客,低调大师

开源分布式工作流任务调度系统EasyScheduler使用详解

使用手册 登录 输入http://192.168.xx.xx:8888/view/login/index.html 网址,输入用户名:admin,密码:escheduler123 登录 登录之后每个页面的右上角都有用户的身份标识。点击下拉箭头包含用户信息和退出两个按钮 点击“用户信息”按钮,如下图: 点击”修改”按钮,修改用户信息 点击退出按钮则退出系统,返回登录页面 安全中心 只有管理员才有安全中心,安全中心的主要功能是给管理员提供管理普通用户的功能。 管理员可以有多个,管理员是功能上的管理,不参与具体的业务。也就是说管理员是不能执行具体任务的。 租户管理 租户是Linux上的用户,用于作业的提交。 创建、编辑租户 <img src="https://analysys.github.io/EasyScheduler/zh_CN/images/addtenant.png" width="60%" /> 租户编码:租户编码是Linux上的用户,唯一,不能重复 租户名称:租户的名称 队列:租户对应的YARN上的队列,在数据库 t_escheduler_queue 中设置 描述:租户的描述信息 用户管理 用户是EasyScheduler上的用户,用于EasyScheduler上的功能操作。 创建、编辑用户 用户名称:用户的名称,唯一,不能重复 租户:设置该用户所属的租户 邮箱:输入用户的邮箱,用来邮件发送和任务告警 手机:输入用户的手机号 注意:如果该用户切换了租户,则该用户所在租户下所有资源将复制到切换的新租户下 授权 管理员可以对普通用户进行非其创建的项目、资源、数据源和UDF函数进行授权。因为项目、资源、数据源和UDF函数授权方式都是一样的,所以以项目授权为例介绍。 1.点击指定人的授权按钮,如下图: 2.选中项目按钮,进行项目授权 项目列表:是该用户未授权的项目 已选项目:是该用户已授权的项目。 特别注意:对于用户自己创建的项目,该用户拥有所有的权限。则项目列表和已选项目列表中不会体现。 告警组管理 告警组是告警用户抽象出来的组,使用告警组来管理用户。 新建、编辑邮件组 组名称:输入组的名称 组类型:支持邮件/短信两种 备注:输入告警组的备注信息 管理用户 管理用户列表:是未添加到该组的用户列表 已选管理用户:是已添加到该组的用户列表 服务管理 服务管理是对EasyScheduler的Master、Worker的任务监控 Master Worker 资源中心 资源中心主要分为文件管理和UDF函数管理。 文件管理:主要是用户的程序,脚本和配置文件需要上传到HDFS进行统一管理UDF函数管理:对用户创建的UDF进行管理 文件管理 创建文件 文件格式支持以下几种类型:txt、log、sh、conf、cfg、py、java、sql、xml、hql 上传文件 文件名:输入文件的名称 描述:输入文件的描述信息 上传文件:点击上传按钮进行上传,将文件拖拽到上传区域,文件名会自动以上传的文件名称补全 文件查看 对可查看的文件类型,点击 文件名称 可以查看文件详情 下载文件 可以在 文件详情 中点击右上角下载按钮下载文件,或者在文件列表后的下载按钮下载文件 文件重命名 删除 文件列表,点击 删除 按钮,删除文件 UDF管理 资源管理 资源管理和文件管理功能类似,不同之处是资源管理是上传的UDF函数,文件管理上传的是用户程序,脚本及配置文件 函数管理 创建、编辑UDF函数 目前只支持HIVE的临时UDF函数 UDF函数名称:输入UDF函数时的名称 包名类名:输入UDF函数的全路径 参数:用来标注函数的输入参数 数据库名:预留字段,用于创建永久UDF函数 UDF资源:设置创建的UDF对应的资源文件 数据源中心 数据源中心支持MySQL、POSTGRESQL、HIVE及Spark数据源 创建、编辑MySQL数据源 数据源:选择MYSQL 数据源名称:输入数据源的名称 描述:输入数据源的描述 IP/主机名:输入连接MySQL的IP 端口:输入连接MySQL的端口 用户名:设置连接MySQL的用户名 密码:设置连接MySQL的密码 数据库名:输入连接MySQL的数据库名称 Jdbc连接参数:用于MySQL连接的参数设置,以JSON形式填写 创建、编辑POSTGRESQL数据源 数据源:选择POSTGRESQL 数据源名称:输入数据源的名称 描述:输入数据源的描述 IP/主机名:输入连接POSTGRESQL的IP 端口:输入连接POSTGRESQL的端口 用户名:设置连接POSTGRESQL的用户名 密码:设置连接POSTGRESQL的密码 数据库名:输入连接POSTGRESQL的数据库名称 Jdbc连接参数:用于POSTGRESQL连接的参数设置,以JSON形式填写 创建、编辑HIVE数据源 1.使用HiveServer2方式连接 <img src="https://analysys.github.io/EasyScheduler/zh_CN/images/hive_edit.png" width="60%" /> 数据源:选择HIVE 数据源名称:输入数据源的名称 描述:输入数据源的描述 IP/主机名:输入连接HIVE的IP 端口:输入连接HIVE的端口 用户名:设置连接HIVE的用户名 密码:设置连接HIVE的密码 数据库名:输入连接HIVE的数据库名称 Jdbc连接参数:用于HIVE连接的参数设置,以JSON形式填写 2.使用HiveServer2 HA Zookeeper方式连接 <img src="https://analysys.github.io/EasyScheduler/zh_CN/images/hive_edit2.png" width="60%" /> 数据源:选择HIVE 数据源名称:输入数据源的名称 描述:输入数据源的描述 IP/主机名:输入连接Zookeeper的集群 端口:输入连接Zookeeper的端口 用户名:设置连接HIVE的用户名 密码:设置连接HIVE的密码 数据库名:输入连接HIVE的数据库名称 Jdbc连接参数:用于Zookeeper连接的参数设置,以JSON形式填写 创建、编辑Spark数据源 数据源:选择Spark 数据源名称:输入数据源的名称 描述:输入数据源的描述 IP/主机名:输入连接Spark的IP 端口:输入连接Spark的端口 用户名:设置连接Spark的用户名 密码:设置连接Spark的密码 数据库名:输入连接Spark的数据库名称 Jdbc连接参数:用于Spark连接的参数设置,以JSON形式填写 首页 首页是对所有项目在指定时间范围内的任务状态、流程状态和流程定义的统计。 首页和项目首页的主要区别在于: 首页中的图表是没有链接的,项目首页中图表是有链接的 首页统计的是所有的项目,项目首页统计的是某一个项目 项目管理 项目是调度对用户流程定义DAG分组的一个抽象 创建、编辑项目 项目名称:输入项目的名称 描述:输入项目的描述 项目首页 点击项目列表中的项目名称,可以跳转到指定的项目首页,如下图: 项目首页其中包含四个部分,任务状态统计,流程状态统计、流程定义统计及统计的时间范围 任务状态统计:是指在指定时间范围内,统计任务实例中的待运行、失败、运行中、完成、成功的个数 流程状态统计:是指在指定时间范围内,统计流程实例中的待运行、失败、运行中、完成、成功的个数 流程定义统计:是统计该用户创建的流程定义及管理员授予该用户的流程定义 注意:可以点击图,或者数量跳转到相应的任务实例,流程实例和流程定义列表 工作流 工作流分为流程定义、流程实例和任务实例三个功能模块 流程定义:是可视化拖拽成的DAG的统称,它是静态的,没有状态 流程实例:对流程定义的每次实例化会生成一个流程实例,是动态的,是有状态的 任务实例:流程实例DAG中每个Task称为任务实例,是动态的,是有状态的 流程定义 创建工作流 左侧工具栏 => 是目前调度支持的任务类型,当前调度支持SHELL、子流程、存储过程、SQL、MR、Spark和Python七种任务类型 右上角图标 => 分别是拖动节点和选中项、选择线条连线、删除选中的线或节点、全屏和流程定义保持,其主要功能是DAG的绘制所用 创建 SHELL节点 拖动工具栏中的任务节点到画板中,双击任务节点,如下图: 节点名称:一个流程定义中的节点名称是唯一的 运行标志:标识这个节点是否能正常调度 描述信息:描述该节点的功能 失败重试次数:任务失败重新提交的次数,支持下拉和手填 失败重试间隔:任务失败重新提交任务的时间间隔,支持下拉和手填 脚本:用户开发的SHELL程序 资源:是指脚本中需要调用的资源文件列表 自定义参数:是SHELL局部的用户自定义参数,会替换脚本中以${变量}的内容 创建 子流程 节点 拖动工具栏中的任务节点到画板中,双击任务节点,如下图: 节点名称:一个流程定义中的节点名称是唯一的 运行标志:标识这个节点是否能正常调度 描述信息:描述该节点的功能 子节点:是选择子流程的流程定义,右上角进入该子节点可以跳转到所选子流程的流程定义 创建 存储过程 节点 拖动工具栏中的任务节点到画板中,双击任务节点,如下图: 节点名称:一个流程定义中的节点名称是唯一的 运行标志:标识这个节点是否能正常调度 描述信息:描述该节点的功能 失败重试次数:任务失败重新提交的次数,支持下拉和手填 失败重试间隔:任务失败重新提交任务的时间间隔,支持下拉和手填 数据源:存储过程的数据源类型支持MySQL和POSTGRESQL两种,选择对应的数据源 方法:是存储过程的方法名称 自定义参数:存储过程的自定义参数类型支持IN、OUT两种,数据类型支持VARCHAR、INTEGER、LONG、FLOAT、DOUBLE、DATE、TIME、TIMESTAMP、BOOLEAN九种数据类型 创建 SQL 节点 拖动工具栏中的任务节点到画板中,双击任务节点,如下图: 节点名称:一个流程定义中的节点名称是唯一的 运行标志:标识这个节点是否能正常调度 描述信息:描述该节点的功能 失败重试次数:任务失败重新提交的次数,支持下拉和手填 失败重试间隔:任务失败重新提交任务的时间间隔,支持下拉和手填 数据源:SQL数据源支持MySQL、POSTGRESQL、HIVE和Spark四中数据源类型,选择对应的数据源 sql类型:支持查询和非查询两种,查询是select类型的查询,是有结果集返回的,可以指定邮件通知为表格、附件或表格附件三种模板。非查询是没有结果集返回的,是针对update、delete、insert三种类型的操作 sql参数:输入参数格式为key1=value1;key2=value2… sql语句:SQL语句 UDF函数:对于HIVE类型的数据源,可以引用资源中心中创建的UDF函数,其他类型的数据源暂不支持UDF函数 自定义参数:SQL任务类型自定义参数类型和数据类型同存储过程任务类型一样。区别在于SQL任务类型自定义参数会替换sql语句中${变量},而存储过程是自定义参数顺序的给方法设置值 创建 MR 节点 拖动工具栏中的任务节点到画板中,双击任务节点,如下图: (1) JAVA程序 <img src="https://analysys.github.io/EasyScheduler/zh_CN/images/mr_java.png" width="60%" /> 节点名称:一个流程定义中的节点名称是唯一的 运行标志:标识这个节点是否能正常调度 描述信息:描述该节点的功能 失败重试次数:任务失败重新提交的次数,支持下拉和手填 失败重试间隔:任务失败重新提交任务的时间间隔,支持下拉和手填 主函数的class:是MR程序的入口Main Class的全路径 程序类型:选择JAVA语言 主jar包:是MR的jar包 命令行参数:是设置MR程序的输入参数,支持自定义参数变量的替换 其他参数:支持 –D、-files、-libjars、-archives格式 资源: 如果其他参数中引用了资源文件,需要在资源中选择指定 自定义参数:是MR局部的用户自定义参数,会替换脚本中以${变量}的内容 (2) Python程序 节点名称:一个流程定义中的节点名称是唯一的 运行标志:标识这个节点是否能正常调度 描述信息:描述该节点的功能 失败重试次数:任务失败重新提交的次数,支持下拉和手填 失败重试间隔:任务失败重新提交任务的时间间隔,支持下拉和手填 程序类型:选择Python语言 主jar包:是运行MR的Python jar包 其他参数:支持 –D、-mapper、-reducer、-input -output格式,这里可以设置用户自定义参数的输入,比如: -mapper "mapper.py 1" -file mapper.py -reducer reducer.py -file reducer.py –input /journey/words.txt -output /journey/out/mr/${currentTimeMillis} 其中 -mapper 后的 mapper.py 1是两个参数,第一个参数是mapper.py,第二个参数是1 资源: 如果其他参数中引用了资源文件,需要在资源中选择指定 自定义参数:是MR局部的用户自定义参数,会替换脚本中以${变量}的内容 创建 Spark 节点 拖动工具栏中的任务节点到画板中,双击任务节点,如下图: 节点名称:一个流程定义中的节点名称是唯一的 运行标志:标识这个节点是否能正常调度 描述信息:描述该节点的功能 失败重试次数:任务失败重新提交的次数,支持下拉和手填 失败重试间隔:任务失败重新提交任务的时间间隔,支持下拉和手填 程序类型:支持JAVA、Scala和Python三种语言 主函数的class:是Spark程序的入口Main Class的全路径 主jar包:是Spark的jar包 部署方式:支持yarn-cluster、yarn-client、和local三种模式 Driver内核数:可以设置Driver内核数及内存数 Executor数量:可以设置Executor数量、Executor内存数和Executor内核数 命令行参数:是设置Spark程序的输入参数,支持自定义参数变量的替换。 其他参数:支持 --jars、--files、--archives、--conf格式 资源:如果其他参数中引用了资源文件,需要在资源中选择指定 自定义参数:是MR局部的用户自定义参数,会替换脚本中以${变量}的内容 注意:JAVA和Scala只是用来标识,没有区别,如果是Python开发的Spark则没有主函数的class,其他都是一样 创建 Python 节点 拖动工具栏中的任务节点到画板中,双击任务节点,如下图: 节点名称:一个流程定义中的节点名称是唯一的 运行标志:标识这个节点是否能正常调度 描述信息:描述该节点的功能 失败重试次数:任务失败重新提交的次数,支持下拉和手填 失败重试间隔:任务失败重新提交任务的时间间隔,支持下拉和手填 脚本:用户开发的Python程序 资源:是指脚本中需要调用的资源文件列表 自定义参数:是Python局部的用户自定义参数,会替换脚本中以${变量}的内容 创建 依赖 节点 任务依赖分为水平依赖和垂直依赖 水平依赖就是指DAG图的有向依赖,是同一个流程实例任务节点的前驱,后继之间的依赖关系 垂直依赖是流程实例之间的任务依赖,基于定时的依赖。 拖动工具栏中的任务节点到画板中,双击任务节点,如下图: 节点名称:一个流程定义中的节点名称是唯一的 运行标志:标识这个节点是否能正常调度 描述信息:描述该节点的功能 失败重试次数:任务失败重新提交的次数,支持下拉和手填 失败重试间隔:任务失败重新提交任务的时间间隔,支持下拉和手填 任务依赖:增加依赖条件,选择依赖流程定义、节点名称(默认为全部节点)、依赖周期、依赖时间点 选择多个依赖条件之间的关系:或、且 流程实例列表 流程实例列表页是可以显示所有本项目下所有流程实例的列表,并有对流程实例进行名称、状态、时间等字段的筛选功能。通过列表页可以直接对某一个流程实例进行编辑、重跑、恢复失败、暂停、停止、恢复暂停、删除、查看甘特图等操作. 编辑功能: 对已经完成的流程实例,点击编辑按钮,可以对其编辑,如图: 查看流程实例运行变量 点击隐藏按钮,查看流程实例运行变量。如下图: 点击变量是对变量的复制 点击"重跑",可以对已经完成的流程实例进行重新运行操作,如图: 点击"恢复失败", 可以对失败的流程进行恢复,直接从失败的任务节点开始运行。如图: 点击"暂停", 可以对正在运行的流程进行暂停操作,如图: 点击"停止",可以对正在运行的流程进行停止操作,如图: 点击"恢复暂停",可以对暂停的流程恢复,直接从暂停的节点开始运行,如图: 删除 删除流程实例及流程实例下的任务实例 Gantt Gantt图纵轴是某个流程实例下的任务实例的拓扑排序,横轴是任务实例的运行时间 任务实例列表页 点击任务实例节点,点击 查看历史,可以查看该流程实例运行的该任务实例列表 查看日志 点击任务实例节点,点击 查看日志,可以查看该任务实例运行的日志,如下图: 右上角是下载日志、刷新日志和放大/缩小按钮 注意:日志查看是分片的查看,上下滚动查看 任务实例 任务实例是流程实例任务节点的列表 两种方式查看任务实例: 第一种是通过流程实例任务节点 查看历史,这时查看的是此流程实例的任务实例 重跑的列表 第二种是通过点击 流程实例 导航栏,调转到流程实例列表,这时查看的是所有流程实例的任务实例列表 查看日志:点击 查看日志 按钮,可下载和查看日志 系统参数 ### 系统参数 变量 含义 ${system.biz.date} 日常调度实例定时的定时时间前一天,格式为 yyyyMMdd,补数据时,该日期 +1 ${system.biz.curdate} 日常调度实例定时的定时时间,格式为 yyyyMMdd,补数据时,该日期 +1 ${system.datetime} 日常调度实例定时的定时时间,格式为 yyyyMMddHHmmss,补数据时,该日期 +1 时间自定义参数 支持代码中自定义变量名,声明方式:${变量名}。可以是引用 "系统参数" 或指定 "常量"。 我们定义这种基准变量为 $[...] 格式的,$[yyyyMMddHHmmss] 是可以任意分解组合的,比如:$[yyyyMMdd], $[HHmmss], $[yyyy-MM-dd] 等 也可以这样: 后 N 年:$[add_months(yyyyMMdd,12*N)] 前 N 年:$[add_months(yyyyMMdd,-12*N)] 后 N 月:$[add_months(yyyyMMdd,N)] 前 N 月:$[add_months(yyyyMMdd,-N)] 后 N 周:$[yyyyMMdd+7*N] 前 N 周:$[yyyyMMdd-7*N] 后 N 天:$[yyyyMMdd+N] 前 N 天:$[yyyyMMdd-N] 后 N 小时:$[HHmmss+N/24] 前 N 小时:$[HHmmss-N/24] 后 N 分钟:$[HHmmss+N/24/60] 前 N 分钟:$[HHmmss-N/24/60] 用户自定义参数 用户自定义参数分为全局参数和局部参数。全局参数是保存流程定义和流程实例的时候传递的全局参数,全局参数可以在整个流程中的任何一个任务节点的局部参数引用。 例如: global_bizdate为全局参数,引用的是系统参数。 任务中local_param_bizdate通过${global_bizdate}来引用全局参数,对于脚本可以通过${local_param_bizdate}来引用变量local_param_bizdate的值,或通过JDBC直接将local_param_bizdate的值set进去

优秀的个人博客,低调大师

闲鱼公开源代码实例

阿里妹导读:具有一定规模的 App 通常有一套成熟通用的基础库,尤其是阿里系 App,一般需要依赖很多体系内的基础库。那么使用 Flutter 重新从头开发 App 的成本和风险都较高。所以在 Native App 进行渐进式迁移是 Flutter 技术在现有 Native App 进行应用的稳健型方式。 今天我们来看看,闲鱼团队如何在这个实践过程中沉淀出一套独具特色的混合技术方案。 现状及思考 闲鱼目前采用的混合方案是共享同一个引擎的方案。这个方案基于这样一个事实:任何时候我们最多只能看到一个页面,当然有些特定的场景你可以看到多个 ViewController ,但是这些特殊场景我们这里不讨论。 我们可以这样简单去理解这个方案:我们把共享的 Flutter View 当成一个画布,然后用一个 Native 的容器作为逻辑的页面。每次在打开一个容器的时候我们通过通信机制通知 Flutter View 绘制成当前的逻辑页面,然后将 Flutter View 放到当前容器里面。 这个方案无法支持同时存在多个平级逻辑页面的情况,因为你在页面切换的时候必须从栈顶去操作,无法再保持状态的同时进行平级切换。举个例子:有两个页面A,B,当前B在栈顶。切换到A需要把B从栈顶 Pop 出去,此时B的状态丢失,如果想切回B,我们只能重新打开B之前页面的状态无法维持住。 如在 pop 的过程当中,可能会把 Flutter 官方的 Dialog 进行误杀。而且基于栈的操作我们依赖对 Flutter 框架的一个属性修改,这让这个方案具有了侵入性的特点。 新一代混合技术方案 FlutterBoost 重构计划 在闲鱼推进 Flutter 化过程当中,更加复杂的页面场景逐渐暴露了老方案的局限性和一些问题。所以我们启动了代号 FlutterBoost(向C++ Boost库致敬)的新混合技术方案。这次新的混合方案我们的主要目标有: 可复用通用型混合方案 支持更加复杂的混合模式,比如支持主页Tab这种情况 无侵入性方案:不再依赖修改 Flutter 的方案 支持通用页面生命周期 统一明确的设计概念 跟老方案类似,新的方案还是采用共享引擎的模式实现。主要思路是由 Native 容器 Container 通过消息驱动 Flutter 页面容器 Container,从而达到 Native Container与 Flutter Container 的同步目的。我们希望做到 Flutter 渲染的内容是由 Naitve 容器去驱动的。 简单的理解,我们想做到把 Flutter 容器做成浏览器的感觉。填写一个页面地址,然后由容器去管理页面的绘制。在 Native 侧我们只需要关心如果初始化容器,然后设置容器对应的页面标志即可。 主要概念 Native 层概念 Container:Native 容器,平台 Controller,Activity,ViewController Container Manager:容器的管理者 Adaptor:Flutter 是适配层 Messaging:基于 Channel 的消息通信 Dart 层概念 Container:Flutter 用来容纳 Widget 的容器,具体实现为 Navigator 的派生类 Container Manager:Flutter 容器的管理,提供 show,remove 等 Api Coordinator: 协调器,接受 Messaging 消息,负责调用 Container Manager 的状态管理。 Messaging:基于 Channel 的消息通信 关于页面的理解 在 Native 和 Flutter 表示页面的对象和概念是不一致的。在 Native,我们对于页面的概念一般是 ViewController,Activity 。而对于 Flutter 我们对于页面的概念是 Widget 。我们希望可统一页面的概念,或者说弱化抽象掉 Flutter 本身的 Widget 对应的页面概念。换句话说,当一个 Native 的页面容器存在的时候, FlutteBoost 保证一定会有一个 Widget 作为容器的内容。所以我们在理解和进行路由操作的时候都应该以 Native 的容器为准, Flutter Widget 依赖于 Native 页面容器的状态。 那么在 FlutterBoost 的概念里说到页面的时候,我们指的是 Native 容器和它所附属的 Widget 。所有页面路由操作,打开或者关闭页面,实际上都是对 Native 页面容器的直接操作。无论路由请求来自何方,最终都会转发给 Native 去实现路由操作。这也是接入 FlutterBoost 的时候需要实现 Platform 协议的原因。 另一方面,我们无法控制业务代码通过 Flutter 本身的 Navigator 去 push 新的 Widget 。对于业务不通过 FlutterBoost 而直接使用 Navigator 操作 Widget 的情况,包括 Dialog 这种非全屏 Widget,我们建议是业务自己负责管理其状态。这种类型 Widget 不属于 FlutterBoost 所定义的页面概念。 理解这里的页面概念,对于理解和使用 FlutterBoost 至关重要。 与老方案主要差别 前面我们提到老方案在 Dart 层维护单个 Navigator 栈结构用于 Widget 的切换。而新的方案则是在 Dart 侧引入了 Container 的概念,不再用栈的结构去维护现有的页面,而是通过扁平化 key-value 映射的形式去维护当前所有的页面,每个页面拥有一个唯一的 id 。这种结构很自然的支持了页面的查找和切换,不再受制于栈顶操作的问题,之前的一些由于 pop 导致的问题迎刃而解。也不需要依赖修改 Flutter 源码的形式去进行页面栈操作,去掉了实现的侵入性。 实际上我们引入的 Container 就是 Navigator 的,也就是说一个 Native 的容器对应了一个 Navigator 。那这是如何做到的呢? 多 Navigator 的实现 Flutter 在底层提供了让你自定义 Navigator 的接口,我们自己实现了一个管理多个 Navigator 的对象。当前最多只会有一个可见的 Flutter Navigator ,这个Navigator 所包含的页面也就是我们当前可见容器所对应的页面。 Native 容器与 Flutter 容器( Navigator )是一一对应的,生命周期也是同步的。当一个 Native 容器被创建的时候, Flutter 的一个容器也被创建,它们通过相同的 id 关联起来。当 Native 的容器被销毁的时候, Flutter 的容器也被销毁。 Flutter 容器的状态是跟随 Native 容器,这也就是我们说的 Native 驱动。由 Manager 统一管理切换当前在屏幕上展示的容器。 我们用一个简单的例子描述一个新页面创建的过程: 创建 Native 容器( iOS ViewController,Android Activity or Fragment )。 Native 容器通过消息机制通知 Flutter Coordinator 新的容器被创建。 Flutter Container Manager 进而得到通知,负责创建出对应的 Flutter 容器,并且在其中装载对应的 Widget 页面。 当 Native 容器展示到屏幕上时,容器发消息给 Flutter Coordinator 通知要展示页面的 id 。 Flutter Container Manager 找到对应 id 的 Flutter Container 并将其设置为前台可见容器。 这就是一个新页面创建的主要逻辑,销毁和进入后台等操作也类似有 Native 容器事件去进行驱动。 官方提出的混合方案 基本原理 Flutter 技术链主要由 C++实现的 Flutter Engine 和 Dart 实现的 Framework 组成(其配套的编译和构建工具我们这里不参与讨论)。Flutter Engine 负责线程管理,Dart VM 状态管理和 Dart 代码加载等工作。而 Dart 代码所实现的 Framework 则是业务接触到的主要 API,诸如 Widget 等概念就是在 Dart 层面 Framework 内容。 一个进程里面最多只会初始化一个 Dart VM。然而一个进程可以有多个 Flutter Engine,多个 Engine 实例共享同一个 Dart VM。 我们来看具体实现,在 iOS 上面每初始化一个 FlutterViewController 就会有一个引擎随之初始化,也就意味着会有新的线程(理论上线程可以复用)去跑 Dart 代码。Android 类似的 Activity 也会有类似的效果。如果你启动多个引擎实例,注意此时Dart VM 依然是共享的,只是不同 Engine 实例加载的代码跑在各自独立的 Isolate。 官方建议 引擎深度共享 在混合方案方面,我们跟 Google 讨论了可能的一些方案。Flutter 官方给出的建议是从长期来看,我们应该支持在同一个引擎支持多窗口绘制的能力,至少在逻辑上做到 FlutterViewController 是共享同一个引擎的资源的。换句话说,我们希望所有绘制窗口共享同一个主 Isolate。 但官方给出的长期建议目前来说没有很好的支持。 多引擎模式 我们在混合方案中解决的主要问题是如何去处理交替出现的 Flutter 和 Native 页面。Google 工程师给出了一个 Keep It Simple 的方案:对于连续的 Flutter 页面(Widget)只需要在当前 FlutterViewController 打开即可,对于间隔的 Flutter 页面我们初始化新的引擎。 例如,我们进行下面一组导航操作: 我们只需要在 Flutter Page1 和 Flutter Page3 创建不同的 Flutter 实例即可。 这个方案的好处就是简单易懂,逻辑清晰,但是也有潜在的问题。如果一个 Native页面一个 Flutter 页面一直交替进行的话,Flutter Engine 的数量会线性增加,而Flutter Engine 本身是一个比较重的对象。 多引擎模式的问题 冗余的资源问题:多引擎模式下每个引擎之间的 Isolate 是相互独立的。在逻辑上这并没有什么坏处,但是引擎底层其实是维护了图片缓存等比较消耗内存的对象。想象一下,每个引擎都维护自己一份图片缓存,内存压力将会非常大。 插件注册的问题:插件依赖 Messenger 去传递消息,而目前 Messenger 是由 FlutterViewController(Activity) 去实现的。如果你有多个 FlutterViewController ,插件的注册和通信将会变得混乱难以维护,消息的传递的源头和目标也变得不可控。 Flutter Widget 和 Native 的页面差异化问题: Flutter 的页面是 Widget, Native 的页面是 VC 。逻辑上来说我们希望消除 Flutter 页面与 Naitve 页面的差异,否则在进行页面埋点和其它一些统一操作的时候都会遇到额外的复杂度。 增加页面之间通信的复杂度:如果所有 Dart 代码都运行在同一个引擎实例,它们共享一个 Isolate ,可以用统一的编程框架进行 Widget 之间的通信,多引擎实例也让这件事情更加复杂。 因此,综合多方面考虑,我们没有采用多引擎混合方案。 总结 目前 FlutterBoost 已经在生产环境支撑着在闲鱼客户端中所有的基于 Flutter 开发业务,为更加负复杂的混合场景提供了支持,稳定为亿级用户提供服务。 我们在项目启动之初就希望 FlutterBoost 能够解决 Native App 混合模式接入 Flutter 这个通用问题。所以我们把它做成了一个可复用的 Flutter 插件,希望吸引更多感兴趣的朋友参与到 Flutter 社区的建设。在有限篇幅中,我们分享了闲鱼在 Flutter 混合技术方案中积累的经验和代码。欢迎兴趣的同学能够积极与我们一起交流学习。 扩展补充 性能相关 在两个 Flutter 页面进行切换的时候,因为我们只有一个 Flutter View 所以需要对上一个页面进行截图保存,如果 Flutter 页面多截图会占用大量内存。这里我们采用文件内存二级缓存策略,在内存中最多只保存2-3个截图,其余的写入文件按需加载。这样我们可以在保证用户体验的同时在内存方面也保持一个较为稳定的水平。 页面渲染性能方面, Flutter 的 AOT 优势展露无遗。在页面快速切换的时候, Flutter 能够很灵敏的相应页面的切换,在逻辑上创造出一种 Flutter 多个页面的感觉。 Release1.0的支持 项目开始的时候我们基于闲鱼目前使用的 Flutter 版本进行开发,而后进行了 Release 1.0 兼容升级测试目前没有发现问题。 接入 只要是集成了 Flutter 的项目都可以用官方依赖的方式非常方便的以插件形式引入 FlutterBoost ,只需要对工程进行少量代码接入即可完成接入。 详细接入文档,请参阅GitHub主页官方项目文档。 作者: 福居 原文链接​ 本文为云栖社区原创内容,未经允许不得转载。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册