关于开源框架:开源-2-年半除了性能优化我们啥也没做

性能优化是个非常宽泛的话题,它波及 CPU、内存、磁盘、网络等方面。MegEngine 作为一个训推一体的深度学习框架,也在继续一直摸索性能优化的最优解。 本篇整顿了 Bot 过往公布的相干文章,心愿能帮忙大家更好的了解和把握 MegEngine 应用技巧。 工欲善其事必先利其器学会使用性能评测工具提到性能优化,笔者认为性能优化人员的技术水平大略可被分为以下三类: “瞎着写“。这类技术水平的人员个别不会在意其余,遇事先上”三板斧“,如循环展开,向量化,指令重排。性能好往往也不知其所以然,性能不好也没有什么后续的优化思路。”摸着写”。这类技术水平的人员与第一类的一个显著的分水岭是学会使用性能评测工具,通过工具可能摸到程序的瓶颈在何处,而后进行对应的优化。”瞄着写“。这类人员有了量化分析程序性能的能力。当面临同一个程序的多种写法时,可能做到即便不实在实现程序,也能较为精准的算进去哪种写法性能更好。须要留神的是以上三类人员所用的技术是逐级蕴含的关系,例如第三类人员同样把握性能评测工具的应用办法和”三板斧“式的优化办法。正所谓工欲善其事必先利其器,其实只有达到第二类的程度,性能优化人员才初步具备独立优化能力,所以性能评测工具的把握至关重要。如果你对性能优化中一些基本概念还不够理解,且对以下问题也有雷同的疑难: Python 及 C/C++ 拓展程序的常见的优化指标有哪些;常见工具的能力范畴和局限是什么,给定一个优化指标咱们应该如何抉择工具;各种工具的应用办法和后果的可视化办法;《profiling 与性能优化总结》将会是一个很好的总结性资料。 学会根本的性能优化方法论学会了使用性能评测工具之后,还须要理解根本的性能优化方法论,而后就根本具备独立优化能力了。性能优化很多时候就是一直迭代的过程: 以 ARM Cortex a55 上的 GaussianBlur 优化为例,一起看《ARM 算子性能优化上手指南》 作为深度学习框架,模型训练速度很重要解决系统算子工夫占比高的问题家喻户晓,很多深度学习模型中都有相似 element-wise 的散碎操作。例如加减乘除算术运算和神经网络中的激活函数,以及 BatchNormalization 在模型推理的时候个别也被优化成一系列的 element-wise 操作。 这些散碎的操作具备计算访存比低的特点,即其计算量较低然而访存量较高,是一种典型的内存受限(memory bound)的操作。算子交融(kernel fusion)是针对内存受限的算子的常见优化伎俩。然而这些散碎算子的计算模式泛滥,这些计算模式互相组合将会是指数级别的,依附手工写代码进行针对性优化是不事实的。MegEngine 通过引入 JIT 和主动代码生成技术解决计算模式组合爆炸的问题,从而享受到 kernel fusion 带来的性能收益,详见《JIT in MegEngine》。 晋升多机多卡训练效率从 2080Ti 这一代显卡开始,所有的民用游戏卡都勾销了 P2P copy,导致训练速度显著的变慢。针对这种状况下的单机多卡训练,MegEngine 《利用共享内存实现比 NCCL 更快的汇合通信 》算法,对多个不同的网络训练绝对于 NCCL 有 3% 到 10% 的减速成果。 MegEngine v1.5 版本,能够手动切换汇合通信后端为 shm(默认是 nccl),只须要改一个参数。 gm = GradManager() gm.attach(model.parameters(), callbacks=[dist.make_allreduce_cb("sum", backend="shm")]) # 目前只实现了单机版本,多机暂不反对作为一个训推一体的框架,推理速度同样重要云侧GPU CUDA 矩阵乘法单精度矩阵乘法(SGEMM)简直是每一位学习 CUDA 的同学绕不开的案例,这个经典的计算密集型案例能够很好地展现 GPU 编程中罕用的优化技巧,而是否写出高效率的 SGEMM Kernel,也是反映一位 CUDA 程序员对 GPU 体系结构的了解水平的优良考题。 ...

October 8, 2022 · 2 min · jiezi

关于开源框架:火遍安卓的下拉刷新框架-SmartRefresh-出-IOS-版了

安卓那边的开源库 SmartRefresh 之所以能火,我集体感觉是因为 SmartRefresh 汇集了各种优质刷新款式于一身,对款式的切换非常简单,还不必思考更换款式之后的兼容性稳定性问题,在 SmartRefresh 呈现之前 github 上也有各种个样优良款式的刷新,然而切换的老本比拟高,危险也高;同时他能一个框架集成各种格调的款式,也阐明它的扩展性十分强,即便找不到适宜本人的款式,也能够通过自定义款式来解决。 那么当初我带来了一个好消息,IOS版本 SmartRefreshControl 终于公布了! github: 我的项目地址gitee: 我的项目地址 (国内速度快) 简介SmartRefreshControl 是 SmartRefreshLayout 的IOS版,和Android版在 理念 和 外观 下面保留雷同的设计,然而因为 Android 和 IOS 两个零碎的差异,IOS版本在性能应用和个性上与安卓版有所差异。刷新控件应用 ObjectiveC 语言编写,演示 DemoApp 应用 Swift 语言编写。 目前 SmartRefreshControl 性能还不是很弱小,也不太稳固,只是在界面层面实现了安卓版的性能。欢送大家来体验与发现BUG,不举荐应用在正式我的项目中。 由来大学毕业后我大部分工夫从事安卓开发,在安卓版 SmartRefresh 大火之后,我开始转型 IOS 开发。到当初曾经有三年的IOS开发教训,因为IOS上也还未有像 SmartRefresh 一样同一个开源库多种外观款式的刷新库,也想坚固本人所学的 IOS技能,我决定在空闲之余把安卓 SmartRefresh 复刻到IOS平台来。通过一年多的致力总算初步实现了。 成果展现DeliveryMaterialRefresh-your-deliveryMaterialHeaderBezierRadarBezierCirclePull To RefreshPull Down To RefreshFlyRefreshDropBox FlyRefreshDropBoxHeaderPhoenixTaurusYalantis/PhoenixYalantis/TaurusBattleCityHitBlockFunGame/BattleCityFunGame/HitBlockStoreHouseWaveSwipeCRefreshLayoutWaveSwipeRefreshLayoutOriginalClassicsFlyRefreshClassicsHeader如果须要体验下面列出的各种刷新头,须要克隆 git 源码,用Xcode编译运行Demo我的项目即可。 简略用例1.在 Podfile 中增加依赖pod 'SmartRefreshControl', '~> 0.1.0'2.在 ViewController 中增加刷新控件#import <SmartRefreshControl/SmartRefreshControl.h>@interface DemoTableViewController ()@property (strong, nonatomic) IBOutlet UITableView *tableView; @property (strong, nonatomic) UIRefreshBezierRadarHeader *header; @end@implementation DemoTableViewController- (void)viewDidLoad { [super viewDidLoad]; //形式1: 初始化同时绑定事件 [self setHeader:[UIRefreshBezierRadarHeader attach:self.tableView target:self action:@selector(onRefresh)]]; //形式2: 先初始化,再绑定事件 [self setHeader:[UIRefreshBezierRadarHeader attach:self.tableView]]; [self.header addTarget:self action:@selector(onRefresh)]; //形式3: 先创立,再绑定 [self setHeader:[UIRefreshBezierRadarHeader new]]; [self.header attach:self.tableView]; [self.header addTarget:self action:@selector(onRefresh)];}@end3.增加刷新监听事件@implementation DemoTableViewController- (void)onRefresh { [self.header finishRefresh]; //敞开刷新,能够改成申请网络,胜利/失败之后再敞开刷新}@end

July 20, 2022 · 1 min · jiezi

关于开源框架:LiteFlow-260版本发行注记项目逻辑解耦的利器

前言自从LiteFlow 2.5.X版本公布依赖,陆续经验了10个小版本的迭代。社区群也巩固增长,每天都有很多小伙伴在问我问题。 然而我发现最多人问我的还是:什么时候能反对界面编排? 从LiteFLow的倒退布局上来说,将来肯定会反对界面编排,然而在反对界面编排之前。有一些地基必须得打牢固,这是前提,这就像走台阶,没有跨上第二级台阶,是无奈达到第三级台阶的。 所以从布局上来说,这个前提地基就是规定动静脚本的反对。 这一次,咱们带来了2.6.0-BETA1版本,版本个性就是动静脚本的反对,同时反对了阿里QLExpress脚本和Groovy的脚本。应用文档曾经全副更新至官网。 官方主页:https://yomahub.com/liteflow尽管这是个BETA版本,但无论从底层严谨性还有测试用例上,咱们都下了功夫。应该在不久之后,会推出2.6.0的正式版。 如果你是第一次晓得LiteFlow这款框架,能够移步以下链接进行理解: Gitee仓库主页:https://gitee.com/dromara/lit... Github仓库主页:https://github.com/dromara/li... 也能够看我之前公布的一篇介绍LiteFlow框架的文章 https://mp.weixin.qq.com/s/xy...新版本个性个性 #I44FT8 反对脚本语言的组件,并反对动静刷新脚本(版本个性) https://gitee.com/dromara/lit... 个性 #I3ZVEA 流程组件反对重试 https://gitee.com/dromara/lit... 加强 #I40DWO 流程配置文件中减少业务形容,打印步骤中带入业务形容 https://gitee.com/dromara/lit... 修复 #I3VZMZ when类型condition场景下记录节点执行门路的办法会造成数据失落 https://gitee.com/dromara/lit... 修复 #I3UOJG 流程终止Slot内无数据 https://gitee.com/dromara/lit... 目前我的项目情况LiteFLow框架被多家企业使用在外围我的项目中,国内开源流程编排框架其实并不多。LiteFLow的愿景是成为国内最轻量级,流程编排畛域最风行的开源框架。 目前LiteFlow star不多,才500+,社群人数向着300人进发,心愿大家能多多帮咱们转发和推广。 LiteFlow我的项目咱们会始终保护迭代上来。并且在易用性,实用性,性能和官网文档方面会始终进步和改良。 后续打算在2.6.X之后开始打算2.7.X的开发布局,2.7.X,你们所期待的界面编排,界面治理就会如期而至。关注LiteFlow并进入社区群,我会及时更新开发进度。 一键三连啊还是要说下,开源基本上是用爱发电,请大家一键三连啊。在gitee和github上给LiteFlow一个star和fork就是最大的反对 Gitee仓库主页:https://gitee.com/dromara/lit... Github仓库主页:https://github.com/dromara/li... 招募开源事业听起来高大上,然而理论做起来保持下来,并不轻松。因为开源并不赚钱。反而须要付出大量的业余时间和精力。但你也会播种很多。 然而很多开源作者都这么保持下来了,他们也是我的楷模。中国开源也须要很多的爱,去发更多的电。 如果你对技术同样有敬畏,对开源事业同样有酷爱,并且看好LiteFlow这个我的项目,请退出咱们。 如何退出: 1.退出LiteFLow社区群 2.关注LiteFlow的issue并被动认领,在群里@我并告知认领事项 3.实现2个issue后。通过审核合并入master发版之后,给committer权限 4.当前参加LiteFlow的决策,issue奉献和推广保护 如何退出社群因为社群曾经超过200人,关注后,须要加作者,而后拉你入社群,社群目前将近300人,外面有各路大佬能帮你解决应用中的问题。

August 17, 2021 · 1 min · jiezi

关于开源框架:dubbo学习

每个ExtensionLoader实例只负责加载一个特定扩大点实现每个扩大点对应最多只有一个ExtensionLoader实例对于每个扩大点实现,最多只会有一个实例一个扩大点实现能够对应多个名称(逗号分隔)每个扩大点最多只能有一个被AdaptiveExtension每个扩大点能够有多个可主动激活的扩大点实现(应用@Activate注解)因为每个扩大点实现最多只有一个实例,因而扩大点实现应保障线程平安如果扩大点有多个Wrapper,那么最终其执行的程序不确定(外部应用ConcurrentHashSet存储)getExtension办法: public T getExtension(String name) { if (name == null || name.length() == 0) throw new IllegalArgumentException("Extension name == null"); if ("true".equals(name)) { return getDefaultExtension(); } // 先从缓存获取 Holder<Object> holder = cachedInstances.get(name); if (holder == null) { cachedInstances.putIfAbsent(name, new Holder<Object>()); holder = cachedInstances.get(name); } Object instance = holder.get(); if (instance == null) { synchronized (holder) { instance = holder.get(); if (instance == null) { // 构建instance instance = createExtension(name); holder.set(instance); } } } return (T) instance;}createExtension办法: ...

April 21, 2021 · 10 min · jiezi

关于开源框架:recycler

import io.netty.util.Recycler;import org.junit.Assert; public class Entry { String data;private Recycler.Handle<Entry> handle;private static final Recycler<Entry> RECYCLER = new Recycler<Entry>() { @Override protected Entry newObject(Handle<Entry> handle) { return new Entry(handle); }};public Entry(Recycler.Handle<Entry> handle) { this.handle = handle;}public void recycle() { handle.recycle(this);}public String getData() { return data;}public void setData(String data) { this.data = data;}public static Entry newInstance(String data) {// get入口 Entry entry = RECYCLER.get(); entry.setData(data); return entry;}public static void main(String[] args) { Entry entry =Entry.newInstance("one"); // 回收入口 entry.recycle(); Entry entry1 = Entry.newInstance("two"); Assert.assertSame(entry1, entry);}} ...

April 16, 2021 · 5 min · jiezi

关于开源框架:干货丨Zabbix-应用常见问题和故障解决

本文转自@TWT社区 1、Zabbix 是怎么施行监控的? 一个监控零碎运行的大略的流程是这样的: agent须要装置到被监控的主机上,它负责定期收集各项数据,并发送到zabbix server端,zabbix server将数据存储到数据库中,zabbix web依据数据在前端进行展示和绘图。这里agentd收集数据分为被动和被动两种模式: 被动:agent申请server获取被动的监控项列表,并被动将监控项内须要检测的数据提交给server/proxy 被动:server向agent申请获取监控项的数据,agent返回数据。 被动监测通信过程如下: zabbix首先向ServerActive配置的IP申请获取active items,获取并提交active tiems数据值server或者proxy。很多人会提出疑难:zabbix多久获取一次active items?它会依据配置文件中的RefreshActiveChecks的频率进行,如果获取失败,那么将会在60秒之后重试。分两个局部: 获取ACTIVE ITEMS列表 Agent关上TCP连贯(被动检测变成Agent关上) Agent申请items检测列表 Server返回items列表 Agent 解决响应 敞开TCP连贯 Agent开始收集数据 被动检测提交数据过程如下: Agent建设TCP连贯 Agent提交items列表收集的数据 Server解决数据,并返回响应状态 敞开TCP连贯 被动监测通信过程如下: Server关上一个TCP连贯 Server发送申请agent.pingn Agent接管到申请并且响应 Server解决接管到的数据 敞开TCP连贯 1、新建监控我的项目时,抉择的是zabbix代理还是zabbix端点代理程式(主动式),前者是被动模式,后者是被动模式。 2、agentd配置文件中StartAgents参数的设置,如果为0,示意禁止被动模式,否则开启。个别倡议不要设置为0,因为监控我的项目很多时,能够局部应用被动,局部应用被动模式。 2、Zabbix 主动发现是怎么做的? zabbix发现有3种类型: 1、主动网络发现 ( Network discovery) 2、被动客户端主动注册 ( Active agent auto-registration ) 3、低级别发现 ( low-level discovery ) 主动发现的做法: 1、首先须要在模板当中创立一个主动发现的规定,这个中央只须要一个名称和一个键值。 2、过滤器两头要增加你须要的用到的值宏。 3、而后要创立一个监控项原型,也是一个名称和一个键值。 4、而后须要去写一个这样的键值的收集。 主动发现实际上就是须要首先去取得须要监控的值,而后将这个值作为一个新的参数传递到另外一个收集数据的item外面去。 3、Zabbix监控的客户端是怎么进行批量装置的? 举荐应用Ansible等自动化软件来进行批量装置。将装置过程编写执行脚本,而后再应用Ansible来进行批量装置。 1、应用命令生成密钥。 2、将公钥发送到所有装置zabbix客户端的主机。 3、装置 ansible 软件,(批改配置文件,将zabbix 客户机增加进组)。 4、创立一个装置zabbix客户端的脚本。 5、执行该脚本。 ...

March 9, 2021 · 4 min · jiezi

关于开源框架:别再用硬编码写业务流程了试试这款轻量级流程编排框架

前言在每个公司的零碎中,总有一些领有简单业务逻辑的零碎,这些零碎承载着外围业务逻辑,简直每个需要都和这些外围业务无关,这些外围业务业务逻辑简短,波及外部逻辑运算,缓存操作,长久化操作,内部资源调取,外部其余零碎RPC调用等等。工夫一长,我的项目几经易手,保护的老本得就会越来越高。各种硬代码判断,分支条件越来越多。代码的形象,复用率也越来越低,各个模块之间的耦合度很高。一小段逻辑的变动,会影响到其余模块,须要进行残缺回归测试来验证。如要灵便扭转业务流程的程序,则要进行代码大改变进行形象,从新写办法。实时热变更业务流程?简直很难实现。 开源解决方案说到流程引擎,开源界有赫赫有名的老牌开源软件JBPM,也有近几年十分风行的Activiti和Flowable。他们都是基于BPM协定,能够做到基于角色工作的流传,逻辑的流转。并且很多基于BPM协定的编辑工具都能做可视化的编辑。 但明天我要介绍的,是一款轻量级的流程编排框架——Liteflow。 Liteflow次要致力于逻辑驱动的编排。能够满足于大部分的生产业务场景。和以上驰名的开源流程引擎相比,尽管不如他们那么全面,然而胜在轻量,高性能和极少的学习老本。而且这些我的项目都是国外开源我的项目,集成起来绝对比拟重,文档本地化也做的不够好。Liteflow领有欠缺的本地文档和应用范例。能帮忙你的外围零碎变得更加灵便,更加易扩大。是一个解耦你零碎的利器。 https://gitee.com/bryan31/lit... Liteflow框架的作用Liteflow就是为解耦简单逻辑而生,如果你要对简单业务逻辑进行新写或者重构,用liteflow最合适不过。它是一个轻量,疾速的组件式流程引擎框架,组件编排,帮忙解耦业务代码,让每一个业务片段都是一个组件。 应用Liteflow,你须要去把简单的业务逻辑按代码片段拆分成一个个小组件,并定义一个规定流程配置。这样,所有的组件,就能依照你的规定配置去进行简单的流转。同时Liteflow反对规定文件的热加载,即时实现批改失效。并提供多种长久化规定的形式的扩大。 Liteflow的设计准则Liteflow是基于工作台模式进行设计的,何谓工作台模式? n个工人依照肯定程序围着一张工作台,按程序各自生产整机,生产的整机最终能组装成一个机器,每个工人只须要实现本人手中整机的生产,而无需晓得其余工人生产的内容。每一个工人生产所须要的资源都从工作台上拿取,如果工作台上有生产所必须的资源,则就进行生产,若是没有,就等到有这个资源。每个工人所做好的整机,也都放在工作台上。 这个模式有几个益处: 每个工人无需和其余工人进行沟通。工人只须要关怀本人的工作内容和工作台上的资源。这样就做到了每个工人之间的解耦和无差异性。即使是工人之间调换地位,工人的工作内容和关怀的资源没有任何变动。这样就保障了每个工人的稳定性。如果是指派某个工人去其余的工作台,工人的工作内容和须要的资源仍旧没有任何变动,这样就做到了工人的可复用性。因为每个工人不须要和其余工人沟通,所以能够在生产工作进行时进行实时工位更改:替换,插入,撤掉一些工人,这样生产工作也能实时的被更改。这样就保障了整个生产工作的灵活性。这个模式映射到Liteflow框架里,工人就是组件,工人坐的程序就是流程配置,工作台就是上下文,资源就是参数,最终组装的这个机器就是这个业务。正因为有这些个性,所以Liteflow能做到对立解耦的组件和灵便的拆卸。 springboot里疾速配置Liteflow反对了springboot的主动拆卸,当然Liteflow也为非springboot和非spring的我的项目也提供了反对,这里仅以springboot我的项目为示例进行介绍: 依赖最新的依赖包: <dependency> <groupId>com.yomahub</groupId> <artifactId>liteflow-spring-boot-starter</artifactId> <version>2.3.3</version></dependency>配置上规定门路: liteflow.rule-source=config/flow.xml定义组件Liteflow心愿用户把简单逻辑拆分成一个个可复用的组件,所以你得定义你的组件,组件的定义很简略,你须要继承NodeComponent类,而后实现process 办法就行,以下为示例: @Component("test")public class TestComponent extends NodeComponent { @Override public void process() { Slot slot = this.getSlot();//slot为这个申请的上下文 //这里为你的业务解决逻辑 }}这里会有童鞋问,我的业务办法须要入参和出参怎么办,如何传递呢? Liteflow为每个线程都主动调配了惟一的一个slot,能够了解为上下文。想一想下面说的那个模型,每个组件不须要和其余组件进行信息互通,所须要的参数从slot里取就是了,同时,执行完业务逻辑之后,把后果也放入slot里。所以每个组件都是独立的无参结构,这样就打消了每个组件的差异性。 这里的slot能贯通所有组件,每一个组件都能够拜访到slot里所有的数据。当然每个申请之间的slot,Liteflow做了严格的隔离,不必放心数据会串的问题。 Liteflow提供的默认Slot是一个弱类型的对象,这里倡议使用者本人定义一个值对象,只须要继承AbsSlot类,便可成为你本人的Slot。更加贴合业务。 组件除了必须要实现的process 办法,还有几个可选实现: isAccess:示意是否进入该节点,能够用于业务参数的预先判断 isContinueOnError:示意出错是否持续往下执行下一个组件,默认为false isEnd:示意是否立刻完结整个流程 ,默认为false,也能够在业务日志里依据业务判断来调用this.setIsEnd(true)来完结整个流程。 @Component("test")public class TestComponent extends NodeComponent { @Override public void process() { Slot slot = this.getSlot();//slot为这个申请的上下文 //这里为你的业务解决逻辑 } @Override public boolean isAccess() { Slot slot = this.getSlot(); //这里做你的参数查看,如果没获取到必须的业务参数,就不会进入该组件 boolean checkResult = true;//模仿查看后果为true return checkResult; } @Override public boolean isContinueOnError() { return super.isContinueOnError();//默认为false } @Override public boolean isEnd() { return super.isEnd();//默认为false }}你只需定义你的业务组件,之后,在启动时,Liteflow会主动扫描到你定义的所有组件,并进行加载。 ...

January 4, 2021 · 1 min · jiezi

提效降本蚂蚁金服如何用融合计算改造在线机器学习

去年春节期间支付宝推出的集五福的活动可谓风靡一时,每张福卡背面都有刮刮卡,里面有来自蚂蚁金服、阿里巴巴以及合作伙伴的上百种权益。集五福的活动集中在春节前的几天,具有很强的时效性。所以如何实现权益和投放人群的自动匹配,解决系统的冷启动问题,优化转化率和提升用户体验,就成了一个在线学习的优化问题。 之前我们搭建一个这样的系统需要的模块非常繁杂。我们需要日志收集、数据聚合、样本的拼接和采样等流处理任务,需要对接模型训练、模型验证等机器学习模块,需要有把模型实时加载的模型服务,还需要其他的配套设施等等。众多模块的衔接极大地增加了系统的复杂性。 由于涉及的系统比较多,我们之前的系统遇到了比较多的问题。比如大促时为了保证高优链路的稳定性,上游某些数据处理的链路就会被降级了,但下游同学并不知情。另外一个很常见问题的是流批逻辑不一致,需要离线特征来训练基准模型,同时在线计算的特征来对模型进行实时更新。这两个模块一个在离线一个在线,曾经出现过处理逻辑的细微差别对业务效果造成了很大的影响。 总结下来,我们曾经遇到的坑可以归结为三类: SLA:整个链路的SLA会受到每个模块的SLA的影响,并随着模块的增多而放大,稳定性成为制约业务发展的重要因素。系统效率:模块之间的衔接多数是通过数据的落盘来进行,模块间的调度通过系统调度来实现,造成不必要的I/O、计算和网络开销。开发和运维的成本:各个模块风格迥异,开发模式、计算框架、甚至代码风格都不一致,开发和运维对接时需要花很多时间去熟悉系统,降低业务开放的效率。 一个理想的系统应该提供什么样的能力呢?可以从“稳快简”三个方面来讲:首先从数据来讲它需要保证数据和计算一致性,实现整个链路端到端的SLA,数据一致性和链路的稳定是保障业务稳定的基础。第二是我们需要去优化系统效率,我们希望把这十几个系统的衔接转换成系统内部的衔接,希望把这些作业调度转换成任务的调度,通过这样转化我们希望把计算与计算之间协同调度,从而提高系统效率和降低网络带宽使用的目的。一个融合的系统也可以对开发和运维提供非常大的便利,以前需要对接十几个系统,现在只要对接一个系统就可以了。以前我们在应急的时候需要回溯好几个业务来发现问题,现在融合在一起的系统调试也会更加容易。 在线机器学习最外层需要透出数据处理、模型训练、模型服务三个能力。这三个能力反映到对计算引擎框架上的需求是敏捷的调用机制、比较灵活的资源管控,以及比较完善的容错机制。上层的系统往往是通过不同编程语言来实现的,因此还需要有多语言接口。通过对底层需求的考量以及现在各框架的特点,最后我们选择了Ray为融合计算的底座。 Ray是由伯克利大学RiseLab实验室发起,蚂蚁金服共同参与的一个开源分布式计算框架,它提出的初衷在于让分布式系统的开发和应用能够更加简单。Ray作为计算框架可以帮我们实现上面“稳快简”三个目标。Ray作为计算框架具有敏捷的调度机制,用它可以一秒钟进行上百万次任务调度,它也可以根据计算对资源使用的需求实现异构调度。 在目前比较流行的分布式框架,都有三个比较基础的分布式原语,分布式任务、对象和服务。而我们常用的面向过程的编程语言中,也刚好有三个基本概念,函数、变量和类。这三个编程语基本概念刚好可以和分布式框架的原语对应起来。在Ray系统中,可以通过简单的改动,实现他们之间的转换。 左边是一个简单的例子,在这个函数前面需要加入一个“@remote”修饰符,就可以把一个函数转换成为分布式任务。任务通过“.remote”调用执行,返回值是一个变量,又可以参与到其他计算中。 右边是另一个例子,通过加“@remote”修饰符的方式可以把一个类转变成服务。类中的方法可以通过“.remote”调用变成一个分布式任务,和函数的使用非常相似。通过这种方式可以实现从单机程序到分布式任务的转变,把本地的任务调度到远程的机器上进行执行。 Ray上应该做怎么样的调度,衡量指标就是系统的效率问题,系统的效率很多时候取决于计算和数据的组织方式,比如说我们要计算Add(a,b),首先这个函数在本地会被自动注册并且提供给本地调度器。之后通过全剧调度器和第二个节点的本地调度器一起协同工作,把A备份到第二个节点执行Add这个操作。它还可以根据A和B的数据大小来进行进一步的调度和控制优化,A和B可以是简单数据类型,也可以是比较复杂的变量或者矩阵。 Ray上面提供多语言API接口。由于历史原因,在蚂蚁金服内部流式计算使用最多的语言是Java,而机器学习建模比较普遍使用的语言是Python。我先希望重用Java语言实现的流处理算子,同时保留Python进行机器学习建模的便捷性。Ray上面提供这样的多元化支持就非常方便我们做这个事情,用户在上层开发的时候可以可以方便地使用Java和Python分别进行流处理和机器学习模型的开发。 对于在线机器学习来说,它最核心需要解决的问题是要打通流计算和模型训练,那我们需要使用一个介质,这个介质能够比较方便的将两者衔接在一起。之前我们介绍Ray的几个特点,如提供多语言的接口、灵活的调动机制,这是因为这两个特点在Ray上可以比较方便做这个事情,Ray可以起到衔接的作用。数据处理的最后一个节点是流计算的输出,worker节点消费数据,是模型训练的输入。Ray就可以通过调度机制把这两个计算调度在一个节点上,实现数据共享从而实现两个模式的打通。通过这种方式不仅可以兼容流计算和机器学习,也可以将其他模式进行衔接。 计算中DAG概念最开始是为了解决多阶段分布式计算的效率而提出的,主要思想是通过调度减少计算时的IO。但是以前的计算DAG,在任务执行的时候它就已经确定了,但我们在机器学习的任务里面,很多时候我们会需要设计新的模型,或者对模型的超参进行调试,我们希望看到这些模型能被加载到链路上,看到业务效果的同时又不想线上已经有的模型的训练和服务被中断。在Ray系统内部,计算的过程中可以动态的生成另外一个节点,我们可以利用这个特性来增点和变,从而动态的对DAG进行局部修正。 在线系统和离线系统之间比较大的区别,在于如果一个离线系统里的任务挂了,一般来说可以通过重启机器的方式来解决,但对在线系统来说,出于时效性的考虑,我们不能简单的通过重启机群回溯数据的方式来解决。因此就需要有比较完善的容错机制。我们在模型训练的时候可以利用Ray的Actor来拉起模型训练的worker和server节点。如果worker或者server节点处于不健康状态,我们就可以利用Actor的容错特性通过血缘关系来对数据和计算进行恢复,从而实现容错的训练。 我们比较追求链路的时效性,模型能够尽快的拟合实时数据里。但是追求时效性的同时也要保证整个链路的稳定性,在敏捷和敏感之间达到平衡。我们从三个方面,系统稳定性、模型稳定性、机制稳定性来保障整个链路的稳定性。 系统稳定性,里面包括数据实时性和强一致性保障。模型稳定性,我们希望设计的模型能够拟合实时数据流,但同时要防止在线学习链路在各种不确定性因素下,如数据噪音,造成的效果退化。因此我们需要考虑在线特征和离线特征的组合,在模型设计上需要考虑到深层模型和浅层模型对数据的敏感性和噪音的容忍度。机制稳定性,赛马机制、快速回滚策略。除了之前用Ray来实现融合以及它带来的好处,我们也做了非常多的模块建设,TF融合、稳定性保障、样本回流、延迟样本修正、数据共享、流批一体、端到端强一致、模型增量导出。我们把这个平台上线了支付宝的几个场景,从下面的几个数字可以一探效果: 99.9%的全链路SLA业务指标有2%到40%的提升几十分钟模型延迟到4、5分钟,并且可以根据业务的需求进一步降低机器使用降低了60%我们从去年8月份开始建设,今年2月份开始上线第一个场景,在支付线财富线也都取得了不错的效果,接下来我们会推广到蚂蚁金服的其他业务线上。 基于融合计算机器学习,它是融合计算和机器学习这两种模式的有机组合,实现优化资源共享。我们通过这两方面的探索初步验证了融合计算的框架,融合计算是旨在数据共享来进行计算模式的兼容,融合的本质是开放,开放的基础是实现数据的互通,只要我们能够方便的实现各模式之间的数据互通,并且能够保障它们数字的实时性和端到端的一致性,就可以实现复杂场景里面需要多种模式进行组合的计算。模块的衔接就像搭乐高积木一样,基本的模块可能只有几种,但是搭建出复杂且多变的系统。 阿里云双11领亿元补贴,拼手气抽iPhone 11 Pro、卫衣等好礼,点此参与:http://t.cn/Ai1hLLJT 本文作者:缪克卢汉 阅读原文 本文为云栖社区原创内容,未经允许不得转载。

November 4, 2019 · 1 min · jiezi

Solo支付宝开源的Android专项测试工具

1.前言近年来,随着移动互联网的蓬勃发展,移动测试技术也取得了长足的进步,从早期基于测试脚本的单机自动化,到录制回放、图像识别、云测平台等测试技术贴合实际业务需求深度应用和创新,测试效率从而一次又一次被提升。 本文主要介绍支付宝在移动端上实现的一套无线化、非侵入、免 Root 的 Android 专项测试方案 Solo。直接操控手机,即可实现自动化的功能、性能、兼容性、以及稳定性测试等工作。 1.1 移动测试 1.0 时代 移动测试 1.0 时代,也可以称之为探索期。由于厌倦了日复一日的手工操作,如何提升测试效率成为了移动测试领域最重要的课题,在此期间,除了 Monkey、UiAutomator、Instruments 等官方提供的工具,业界还涌现了一批优秀的开源自动化测试工具/框架,在自动化驱动能力的基础之上,不仅可以实现基本功能的验证,还可以结合性能采集方案、遍历算法等实现各类专项测试的自动化。在这个阶段,自动化测试的常见形态是在单机或本地少数几台 PC 上部署测试环境,再利用 Jenkins 等工具实现持续集成。 1.2 移动测试 2.0 时代 伴随着测试技术的持续发展、又得益于 STF 的开源,业界开始出现了云测平台的概念,将真机设备、任务管理、自动化框架以及专项测试方案打包在平台中作为服务提供出去,给用户带来了一站式的测试体验。另一方面,远程调试、设备调度等技术的引入极大的提升了设备的利用率,测试人员不再需要为缺少测试设备或测试任务排队耗时而担心。对于云测平台用户而言,在此阶段常见的测试形态是:在本地 PC 上开发测试脚本,再上传至云测平台执行,最后可在平台中查看测试报告,测试流程简单且清晰。 1.3 移动测试 2.0+ 在保留了上述“云测”的玩法之外,移动测试 2.0+ 时代下的测试技术提供的往往不再是某一个独立的小工具,更多的是带来一套完整的解决方案,例如为用户提供一套定制化的 IDE 环境,结合录制回放、图像识别等技术,用户可能只需要做一些简单的框选、拖拽就能完成测试脚本的开发。另一方面,由于办公环境、硬件条件等因素的限制,越来越多的测试人员希望可以在移动端上直接发起测试,做到移动测试“移动测”。当然,无论是云端、IDE 端、还是移动端,都应该做到能力互通,即“多端多通”,这样才能让测试方案更加灵活、适用于更多场景。 2.无线驱动的Android专项测试方案:Solo“多端多通”的概念比较广,仅凭一篇文章可能无法阐述清楚,所以下面将会重点介绍为了迎接“移动 2.0+”时代,我们在移动端上实现的一套无线化、非侵入、免 Root 的 Android 专项测试方案 Solo。直接操控手机,即可实现自动化的功能、性能、兼容性、以及稳定性测试等工作。 2.1 整体架构 这套方案中,底层依赖主要是“无线 ADB、系统辅助功能、Chrome 调试以及图像识别技术”,后文将会介绍它们具体的应用场景。同时,在底层依赖的基础上,我们封装了一套核心能力,由“控件定位、事件驱动、性能采集以及依赖注入”组成,并在服务层实现了录制、回放、数据处理等公共服务能力。在架构的最顶端,结合界面交互逻辑包装出了各个功能的入口。 2.2 无线 ADB 大家都知道,对于 Android 自动化,ADB shell 的执行能力是一切的基础。 在 PC 上,通过 Android SDK 提供的ADB client 与同样运行于 PC 中的 ADB server 通信,再由 ADB server 通过 USB 与位于设备中的 Adbd 通信。要实现一套无线化的方案,必须要摆脱对 USB 线的依赖。好在 Android 系统还提供了一种基于 Socket 的 ADB 连接模式,既然是这样,那么只需要按照 ADB 通信协议在端上与本机的 5555 端口进行通信即可获得 ADB shell 的执行能力。 ...

July 12, 2019 · 2 min · jiezi

ShardingSphere-x-Seata一致性更强的分布式数据库中间件

日前,分布式数据库中间件 ShardingSphere 将 Seata 分布式事务能力进行整合,旨在打造一致性更强的分布式数据库中间件。 背景数据库领域,分布式事务的实现主要包含:两阶段的 XA 和 BASE 柔性事务。XA 事务底层,依赖于具体的数据库厂商对 XA 两阶段提交协议的支持。通常,XA 协议通过在 Prepare 和 Commit 阶段进行 2PL(2 阶段锁),保证了分布式事务的 ACID,适用于短事务及非云化环境(云化环境下一次 IO 操作大概需要 20ms,两阶段锁会锁住资源长达 40ms,因此热点行上的事务的 TPS 会降到 25/s 左右,非云化环境通常一次 IO 只需几毫秒,因此锁热点数据的时间相对较低)。 但在 BASE 柔性事务方面,ShardingSphere 提供的接入分布式事务的 SPI,只适用于对性能要求较高,对一致性要求比较低的业务。 Seata 核心的 AT 模式适用于构建于支持本地 ACID 事务的关系型数据库。通过整合 Seata,其 AT 模式在一阶段提交+补偿的基础上,通过 TC 的全局锁实现了 RC 隔离级别的支持,可提高 ShardingSphere 的分布式事务的一致性。 整合方案整合 Seata AT 事务时,需要把 TM,RM,TC 的模型融入到 ShardingSphere 分布式事务的 SPI 的生态中。在数据库资源上,Seata 通过对接 DataSource 接口,让 JDBC 操作可以同 TC 进行 RPC 通信。同样,ShardingSphere 也是面向 DataSource 接口对用户配置的物理 DataSource 进行了聚合,因此把物理  DataSource 二次包装为 Seata 的 DataSource 后,就可以把 Seata AT 事务融入到 ShardingSphere 的分片中。 ...

July 4, 2019 · 1 min · jiezi

蚂蚁金服大规模分布式事务实践和开源详解-GIAC-实录

本文整理自蚂蚁金服技术专家、分布式事务 Seata 发起者之一张森(花名:绍辉)在 GIAC 全球互联网架构大会的分享。详细讲解了在分布式架构演进中,蚂蚁金服面对的跨服务、跨数据库的业务数据一致性问题以及应对措施,并分享了分布式事务 Seata 的 AT、TCC、Saga 和 XA 四种模式。 Seata:https://github.com/seata/seata 一、自研分布式事务解决数据一致性问题1.1 分布式事务问题产生原因1.1.1 数据库的水平拆分蚂蚁金服的业务数据库起初是单库单表,但随着业务数据规模的快速发展,数据量越来越大,单库单表逐渐成为瓶颈。所以我们对数据库进行了水平拆分,将原单库单表拆分成数据库分片。 如下图所示,分库分表之后,原来在一个数据库上就能完成的写操作,可能就会跨多个数据库,这就产生了跨数据库事务问题。 1.1.2 业务服务化拆分在业务发展初期,“一块大饼”的单业务系统架构,能满足基本的业务需求。但是随着业务的快速发展,系统的访问量和业务复杂程度都在快速增长,单系统架构逐渐成为业务发展瓶颈,解决业务系统的高耦合、可伸缩问题的需求越来越强烈。 如下图所示,蚂蚁金服按照面向服务(SOA)的架构的设计原则,将单业务系统拆分成多个业务系统,降低了各系统之间的耦合度,使不同的业务系统专注于自身业务,更有利于业务的发展和系统容量的伸缩。 业务系统按照服务拆分之后,一个完整的业务往往需要调用多个服务,如何保证多个服务间的数据一致性成为一个难题。 1.2 蚂蚁金服遇到的数据一致性问题在数据库水平拆分、服务垂直拆分之后,一个业务操作通常要跨多个数据库、服务才能完成。在分布式网络环境下,我们无法保障所有服务、数据库都百分百可用,一定会出现部分服务、数据库执行成功,另一部分执行失败的问题。 当出现部分业务操作成功、部分业务操作失败时,业务数据就会出现不一致。以金融业务中比较常见的“转账”场景为例: 如下图所示,在支付宝的“转账”操作中,要分别完成 4 个动作: 创建交易订单;创建支付订单;A 账户扣钱;B 账户加钱;而完成以上操作要分别访问 3 个服务和 4 个数据库。 在分布式环境下,肯定会出现部分操作成功、部分操作失败的问题,比如:A 账户的钱扣了,但是 B 账户的钱没加上,这就造成了资金损失,影响资金安全。 在金融业务场景下,我们必须保证“转账”的原子性,要么所有操作全部成功,要么全部失败,不允许出现部分成功部分失败的现象。 为了解决跨数据库、跨服务的业务数据一致性问题,蚂蚁金服自主研发了分布式事务中间件。 从 2007 年开始做分布式事务并支持双十一,至今已经有 12 年。 2013 年,蚂蚁金服开始做单元化改造,分布式事务也开始支持 LDC、异地多活和高可用容灾,解决了机房故障情况下服务快速恢复的问题。 2014 年,蚂蚁金服分布式事务中间件 DTX(Distributed Transaction-eXtended)开始通过蚂蚁金融云对外输出,我们发展了一大批的外部用户。在发展外部客户的过程中,外部客户表示愿意牺牲一部分性能(无蚂蚁的业务规模)以换取接入便利性和无侵入性。所以在 2015 年,我们开始做无侵入的事务解决方案:FMT 模式和 XA 模式。 蚂蚁金服分布式事务(Distributed Transaction-eXtended,简称 DTX)链接:https://tech.antfin.com/products/DTX 二、投入开源社区,共建开源分布式事务 Seata2.1 分布式事务 Seata 介绍Seata(Simple Extensible Autonomous Transaction Architecture,简单可扩展自治事务框架)是 2019 年 1 月份蚂蚁金服和阿里巴巴共同开源的分布式事务解决方案。Seata 开源半年左右,目前已经有接近一万 star,社区非常活跃。我们热忱欢迎大家参与到 Seata 社区建设中,一同将 Seata 打造成开源分布式事务标杆产品。 ...

July 3, 2019 · 3 min · jiezi

SOFAJRaft-线性一致读实现剖析-SOFAJRaft-实现原理

SOFAStackScalable Open Financial Architecture Stack是蚂蚁金服自主研发的金融级分布式架构,包含了构建金融级云原生架构所需的各个组件,是在金融场景里锤炼出来的最佳实践。 本文为《剖析 | SOFAJRaft 实现原理》第三篇,本篇作者米麒麟,来自陆金所。《剖析 | SOFAJRaft 实现原理》系列由 SOFA 团队和源码爱好者们出品,项目代号:<SOFA:JRaftLab/>,目前领取已经完成,感谢大家的参与。 SOFAJRaft 是一个基于 Raft 一致性算法的生产级高性能 Java 实现,支持 MULTI-RAFT-GROUP,适用于高负载低延迟的场景。 SOFAJRaft :https://github.com/sofastack/sofa-jraft 前言线性一致读是在分布式系统中实现 Java volatile 语义,当客户端向集群发起写操作的请求并且获得成功响应之后,该写操作的结果要对所有后来的读请求可见。实现线性一致读常规手段是走 Raft 协议,将读请求同样按照 Log 处理,通过日志复制和状态机执行获取读结果返回给客户端,SOFAJRaft 采用 ReadIndex 替代走 Raft 状态机的方案。本文将围绕 Raft Log Read,ReadIndex Read 以及 Lease Read 等方面剖析线性一致读原理,阐述 SOFAJRaft 如何使用 ReadIndex 和 Lease Read 实现线性一致读: 什么是线性一致读?共识算法只能保证多个节点对某个对象的状态是一致的,以 Raft 为例只能保证不同节点对 Raft Log 达成一致,那么 Log 后面的状态机的一致性呢?基于 ReadIndex 和 Lease Read 方式 SOFAJRaft 如何实现高效的线性一致读?线性一致读什么是线性一致读? 所谓线性一致读,一个简单的例子是在 t1 的时刻我们写入了一个值,那么在 t1 之后,我们一定能读到这个值,不可能读到 t1 之前的旧值(想想 Java 中的 volatile 关键字,即线性一致读就是在分布式系统中实现 Java volatile 语义)。简而言之是需要在分布式环境中实现 Java volatile 语义效果,即当 Client 向集群发起写操作的请求并且获得成功响应之后,该写操作的结果要对所有后来的读请求可见。和 volatile 的区别在于 volatile 是实现线程之间的可见,而 SOFAJRaft 需要实现 Server 之间的可见。 如上图 Client A、B、C、D 均符合线性一致读,其中 D 看起来是 Stale Read,其实并不是,D 请求横跨 3 个阶段,而 Read 可能发生在任意时刻,所以读到 1 或 2 都行。 Raft Log read实现线性一致读最常规的办法是走 Raft 协议,将读请求同样按照 Log 处理,通过 Log 复制和状态机执行来获取读结果,然后再把读取的结果返回给 Client。因为 Raft 本来就是一个为了实现分布式环境下线性一致性的算法,所以通过 Raft 非常方便的实现线性 Read,也就是将任何的读请求走一次 Raft Log,等此 Log 提交之后在 apply 的时候从状态机里面读取值,一定能够保证这个读取到的值是满足线性要求的。 当然,因为每次 Read 都需要走 Raft 流程,Raft Log 存储、复制带来刷盘开销、存储开销、网络开销,走 Raft Log不仅仅有日志落盘的开销,还有日志复制的网络开销,另外还有一堆的 Raft “读日志” 造成的磁盘占用开销,导致 Read 操作性能是非常低效的,所以在读操作很多的场景下对性能影响很大,在读比重很大的系统中是无法被接受的,通常都不会使用。 在 Raft 里面,节点有三个状态:Leader,Candidate 和 Follower,任何 Raft 的写入操作都必须经过 Leader,只有 Leader 将对应的 Raft Log 复制到 Majority 的节点上面认为此次写入是成功的。所以如果当前 Leader 能确定一定是 Leader,那么能够直接在此 Leader 上面读取数据,因为对于 Leader 来说,如果确认一个 Log 已经提交到大多数节点,在 t1 的时候 apply 写入到状态机,那么在 t1 后的 Read 就一定能读取到这个新写入的数据。 那么如何确认 Leader 在处理这次 Read 的时候一定是 Leader 呢?在 Raft 论文里面,提到两种方法: ReadIndex ReadLease ReadReadIndex Read第一种是 ReadIndex Read,当 Leader 需要处理 Read 请求时,Leader 与过半机器交换心跳信息确定自己仍然是 Leader 后可提供线性一致读: Leader 将自己当前 Log 的 commitIndex 记录到一个 Local 变量 ReadIndex 里面;接着向 Followers 节点发起一轮 Heartbeat,如果半数以上节点返回对应的 Heartbeat Response,那么 Leader就能够确定现在自己仍然是 Leader;Leader 等待自己的 StateMachine 状态机执行,至少应用到 ReadIndex 记录的 Log,直到 applyIndex 超过 ReadIndex,这样就能够安全提供 Linearizable Read,也不必管读的时刻是否 Leader 已飘走;Leader 执行 Read 请求,将结果返回给 Client。使用 ReadIndex Read 提供 Follower Read 的功能,很容易在 Followers 节点上面提供线性一致读,Follower 收到 Read 请求之后: Follower 节点向 Leader 请求最新的 ReadIndex;Leader 仍然走一遍之前的流程,执行上面前 3 步的过程(确定自己真的是 Leader),并且返回 ReadIndex 给 Follower;Follower 等待当前的状态机的 applyIndex 超过 ReadIndex;Follower 执行 Read 请求,将结果返回给 Client。不同于通过 Raft Log 的 Read,ReadIndex Read 使用 Heartbeat 方式来让 Leader 确认自己是 Leader,省去 Raft Log 流程。相比较于走 Raft Log 方式,ReadIndex Read 省去磁盘的开销,能够大幅度提升吞吐量。虽然仍然会有网络开销,但是 Heartbeat 本来就很小,所以性能还是非常好的。 Lease Read虽然 ReadIndex Read 比原来的 Raft Log Read 快很多,但毕竟还是存在 Heartbeat 网络开销,所以考虑做更进一步的优化。Raft 论文里面提及一种通过 Clock + Heartbeat 的 Lease Read 优化方法,也就是 Leader 发送 Heartbeat 的时候首先记录一个时间点 Start,当系统大部分节点都回复 Heartbeat Response,由于 Raft 的选举机制,Follower 会在 Election Timeout 的时间之后才重新发生选举,下一个 Leader 选举出来的时间保证大于 Start+Election Timeout/Clock Drift Bound,所以可以认为 Leader 的 Lease 有效期可以到 Start+Election Timeout/Clock Drift Bound 时间点。Lease Read 与 ReadIndex 类似但更进一步优化,不仅节省 Log,而且省掉网络交互,大幅提升读的吞吐量并且能够显著降低延时。 Lease Read 基本思路是 Leader 取一个比 Election Timeout 小的租期(最好小一个数量级),在租约期内不会发生选举,确保 Leader 不会变化,所以跳过 ReadIndex 的第二步也就降低延时。由此可见 Lease Read 的正确性和时间是挂钩的,依赖本地时钟的准确性,因此虽然采用 Lease Read 做法非常高效,但是仍然面临风险问题,也就是存在预设的前提即各个服务器的 CPU Clock 的时间是准的,即使有误差,也会在一个非常小的 Bound 范围里面,时间的实现至关重要,如果时钟漂移严重,各个服务器之间 Clock 走的频率不一样,这套 Lease 机制可能出问题。 ...

July 2, 2019 · 1 min · jiezi

网易云信Duilib开发实践和Windows应用界面开发框架源码开源介绍

序言 Duilib介绍Duilib是windows平台下的一款轻量级directUI开源库(遵循BSD协议),完全免费,可用于商业软件开发,只需在软件包里附上协议文件即可。Duilib可以简单方便地实现大多数界面需求,包括换肤、换色,透明等功能,支持多种图片格式,使用XML可以方便地定制窗口,能较好地做到UI和逻辑相分离,尽量减少在代码里创建UI控件。目前,Duilib库已经渐趋稳定,目前在国内有较为广泛的使用,网络上也有很多的使用教程。 网易云信Duilib介绍Duilib是在研发易信PC版时被引入,历经六七年的研发过程,相对于原版Duilib,网易云信Duilib修复了一些问题和不足,包括但不限于控件种类不丰富、不支持动画、不支持半透明异形窗体、对多线程支持不好等,目前,网易云信Duilib配合比较高效的引擎库Base解决多线程问题,可以做出功能更强更稳定的客户端界面。 网易云信Duilib特色多国语言支持通用样式支持DPI 缩放支持GIF 动画支持CEF 控件支持(CEF 2623 支持 XP)触控设备支持(Surface、Wacom)抽象渲染接口(为其他渲染引擎提供支持) 源码使用克隆项目到你的磁盘中git clone https://github.com/netease-im...进入 NIM_Duilib_Framework/samples 目录,使用 Visual Studio 2013 Update 5 以上版本 IDE 打开 samples.sln。 工程目录结构bin输出目录docs 文档libs 静态库samples 示例Demo程序third_party 第三方库toolkits ─ base 基础类库 ─ duilib 核心代码 ─ shared 工具类库 ─ ui_components 组件库 模块介绍Bin:输出目录,各个示例程序输出目录,包含预设的皮肤和语言文件以及 CEF 依赖。Docs:文档,duilib 接口的说明文档。Libs:静态库,静态库编译后的输出目录,包含预设的一些 CEF 组件静态库。Samples:示例Demo程序。Third_party:第三方库,目前仅有 cef_control 有依赖。Base:基础类库,提供了基本框架Messageloops,闭包,基本函数库(file、network等),基本类库(time,线程,定时器等),基本工具库(log,加解密)等。Duilib:duilib 核心代码,依赖 base 但不依赖 shared。Shared:工具共享库,对base库,第三方库做的简单的封装,如命令行解析、日志、路径处理,供其他模块使用。ui_components:组件库,基于 duilib 封装的常用组件库如 msgbox、toast、cef_control 等。 控件介绍容器容器可作为容器控件的介质,包含常用的水平布局和垂直布局等容器。在一个程序界面开始设计前首先要考虑整个界面的布局,这就要用到容器。不同的容器有不同的布局样式,以下为支持的容器类型,可根据自己需要选择进行布局。Box 自由布局容器HBox 水平布局容器VBox 垂直布局容器TabBox 多标签布局容器TileBox 格子布局容器ScrollableBox 带有滚动条的布局容器ChildBox 子布局容器列表此目录下包含一些列表容器,方便管理同类型的多份数据,以下列举了可用的列表容器。Combo 下拉列表ListBox 普通列表TreeView 属性列表VirtualListBox 虚拟列表控件控件包含了所有可用的独立控件,如按钮、文本、进度条等,提供用户输入或输出内容提供使用者查看。以下列举了所有可用的控件列表。Window 用于容纳所有控件的窗口,这里暂时放到控件分类中Control 所有控件的基类,包含了控件的基本属性和接口Button 按钮控件CheckBox 复选框Option 单选框Label 文本Progress 进度条Slider 滑动条RichEdit 富文本ScrollBar 滚动条CefControl CEF 控件盒子盒子通常用于容纳一组不同的控件但由整个盒子统一响应用户触发的事件。不同于普通的容器或普通的控件,它们具有容器的基本布局功能,也具备控件的事件响应机制。一般用于列表中显示一个子项,或者树形列表中显示一个节点,但这些子项和节点可能包含丰富的图标和文字描述并要求可以响应用户触发的事件。在这种场景下就会使用到这些盒子了,以下为支持的盒子模型:ListContainerElement 常用于列表中显示一个子项TreeNode 常用于树形列表中显示一个子节点Other 一些其他的盒子模型工具DPI Manager DPI 管理Muilt Language 多语言管理Shadow 阴影管理Window Base 窗口基础帮助类 ...

June 26, 2019 · 1 min · jiezi

BERT和ERNIE谁更强这里有一份4大场景的细致评测

BERT和ERNIE,NLP领域近来最受关注的2大模型究竟怎么样?刚刚有人实测比拼了一下,结果在中文语言环境下,结果令人意外又惊喜。具体详情究竟如何?不妨一起围观下这篇技术评测。 写在前面随着2018年ELMo、BERT等模型的发布,NLP领域终于进入了“大力出奇迹”的时代。采用大规模语料上进行无监督预训练的深层模型,在下游任务数据上微调一下,即可达到很好的效果。曾经需要反复调参、精心设计结构的任务,现在只需简单地使用更大的预训练数据、更深层的模型便可解决。 随后在2019年上半年,百度的开源深度学习平台PaddlePaddle发布了知识增强的预训练模型ERNIE,ERNIE通过海量数据建模词、实体及实体关系。相较于BERT学习原始语言信号,ERNIE直接对先验语义知识单元进行建模,增强了模型语义表示能力。 简单来说,百度ERNIE采用的Masked Language Model是一种带有先验知识Mask机制。可以在下图中看到,如果采用BERT随机mask,则根据后缀“龙江”即可轻易预测出“黑”字。引入了词、实体mask之后,“黑龙江”作为一个整体被mask掉了,因此模型不得不从更长距离的依赖(“冰雪文化名城”)中学习相关性。 除此之外,百度ERNIE还引入了DLM(对话语言模型)任务,通过这种方式来学习相同回复对应的query之间的语义相似性。实验证明DLM的引入对LCQMC(文本相似度计算)系列任务带来了较大的帮助。最终ERNIE采用多源训练数据,利用高性能分布式深度学习平台PaddlePaddle完成预训练。 亲测到底百度ERNIE模型所引入训练机制有没有起到作用,只有实践了以后才知道。为此,我亲自跑了BERT和ERNIE两个模型,在下面的几个场景中得到了预测结果。 2.1 完形填空完形填空任务与预训练时ERNIE引入的知识先验Mask LM任务十分相似。从下图的比较中我们可以看到,ERNIE对实体词的建模更加清晰,对实体名词的预测比BERT更准确。例如BERT答案“周家人”融合了相似词语“周润发”和“家人”结果不够清晰;“市关村”不是一个已知实体;“菜菜”的词边界是不完整的。ERNIE的答案则能够准确命中空缺实体。 2.2 NER (命名实体识别)在同样为token粒度的NER任务中,知识先验Mask LM也带来了显著的效果。对比MSRA-NER数据集上的F1 score表现,ERNIE与BERT分别为93.8%、92.6%。在PaddleNLP的LAC数据集上,ERNIE也取得了更好的成绩,测试集F1为92.0%,比BERT的结果90.3%提升了1.7%。分析二者在MSRA-NER测试数据中二者的预测结果。可以观察到: 1.)ERNIE对实体理解更加准确:“汉白玉”不是实体类型分类错误; 2.)ERNIE对实体边界的建模更加清晰:“美国法律所”词边界不完整,而“北大”、“清华”分别是两个机构。 Case对比:摘自MSRA-NER数据测试集中的三段句子。B_LOC/I_LOC为地点实体的标签,B_ORG/L_ORG为机构实体的标签,O为无实体类别标签。下表分别展现了 ERNIE、BERT模型在每个字上的标注结果。 2.3 相似度ERNIE在训练中引入的DLM能有效地提升模型对文本相似度的建模能力。因此,我们比较文本相似度任务LCQMC数据集上二者的表现。从下表的预测结果可以看出,ERNIE学习到了中文复杂的语序变化。最终ERNIE与BERT在该任务数据的预测准确率为87.4%、87.0%. 2.4 分类 最后,比较应用最广泛的情感分类任务。经过预训练的ERNIE能够捕捉更加细微的语义区别,这些句子通常含有较委婉的表达方式。下面展示了PaddleNLP情感分类测试集上ERNIE与BERT的打分表现:在句式“不是很…”中含有转折关系,ERNIE能够很好理解这种关系,将结果预测为“消极”。在ChnSentiCorp情感分类测试集上finetune后ERNIE的预测准确率为95.4%,高于BERT的准确率(94.3%)。 从以上数据我们可以看到,ERNIE在大部分任务上都有不俗的表现。尤其是在序列标注、完形填空等词粒度任务上,ERNIE的表现尤为突出,不输给Google的BERT。

June 17, 2019 · 1 min · jiezi

滴滴开源-Rdebug基于真实流量的研发调试测试利器

出品 | 滴滴技术 前言:近日,滴滴在 GitHub 上开源后端研发、调试、测试的实用工具 Rdebug,全称 Real Debugger,中文称作真 · Debugger 。使用真实的线上流量进行线下回放测试,提升研发效率、保障代码质量,进而减少事故。一起来具体了解吧。 ▍背景随着微服务架构的普及和应用,一个复杂的单体服务通常会被拆分成多个小而美的微服务。在享受微服务带来便利的同时,也要接受因为微服务改造带来的问题:需要维护的服务数变多、服务之间 RPC 调用次数增加。 这就造成线下环境维护成本大大增加,其次线下环境涉及到的部门较多,维护一个长期稳定的线下环境也是一个挑战;业务快速发展、需求不断迭代,手写单测又因复杂的业务逻辑以及复杂的服务调用需要 mock 多个下游服务,导致手写和维护单测成本特别的高;手动构造数据,又不够全面真实。以上问题都严重影响 RD 的研发效率,并且增加线上产生事故的隐患。 RD 迫切需要一个只需在本地部署代码、不用搭建下游依赖、使用真实数据,进行快速开发、调试、测试的解决方案。Rdebug 基于流量录制、流量回放的思路,能够巧妙的实现上述方案。 ▍宗旨提升研发效率、降低测试成本、缩短产品研发周期,保障代码质量、减少线上事故。 ▍使用全景图 ▍全新的研发体验只需部署模块代码,无需搭建下游服务;在 macOS 本地回放,开发、调试、测试无需登录远程服务器;流量录制支持常用协议,FastCGI、HTTP、Redis、Thrift、MySQL 等;回放速度快,单次回放秒级别。 ▍录路径重定向为了方便 RD 在本地开发、测试,Rdebug 支持路径重定向。 当线上部署路径和本地代码路径不一致时,当代码中存在大量线上路径硬编码时,无需入侵式修改代码,只需要简单的配置即可实现路径重定向。 即代码可以存放在任何路径下回放。 ▍时间偏移流量回放时会自动把时间偏移到流量录制的时间点。 在代码中获取时间时,会获得录制时间点之后的时间。所以,当业务接口对时间敏感时,也无需担心。 ▍文件 Mock流量回放支持文件 Mock,指定文件路径和 Mock 的内容,即可快速实现文件 Mock。结合录制上报功能,在线上上报配置读取,在线下使用文件Mock实现配置“重现”。 ▍Elastic 搜索对存储在 Elastic 中的流量,支持 URI、输入输出关键词、下游调用等多维度搜索。回放支持指定文件,也支持上述搜索回放,使用体验更佳。 ▍Xdebug 调试最高效的功能是 Xdebug 联动调试,通过对代码设置断点即可使用线上流量进行调试。通过这种方式,可以用来研究代码、排查问题、查看下游接口响应格式及数据等,是一个开发调试利器。 ▍丰富的报告回放报告,汇总线上线下的输入、输出、结果对比,一目了然。 下游调用报告,会列举出所有的下游调用,包括协议、请求内容、匹配上的响应以及相识度。通过不同的背景颜色,标记出完全匹配的流量、存在噪点的调用、缺失的调用、新增的调用等。 结合 Xdebug 生成覆盖率报告,能够清楚的看到哪些代码被执行、哪些代码未被执行以及接口的覆盖率情况。 有关安装、使用过程以及常见问题解答,请查看以下链接:GitHub:https://github.com/didi/rdebugWiki:https://github.com/didi/rdebu...Documentation:https://github.com/didi/rdebu... 同时欢迎加入「Rdebug 用户交流群」请在滴滴技术公众号后台回复「Rdebug」即可加入 ...

June 3, 2019 · 1 min · jiezi

宜信开源微服务任务调度平台SIATASK

背景无论是互联网应用或者企业级应用,都充斥着大量的批处理任务。常常需要一些任务调度系统帮助开发者解决问题。随着微服务化架构的逐步演进,单体架构逐渐演变为分布式、微服务架构。在此的背景下,很多原先的任务调度平台已经不能满足业务系统的需求。于是出现了一些基于分布式的任务调度平台。这些平台各有其特点,但各有不足之处,比如不支持任务编排、与业务高耦合、不支持跨平台等问题。非常不符合新一代微服务架构的需求,因此宜信公司开发了微服务任务调度平台(SIA-TASK)。 SIA是宜信公司基础开发平台Simple is Awesome的简称,SIA-TASK(微服务任务调度平台)是其中的一项重要产品,SIA-TASK契合当前微服务架构模式,具有跨平台,可编排,高可用,无侵入,一致性,异步并行,动态扩展,实时监控等特点。 项目简介SIA-TASK是任务调度的一体式解决方案。对任务进行元数据采集,然后进行任务可视化编排,最终进行任务调度,并且对任务采取全流程监控,简单易用。对业务完全无侵入,通过简单灵活的配置即可生成符合预期的任务调度模型。 SIA-TASK借鉴微服务的设计思想,获取分布在每个任务执行器上的任务元数据,上传到任务注册中心。利用在线方式进行任务编排,可动态修改任务时钟,采用HTTP作为任务调度协议,统一使用JSON数据格式,由调度中心进行时钟解析,执行任务流程,进行任务通知。 关键术语任务(Task): 基本执行单元,执行器对外暴露的一个HTTP调用接口;作业(Job): 由一个或者多个存在相互逻辑关系(串行/并行)的任务组成,任务调度中心调度的最小单位;计划(Plan): 由若干个顺序执行的作业组成,每个作业都有自己的执行周期,计划没有执行周期;任务调度中心(Scheduler): 根据每个的作业的执行周期进行调度,即按照计划、作业、任务的逻辑进行HTTP请求;任务编排中心(Config): 编排中心使用任务来创建计划和作业;任务执行器(Executer): 接收HTTP请求进行业务逻辑的执行;Hunter:Spring项目扩展包,负责执行器中的任务抓取,上传注册中心,业务可依赖该组件进行Task编写。微服务任务调度平台的特性基于注解自动抓取任务,在暴露成HTTP服务的方法上加入@OnlineTask注解,@OnlineTask会自动抓取方法所在的IP地址,端口,请求路径,请求方法,请求参数格式等信息上传到任务注册中心(zookeeper),并同步写入持久化存储中,此方法即任务;基于注解无侵入多线程控制,单一任务实例必须保持单线程运行,任务调度框架自动拦截@OnlineTask注解进行单线程运行控制,保持在一个任务运行时不会被再次调度。而且整个控制过程对开发者完全无感知。调度器自适应任务分配,任务执行过程中出现失败,异常时。可以根据任务定制的策略进行多点重新唤醒任务,保证任务的不间断执行。高度灵活任务编排模式,SIA-TASK的设计思想是以任务为原子,把多个任务按照执行的关系组合起来形成一个作业。同时运行时分为任务调度中心和任务编排中心,使得作业的调度和作业的编排分隔开来,互不影响。在我们需要调整作业的流程时,只需要在编排中心进行处理即可。同时编排中心支持任务按照串行,并行,分支等方式组织关系。在相同任务不同任务实例时,也支持多种调度方式进行处理。微服务任务调度平台设计SIA-TASK主要分为五个部分: 任务执行器任务调度中心任务编排中心任务注册中心(zookeeper)持久存储(Mysql) SIA-TASK的主要运行逻辑: 通过注解抓取任务执行器中的任务上报到任务注册中心任务编排中心从任务注册中心获取数据进行编排保存入持久化存储任务调度中心从持久化存储获取调度信息任务调度中心按照调度逻辑访问任务执行器 UI预览首页提供多维度监控 调度器信息:展示调度器信息(负载能力,预警值),以及作业分布情况。调度信息:展示调度中心触发的调度次数,作业、任务多维度调度统计。对接项目统计:对使用项目的系统进行统计,作业个数,任务个数等等。 调度监控提供对已提交的作业进行实时监控展示。 作业状态实时监控:以项目组为单位面板,展示作业运行时状态。实时日志关联:可以通过涂色状态图标进行日志实时关联展示。 任务管理:提供任务元数据的相关操作 任务元数据录入:手动模式的任务,可在此进行录入。任务连通性测试:提供任务连通性功能测试。任务元数据其他操作:修改,删除。 Job管理:提供作业相关操作 任务编排:进行作业的编排。发布作业: 作业的创建,修改,以及发布。级联设置:提供存在时间依赖的作业设置。 日志管理 本地日志:日志界面简洁,查询快速;日志提供7天的调度日志,以供快速查询。开源地址https://github.com/siaorg/sia-task作者:宜信开发平台负责人/资深架构师梁鑫

May 24, 2019 · 1 min · jiezi

Flutter高内聚组件怎么做阿里闲鱼打造开源高效方案

fish_redux是闲鱼技术团队打造的flutter应用开发框架,旨在解决页面内组件间的高内聚、低耦合问题。开源地址:https://github.com/alibaba/fish-redux 从react_redux说起redux对于前端的同学来说是一个比较熟悉的框架了,fish_redux借鉴了redux单项数据流思想。在flutter上说到redux,大家可能第一反应会类比到react上的react_redux。在react_redux中有个重要的概念——connect, connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])简单得说,connect允许使用者从Redux store中获取数据并绑定到组件的props上,可以dispatch一个action去修改数据。 那么fish_redux中的connector是做什么的呢?为什么说connector解决了组件内聚的问题?我们应该如何理解它的设计呢? connector in fish_redux尽管都起到了连接的作用,但fish_redux与react_redux在抽象层面有很大的不同。 fish_redux本身是一个flutter上的应用框架,建立了自己的component体系,用来解决组件内的高内聚和组件间的低耦合。从connector角度来说,如何解决内聚问题,是设计中的重要考量。 fish_redux自己制造了Component树,Component聚合了state和dispatch,每一个子Component的state通过connector从父Component的state中筛选。如图所示: 可以看到,fish_redux的connector的主要作用把父子Component关联起来,最重要的操作是filter。state从上之下是一个严谨的树形结构,它的结构复用了Component的树形结构。类似一个漏斗形的数据管道,管理数据的分拆与组装。它表达了如何组装一个Component。 而对于react_redux来说,它主要的作用在于把react框架和redux绑定起来,重点在于如何让React component具有Redux的功能。 从图中可以看到,react_redux和React是平行的结构,经过mapStateToProps后的state也不存在严谨的树形结构,即对于一个React component来说,它的state来自于Redux store而不是父component的state。从框架设计的角度来说,react_redux最重要的一个操作就是attach。 源码分析说完概念,我们从源码的角度来看看fish_redux中的connector是如何运作的,以fish_redux提供的example为例。 class ToDoListPage extends Page<PageState, Map<String, dynamic>> { ToDoListPage() : super( ... dependencies: Dependencies<PageState>( adapter: ToDoListAdapter(), slots: <String, Dependent<PageState>>{ 'report': ReportConnector() + ReportComponent() }), ... );}在ToDoListPage的构造函数中,向父类构造传递了一个Dependencies对象,在构造Dependencies时,参数slots中包含了名叫"report"的item,注意这个item的生成,是由一个ReportConnector+ReportComponent产生的。 从这里我们得出一个简单却非常重要的结论: 在fish_redux中,一个Dependent = connector + Component 。Dependent代表页面拼装中的一个单元,它可以是一个Component(通过buildComponent函数产生),也可以是一个Adapter(由buildAdapter函数产生)。这样设计的好处是,对于View拼装操作来说,Dependent对外统一了API而不需要透出更多的细节。 根据上面我们得出的结论,connector用来把一个更小的Component单元链接到一个更大的Component或Adapter上。这与我们之前的描述相符合。 connector到底是什么知道了connector的基本作用,我们来看一下它到底链接了哪些东西以及如何链接。 先来看一下ReportConnector类的定义: class ReportConnector extends ConnOp<PageState, ReportState>ReportConnector继承了ConnOp类,所有connector的操作包括+操作,都来自于ConnOp类。 set/get 既然是数据管道,就会有获取和放置 set函数的入参很好得表达了T和P的意思,即把一个P类型的subState合并到T类型的state中。 ...

May 24, 2019 · 1 min · jiezi

蚂蚁金服开源的机器学习工具-SQLFlow有何特别之处

阿里妹导读:近日,蚂蚁金服副 CTO 胡喜正式宣布开源机器学习工具 SQLFlow,他在大会演讲中表示:“未来三年,AI 能力会成为每一位技术人员的基本能力。我们希望通过开源 SQLFlow,降低人工智能应用的技术门槛,让技术人员调用 AI 像 SQL 一样简单。” SQLFlow 能够抽象出端到端从数据到模型的研发过程,配合底层的引擎及自动优化,具备基础 SQL 知识的技术人员即可完成大部分的机器学习模型训练及预测任务。SQLFlow 由何而来?蚂蚁金服对于 SQLFlow 未来还有哪些规划?一起来深入了解。 SQLFlow 的目标是将 SQL 引擎和 AI 引擎连接起来,让用户仅需几行 SQL 代码就能描述整个应用或者产品背后的数据流和 AI 构造。其中所涉及的 SQL 引擎包括 MySQL、Oracle、Hive、SparkSQL、Flink 等支持用 SQL 或其某个变种语言描述数据,以及描述对数据的操作的系统。而这里所指的 AI 引擎包括 TensorFlow、PyTorch 等深度学习系统,也包括 XGBoost、LibLinear、LibSVM 等传统机器学习系统。 SQLFlow 研发团队认为,在 SQLFlow 和 AI 引擎之间存在一个很大的空隙——如何把数据变成 AI 模型需要的输入。谷歌开源的 TensorFlow 项目开了一个好头,TFX Data Transform 和 feature column API 都是意图填补这个空缺的项目。但是这个空缺很大,是各种 SQL 引擎和各种 AI 引擎的笛卡尔积,远不是 TensorFlow 的这两个子项目就足以填补的,需要一个开源社区才行。要填补好这个空缺,需要先让用户意识到其重要性,这也是蚂蚁金服开源 SQLFlow 的意图之一。 SQLFlow 位于 AI 软件系统生态的最顶端,最接近用户,它也位于数据和数据流软件生态之上。 ...

May 9, 2019 · 3 min · jiezi

如何编写一个企业级区块链Hyperledger-Fabric开源框架

Convector(a.k.a Convector Smart Contracts)是为企业区块链框架构建的JavaScript开发框架。它增强了开发体验,同时帮助开发人员创建更强大,更安全的智能合约系统。它通过链代码和后端一直到前端,允许开发人员以库的形式重用相同的代码库。它基于模型/控制器模式,支持Hyperledger Fabric,并沿着Fabric精心设计的模式本地运行。 这篇博客文章介绍了该项目的历史,并重点介绍了沿途开发的挑战和解决方案。 当我们开始研究Tellus时,一切都开始了,Tellus是一个无代码交易设计师,用于在Hyperledger Fabric区块链上运行。那时我们有一堆Golang智能合约。 我们对开发者体验(DX)的第一印象并不是那么好。有两种方法:init和invoke,除了在invoke方法上放置if条件并使用其中一个参数指示调用的方法之外,没有其他方法可以添加新方法。所有参数都是位置传递的字符串,需要手动解析复杂参数,并且无法在本地测试它。 在项目开始时,Fabric 1.1增加了对Javascript链代码的支持。我们决定尝试一下,希望改善开发人员的体验。不幸的是,它遵循Golang链式代码中的相同模式,你仍然需要在日常逻辑中做一些肮脏的工作。我们一直在寻找更好的解决方案,并发现了一篇关于TheLedger的库的帖子,该文章在Typescript中制作Fabric链接代码,它真正改善了原始Javascript的内容。 在我们的智能合约从Golang迁移到Javascript期间出现了一种模式。大多数时候函数按以下顺序执行: 1.解析参数。2.做一些断言。3.执行更改。4.保存更改。这导致了关于项目计划的一个基本问题:智能合约是否应该快速迁移,或者应该花更多的时间来确定模式并使其足够灵活以适应多个业务案例。这一切都始于项目的./src/utils/。 /** @module @worldsibu/convector-examples-token */import * as yup from ‘yup’;import { ConvectorModel, ReadOnly, Required, Validate} from ‘@worldsibu/convector-core-model’;export class Token extends ConvectorModel { @ReadOnly() public readonly type = ‘io.worldsibu.examples.token’; @ReadOnly() @Required() @Validate(yup.object()) public balances: { [key: string]: number }; @ReadOnly() @Required() @Validate(yup.number().moreThan(0)) public totalSupply: number; @ReadOnly() @Required() @Validate(yup.string()) public name: string; @ReadOnly() @Required() @Validate(yup.string()) public symbol: string;}对流模型Fabric对区块链中存储的数据形状没有限制。你基本上有一个键值映射,其中两个都是字符串,这意味着你可以序列化和存储任何复杂的对象。我们拆开模型以在代码中重用它们。我们刚刚通过了所有必要的参数。 ...

April 25, 2019 · 1 min · jiezi

提升不止一点点,Dubbo 3.0 预览版详细解读

Dubbo 自 2011 年 10 月 27 日开源后,已被许多非阿里系的公司使用,其中既有当当网、网易考拉等互联网公司,也不乏中国人寿、青岛海尔等大型传统企业。更多用户信息,可以访问Dubbo @GitHub,issue#1012: Wanted: who's using dubbo。 自去年 12 月开始,Dubbo 3.0 便已正式进入开发阶段,并备受社区和广大 Dubbo 用户的关注,本文将为您详细解读 3.0 预览版的新特性和新功能。 下面先解答一下两个有意思的与 Dubbo 相关的疑问。 为什么 Dubbo 一开源就是 2.0 版本?之前是否存在 1.0 版本?笔者曾做过 Dubbo 协议的适配兼容,Dubbo 确实存在过 1.x 版本,而且从协议设计和模型设计上都与 2.0 的开源版本协议是完全不一样的。下图是关于 Dubbo 的发展路径: 阿里内部正在使用 Dubbo 开源版本吗?是的,非常确定,当前开源版本的 Dubbo 在阿里巴巴被广泛使用,而阿里的电商核心部门是用的 HSF2.2 版本,这个版本是兼容了 Dubbo 使用方式和 Remoting 协议。当然,我们现在正在做 HSF2.2 的升级,直接依赖开源版本的 Dubbo 来做内核的统一。所以,Dubbo 是得到大规模线上系统验证的分布式服务框架,这一点毋容置疑。 Dubbo 3.0 预览版的要点Dubbo 3.0 在设计和功能上的新增支持和改进,主要是以下四方面: Dubbo 内核之 Filter 链的异步化这里要指出的是,3.0 中规划的异步去阻塞和 2.7 中提供的异步是两个层面的特性。2.7 中的异步是建立在传统 RPC 中 request – response 会话模型上的,而 3.0 中的异步将会从通讯协议层面由下向上构建,关注的是跨进程、全链路的异步问题。通过底层协议开始支持 streaming 方式,不单单可以支持多种会话模型,还可以在协议层面开始支持反压、限流等特性,使得整个分布式体系更具有弹性。综上所述,2.7 关注的异步更局限在点对点的异步(一个 consumer 调用一个 provider),3.0 关注的异步化,宽度上则关注整个调用链上的异步,高度上则向上又可以包装成 Rx 的编程模型。有趣的是,Spring 5.0 发布了对 Flux 的支持,随后开始解决跨进程的异步问题。 ...

April 22, 2019 · 6 min · jiezi

开源|ns4_frame分布式服务框架开发指南

导语:宜信于2019年3月29日正式开源nextsystem4(以下简称“NS4”)系列模块。此次开源的NS4系列模块是围绕当前支付系统笨重、代码耦合度高、维护成本高而产生的分布式业务系统解决方案。NS4系列框架允许创建复杂的流程/业务流,对于业务服务节点的实现可串联,可分布式。其精简、轻量,实现了“脱容器”(不依赖tomcat、jetty等容器)独立运行。NS4系列框架的设计理念是将业务和逻辑进行分离,开发人员只需通过简单的配置和业务实现就可以实现逻辑复杂、性能高效、功能稳定的业务系统。【点击查看框架整体介绍】NS4系列包括4个开源模块,分别是:ns4_frame分布式服务框架、ns4_gear_idgen ID 生成器组件(NS4框架Demo示例)、ns4_gear_watchdog 监控系统组件(服务守护、应用性能监控、数据采集、自动化报警系统)和ns4_chatbot通讯组件。本文将详细介绍ns4_frame分布式服务框架开发指南。项目地址:https://github.com/newsettle/…一、框架介绍ns4_frame本质上是两个应用加三套开发框架组合起来的分布式业务框架。1.1 使用范围ns4_frame分布式框架主要适用于业务类型为消息流或者业务核心模型为流式业务的业务系统。它支持消息分发、传递、追踪,支持分步骤、分批次的消息处理,对于信息流、数据流等消息驱动型的业务尤为契合。1.2 项目结构ns4_frame框架是一套MAVEN父子项目,由五个项目组成:NS_MQ :负责和底层消息队列进行通信,提供了对消息队列进行操作的API。NS_TRANSPORTER:通过调用NS_MQ提供的API,对业务消息进行收取、处理、转发。NS_CHAIN :一个可选开发框架,负责对同一个jvm中的业务处理步骤进行链条式的整合,组成当前业务模块的业务处理流程。NS_CONTROLLER:一个业务消息转发应用,负责将接收到的消息转给对应的业务模块进行处理,同时负责将业务模块根据整体业务进行关联。NS_CONTROLLER本质是一个独立的应用系统,构建于 NS_TRANPORTOR和NS_CHAIN之上。NS_DISPATCHER :ns4_frame架构规定的消息入口,通过提供的http服务接受业务系统边界外的http请求,并将请求转化成业务系统内部通信使用的消息协议格式。二、基础入⻔2.1 开发环境配置开发语言:JAVAJDK版本:JDK1.7MAVEN版本:3.3以上REDIS版本:3.0以上以上是开发环境必备的组件和配置,其中java为开发语言,maven为项目编译打包部署必备, redis作为消息中间件使用。2.2 运行ns4_frame运行至少需要启动三个jvm项目才能完整运行。启动整个项目分为如下三步:第一步: ns4_frame消息入口是一个http接口,http服务是由NS_DISPATCHER项目提供的,所以我们第一件事情就是要把NS_DISPATCHER运行起来。要运行NS_DISPATCHER,直接运行Bootstrap类的main方法即可。 默认的NS_DISPATCHER会在本机(127.0.0.1)的8027端口上监听http请求,如果收到http请求,默认会将http请求转换成内部通信消息,并存储到本机(127.0.0.1)的 redis中,默认访问的redis端口号是6379。第二步: NS_CONTROLLER负责接收NS_DISPATCHER传入的消息,并根据配置进行消息分发。 所以我们随后需要运行NS_CONTROLLER项目(为了方便,以下简称“CONTROLLER”) 。在CONTROLLER项目中我们不能直接运行,需要配置一些东⻄。CONTROLLER要运行至少需要指定一个配置文件位置。这个配置文件需要通过java命令参数来指定。假设我现在指定java运行参数 -Dconfigfile=nscontroller.xml 这个参数本质上是给CONTROLLER底层的NS_TRANSPORTER使用的,它指明了 NS_TRANSPORTER必须得配置文件位置,使得CONTROLLER能顺利利用 NS_TRANSPORTER进行消息收发。默认情况下,CONTROLLER还会到classpath下去找关于NS_CHAIN需要的配置文件, 默认路径是classpath下的nschainconfig目录,在这个目录下所有的xml文件会被认作是NS_CHAIN需要的配置文件集合。当配置文件配置好后,可以通过调用com.creditease.ns.transporter.context.XmlAppTransporterContext的 main方法来启动NS_CONTROLLER 。第三步: 在这个步骤中我们需要启动自己的业务项目,在这个业务项目中,必须有以下三个前置条件:业务项目需要建立在NS_TRANSPORTER框架之上。业务项目的消息队列名称必须和CONTROLLER项目中配置的队列名一致。业务启动必须通过 com.creditease.ns.transporter.context.XmlAppTransporterContext的 main方法来启动。完成以上的三个步骤,一个基本的ns4_frame系统就搭建好并运行起来了。三、项目架构3.1 层次划分上图展示了ns4_frame每个系统的层次结构。底层是以redis作为消息中间件,对消息中间件的操作被封装入了NS_MQ项目,它向上层提供了对消息队列的操作API接口。在NS_MQ的上层是NS_TRANSPORTER,它本质是一套消息收发处理框架,它负责接收消息后反向回调业务代码,并将消息交给业务层处理。当业务层处理完毕后,它负责将处理后的消息返回到redis中。NS_CHAINS是一套开发辅助框架,它负责将一个模块的业务处理步骤解耦成一个个零散的任务,并可以随意以任何顺序做关联。NS_CONTROLLER是一个项目,它本质上是一个独立的应用,它负责将整体业务分解成一个个节点,并通过配置将他们以一定的顺序关联起来,并通过消息机制,将这些节点结合起来 形成一套业务系统。NS_DISPATCHER也是一个项目,它是以NETTY框架作为基础,开发出的一个能提供基本的 http服务的独立应用。同时它也是业务系统和外部通讯的唯一边界。3.2 运行流程ns4_frame整套系统本质上其实就是一套消息中间件服务加开发框架,整体的结构图如下:上图显示了一个ns4_frame整体分布式项目的运行流程,一个消息的运转流程按如下顺序:NS_DISPATCHER收到http请求,并将http请求转化为内部消息协议放入指定的消息队列中(根据配置文件)。NS_CONTORLLER从步骤1指定的队列接收到消息,并根据配置的服务编排开始按照顺序将消息发送到每个服务步骤对应的消息队列中。业务系统收到步骤2中NS_CONTROLLER指定的消息队列接收到消息并开始处理,处理完毕后,将结果返回。NS_CONTROLLER收到业务系统的响应,开始根据配置好的服务,将返回的消息结果发送到下一个服务对应的消息队列中。四、NS_MQ框架介绍4.1 核心类和接口RedisMQTemplate类:封装了所有和消息队列的操作相关的APIMQConfig:存储了所有和底层消息中间件相关的配置。4.2 配置方案默认的,在没有做任何配置的情况下,NS_MQ会自动访问本机(127.0.0.1)的6379端口的redis,如果没有,则会报异常。通常,NS_MQ会去找classpath下一个名为ns_mq.properties的配置文件,这个配置文件中存储着所有和底层消息中间件相关的属性。列举一些关键的配置元素:redis.type 1 代表redis单机 2 代表redis集群 默认为1redis.single/cluster.host redis单机或者集群的主机地址(包含端口)redis.single/cluster.maxTotal redis单机或者集群的最大连接数redis.single/cluster.miniIdle redis单机或者集群的最小闲置连接数redis.single/cluster.maxIdle redis单机或者集群的最大闲置连接数redis.single/cluster.connectionTimeout redis单机或者集群的尝试连接的超时时间(尚未连接到服务需要等待的时间)redis.single/cluster.socketTimeout redis单机或者集群连接后socket闲置的超时时间五、NS_TRANSPORTER框架介绍5.1 框架架构上图展示了整个NS_TRANSPORTER的整体架构,整套框架收发处理消息分为如下三个步骤:首先由接收消息的线程(Fetcher线程)通过NS_MQ从底层消息中间件获取消息并放入到本地消息缓存。消息处理线程(Handler线程)从本地消息缓存中取出消息,并调用业务层的方法实现对消息进行处理,处理完毕后,将处理后的消息放到本地发送缓存。发送线程(Sender线程)从本地发送缓存取出消息后,将消息通过NS_MQ将消息放入底层消息中间件。5.2 核心类和接口ServiceMessage:对各个模块之间传递的消息的java封装,包含了模块间通信需要知道的任何信息;Worker:业务层需要实现此接口的doWork方法,实现此接口的对象会被NS_TRANSPORTER的Handler线程回调用来对ServiceMessage中的信息进行处理。ActionWorker:已经部分封装好的抽象类,实现了Worker接口,业务层可以直接继承这个抽象类,简化开发。5.3 配置方案默认的,NS_TRANSPORTER会去找名为configfile的系统变量,这个系统变量的值就是NS_TRANSPOTER需要的配置文件所在的路径,NS_TRANSPORTER会找到这个xml配置文件,并在解析相关的配置后启动。 NS_TRANSPORTER相关的配置文件模板如下:<queues> <prefix></prefix> <launchers> <launcher><class name=“类的全名” method=“method方法名” property="" /><class name=“类的全名” static-method=“method方法名” /> </launcher> </launchers> <inqueues> <queue> <name></name><fetchernum></fetchernum> <buffersize></buffersize> <handlersize></handlersize> <serviceClass></serviceClass> <sendernum></sendernum> </queue> </inqueues></queues>以上xml模板中有如下几个关键元素需要注意:Launcher:用来定义在整个框架完全运行之前需要执行的方法。queue:在这个元素下 name元素表示需要监听的底层消息中间件的队列名。Fetchernum:表示监听消息队列并获取消息的线程数,默认是1。buffersize:表示本地接收/发送消息队列的大小默认是100。handlersize:表示处理消息的线程数,默认是10。Serviceclass:表示具体的处理消息的业务类,这个类必须实现了Worker接口。Sendernum:表示从本地发送消息队列中获取消息后发送到底层消息中间件的线程数。六、NS_CHAIN框架介绍6.1 框架架构由于NS_CHAIN本质是一个纯开发框架,故暂时忽略此框架的框架架构。6.2 核心类和接口暂略6.3 配置方案本节将详细介绍NS_CHAINS的配置。NS_CHAINS启动时会去找系统变量chainconfig,这个变量的值就是NS_CHAINS配置文件所在的路径。NS_CHAINS支持配置目录(目录下的所有xml格式文件都被视作NS_CHAINS框架的配置文件)和配置文件。 对于NS_CHAINS的配置格式我们大致列举出关键要素如下:catalog:这个相当于一个完整的服务或者一个命名空间,是NS_CHAINS对外服务的基本单位,NS_CHAINS外部系统只能看到catalog。Command:这是NS_CHAINS任务执行的最小单位,所有执行任务都可以以command的形式被调用执行。Chain:这是一个command的容器,可以将多个command的任务组合成一个执行链路。Group:这个一个command的组合,它可以将多个command组合成一个整体,并按照配置顺序执行。同时NS_CHAINS的配置具有完整的逻辑语法,支持if条件判断,while循环结构和顺序结构。七、NS_DISPATCHER应用介绍7.1 框架架构NS_DISPATCHER本质是一个独立的建立在Netty框架上的一个能提供http服务的独立应用,所以框架结构此处从略。7.2 核心类和接口NS_DISPATCHER是以NETTY框架为基础的,所以其核心类就是如下的几个协议处理器:HttpDispatcherServerHandler:主要负责解析传入的http请求,并封装成对应的java对象交给 HttpRPCHandler做进一步处理。HttpRPCHandler:主要接收上一步封装好的java对象,并取出对应的请求参数、请求内容等,封装成系统内部传输用的协议对象,并可以以同步请求响应模式/异步发送模式将协议对象放入底层消息中间件。7.3 配置方案NS_DISPATCHER启动会去找ns_dispatcher.properties文件,下面介绍配置的关键元素:http.port:指定了http服务的监听端口。dispatcher.pool.num:指定了dispatcher的并发线程数,dispatcher的性能和这个参数有非常大的关系。dispatcher.queuename:封装好的内部协议消息要放入的队列的名字,NS_DISPATCHER也支持https,所以,如果在ns_dispatcher.properties文件中有如下几个选项,那么NS_DISPATCHER也会启动对应的https服务。ca.path:指明了可信任证书的路径。key.path:指明了公钥的路径。https.port:指明了https服务监听的端口。八、NS_CONTROLLER应用介绍8.1 框架架构NS_CONTROLLER本质是建立在NS_TRANSPORTER和NS_CHAINS上的独立应用,核心就是 NS_TRANSPORTER的架构加NS_CHAINS的辅助,故不再重复列举其架构。8.2 核心类和接口DefaultPublishCommand:这是NS_CONTROLLER对于NS_CHAINS的一个扩展,它支持同步发送消息,并等待消息的响应,并可以设置等待响应的超时时间。同时,还支持异步发送消息,不需要等待消息的响应。8.3 配置方案遵循NS_TRANSPORTER和NS_CHAINS的配置规则,所以不再赘述。 注意:在NS_CONTROLLER中对于NS_CHAINS的配置做了一些功能扩展,主要是添加了publish的配置元素,这个随后可以提供配置模板。九、项目部署9.1 部署方案如果要部署整个ns4_frame项目,请按照以下步骤进行:部署NS_DISPATCHER项目:NS_DISPATCHER项目是一个Maven项目,首先需要通过mvn:package deploy将整个项目打成一个zip包上传到服务器,然后解压成一个目录。在这个目录中,有如下几个子目录:bin、config、lib、logs。其中,bin目录中包含了DISPATCHER的启动脚本;config目录存放了NS_DISPATCHER必须的配置文件;lib目录存放了NS_DISPATCHER所需要的所有jar包;logs目录存放了所有NS_DISPATCHER打印的日志。部署NS_CONTROLLER项目:NS_CONTROLLER项目也是一个Maven项目,需要通过mvn:package deploy将整个项目打成一个zip包。目录结构同NS_DISPATCHER项目,此处不再赘述。部署业务代码:业务代码请自行按照各个团队的规则部署。十、运行日志10.1 日志分类ns4_frame项目将日志大致分成了四类:fram.log:系统日志,属于整个ns4_frame底层系统内部的日志,包括系统的启动,线程的启动关闭等信息。biz.log:业务日志,所有业务相关的日志统统会被导向到这里。flow.log:消息流日志,这里记录了系统所有消息的流转信息。mq.log:这里记录所有对底层消息中间件进行操作的信息。10.2 如何查看日志业务报错:如果业务报错,基本所有的报错信息都会在biz.log中查到。消息流转: 如果是消息发送响应的问题,基本上在flow.log中可以查到或者推断出相关的信息。底层消息中间件交互: 如果消息流转无法推断出问题,或者无法查到对应的消息,就需要转到mq.log中进行查询。十一、其他11.1 常⻅问题ns4_frame系统本质是一个以消息为通信机制的分布式系统,经常出现的问题分成以下两部分:业务异常由于业务本身是由底层NS_TRANSPORTER回调来执行的,当业务出现异常的时候,很可能由于没有合适的被catch到,从而被底层的NS_TRANSPOTER框架捕获。 对于没有在biz.log和stdoout.log中查找到的问题,可以去查看下flow.log的日志,看是否出现了异常被底层NS_TRANSPOTER捕获了。底层异常有些情况,业务本身并没有出现问题,但是由于消息通信出现了问题,会导致业务没有执行,对于 这种情况我们需要首先从消息入口处即NS_DISPATCHER的flow.log中查找到对应的 messageId,然后根据消息流转路径,一步步去对应的部署机器上查询。 内容来源:宜信技术学院 ...

April 18, 2019 · 1 min · jiezi

码上用它开始Flutter混合开发——FlutterBoost

开源地址: https://github.com/alibaba/fl…为什么需要混合方案具有一定规模的App通常有一套成熟通用的基础库,尤其是阿里系App,一般需要依赖很多体系内的基础库。那么使用Flutter重新从头开发App的成本和风险都较高。所以在Native App进行渐进式迁移是Flutter技术在现有Native App进行应用的稳健型方式。闲鱼在实践中沉淀出一套自己的混合技术方案。在此过程中,我们跟Google Flutter团队进行着密切的沟通,听取了官方的一些建议,同时也针对我们业务具体情况进行方案的选型以及具体的实现。官方提出的混合方案基本原理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 Page2 -> Native Page1 -> Flutter Page3 我们只需要在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之间的通信,多引擎实例也让这件事情更加复杂。因此,综合多方面考虑,我们没有采用多引擎混合方案。现状与思考前面我们提到多引擎存在一些实际问题,所以闲鱼目前采用的混合方案是共享同一个引擎的方案。这个方案基于这样一个事实:任何时候我们最多只能看到一个页面,当然有些特定的场景你可以看到多个ViewController,但是这些特殊场景我们这里不讨论。我们可以这样简单去理解这个方案:我们把共享的Flutter View当成一个画布,然后用一个Native的容器作为逻辑的页面。每次在打开一个容器的时候我们通过通信机制通知Flutter View绘制成当前的逻辑页面,然后将Flutter View放到当前容器里面。老方案在Dart侧维护了一个Navigator栈的结构。栈数据结构特点就是每次只能从栈顶去操作页面,每一次在查找逻辑页面的时候如果发现页面不在栈顶那么需要往回Pop。这样中途Pop掉的页面状态就丢失了。这个方案无法支持同时存在多个平级逻辑页面的情况,因为你在页面切换的时候必须从栈顶去操作,无法再保持状态的同时进行平级切换。举个例子:有两个页面A,B,当前B在栈顶。切换到A需要把B从栈顶Pop出去,此时B的状态丢失,如果想切回B,我们只能重新打开B之前页面的状态无法维持住。这也是老方案最大的一个局限。如在pop的过程当中,可能会把Flutter 官方的Dialog进行误杀。这也是一个问题。而且基于栈的操作我们依赖对Flutter框架的一个属性修改,这让这个方案具有了侵入性的特点。这也是我们需要解决的一个问题。具体细节,大家可以参考老方案开源项目地址:https://github.com/alibaba-flutter/hybrid_stack_manager新一代混合技术方案 FlutterBoost重构计划在闲鱼推进Flutter化过程当中,更加复杂的页面场景逐渐暴露了老方案的局限性和一些问题。所以我们启动了代号FlutterBoost(向C++ Boost致敬)的新混合技术方案。这次新的混合方案我们的主要目标有:可复用通用型混合方案支持更加复杂的混合模式。比如支持主页Tab这种情况无侵入性方案:不再依赖修改Flutter的方案支持通用页面生命周期统一明确的设计概念跟老方案类似,新的方案还是采用共享引擎的模式实现。主要思路是由Native容器Container通过消息驱动Flutter页面容器Container,从而达到Native Container与Flutter Container的同步目的。我们希望做到Flutter渲染的内容是由Naitve容器去驱动的。简单的理解,我们想做到把Flutter容器做成浏览器的感觉。填写一个页面地址,然后由容器去管理页面的绘制。在Native侧我们只需要关心如果初始化容器,然后设置容器对应的页面标志即可。主要概念Native层概念Container:Native容器,平台Controller,Activity,ViewControllerContainer Manager:容器的管理者Adaptor:Flutter是适配层Messaging:基于Channel的消息通信Dart层概念Container:Flutter用来容纳Widget的容器,具体实现为Navigator的派生类-Container Manager:Flutter容器的管理,提供show,remove等ApiCoordinator: 协调器,接受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源码的形式去进行实现,除去了实现的侵入性。那这是如何做到的呢?多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容器事件去进行驱动。总结目前FlutterBoost已经在生产环境支撑着在闲鱼客户端中所有的基于Flutter开发业务,为更加负复杂的混合场景提供了支持。同时也解决了一些历史遗留问题。我们在项目启动之初就希望FlutterBoost能够解决Native App混合模式接入Flutter这个通用问题。所以我们把它做成了一个可复用的Flutter插件,希望吸引更多感兴趣的朋友参与到Flutter社区的建设。我们的方案可能不是最好的,这个方案距离完美还有很大的距离,我们希望通过多分享交流以推动Flutter技术社区的发展与建设。我们更希望看到社区能够涌现出更加优秀的组件和方案。在有限篇幅中,我们分享了闲鱼在Flutter混合技术方案中积累的经验和代码。欢迎兴趣的同学能够积极与我们一起交流学习。扩展补充性能相关在两个Flutter页面进行切换的时候,因为我们只有一个Flutter View所以需要对上一个页面进行截图保存,如果Flutter页面多截图会占用大量内存。这里我们采用文件内存二级缓存策略,在内存中最多只保存2-3个截图,其余的写入文件按需加载。这样我们可以在保证用户体验的同时在内存方面也保持一个较为稳定的水平。页面渲染性能方面,Flutter的AOT优势展露无遗。在页面快速切换的时候,Flutter能够很灵敏的相应页面的切换,在逻辑上创造出一种Flutter多个页面的感觉。Release 1.0支持项目开始的时候我们基于闲鱼目前使用的Flutter版本进行开发,而后进行了Release 1.0兼容升级测试目前没有发现问题。接入只要是集成了Flutter的项目都可以用官方依赖的方式非常方便的以插件形式引入FlutterBoost,只需要对工程进行少量代码接入即可完成接入。详细接入文档,请参阅GitHub主页官方项目文档。现已开源目前,新一代混合栈已经在闲鱼全面应用。我们非常乐意将沉淀的技术回馈给社区。欢迎大家一起贡献,一起交流,携手共建Flutter社区。项目开源地址:https://github.com/alibaba/flutter_boost本文作者:闲鱼技术-福居阅读原文本文为云栖社区原创内容,未经允许不得转载。

April 17, 2019 · 1 min · jiezi

开源|宜信开源专注业务逻辑的轻量级服务框架nextsystem4

宜信于2019年3月29日正式开源nextsystem4(以下简称“NS4”)系列模块。此次开源的NS4系列模块是围绕当前支付系统笨重、代码耦合度高、维护成本高而产生的分布式业务系统解决方案。NS4系列框架允许创建复杂的流程/业务流,对于业务服务节点的实现可串联,可分布式。其精简、轻量,实现了“脱容器”(不依赖tomcat、jetty等容器)独立运行。NS4系列框架的设计理念是将业务和逻辑进行分离,开发人员只需通过简单的配置和业务实现就可以实现逻辑复杂、性能高效、功能稳定的业务系统。NS4系列包括4个开源模块,分别是:ns4_frame 分布式服务框架、ns4_gear_idgen ID 生成器组件(NS4框架Demo示例)、ns4_gear_watchdog 监控系统组件(服务守护、应用性能监控、数据采集、自动化报警系统)和ns4_chatbot通讯组件。NS4系列模块的核心优势主要体现在以下几个方面:具有很好的伸缩性,可以优雅地扩容和降级;集中化管理,对各个节点的消息进行集中式管理和分发;易维护,将复杂的流程性业务拆分成多个模块系统进行交互,减少代码耦合;完善的调用链路,对于链路复杂的系统可以准确地定位出错的环节。可以通过在线聊天机器人实现及时的自动提醒。项目开源地址:https://github.com/newsettle一、ns4_frame开源地址:https://github.com/newsettle/…ns4_frame是一个高性能优秀的分布式服务框架,允许创建复杂的流程/业务流,对于业务服务节点的实现可串联,可分布式。其精简、轻量,实现了“脱容器”(不依赖tomcat、jetty等容器)独立运行。ns4_frame将业务和逻辑进行分离,开发人员只需通过简单的配置和业务实现就可以实现逻辑复杂、性能高效、功能稳定的业务系统。项目结构ns4_frame是一套MAVEN父子项目,由五个子项目组成:NS_MQ :负责和底层消息队列进行通信,提供了对消息队列进行操作的API。目前NS4底层支持redis作为消息中间件,同时提供通用的接口,可以扩展多种消息中间件,对消息中间件的操作被封装入了NS_MQ项目中。NS_TRANSPORTER:通过调用NS_MQ提供的API,对业务消息进行收取、处理、转发。它本质是一套消息收发处理框架,主要负责接收消息后反向回调业务代码,并将消息交给业务层处理,当业务层处理完毕后,再将处理后的消息返回给redis中。NS_CHAIN:一个可选开发框架,负责对同一个JVM中的业务处理步骤进行链条式的整合,组成当前业务模块的业务处理流程。NS_CONTROLLER:一个业务消息转发应用,负责将接收到的消息转给对应的业务模块进行处理,同时根据整体业务将业务模块进行关联.NS_CONTROLLER本质是一个独立的应用系统,构建于 NS_TRANPORTOR和NS_CHAIN之上。NS_DISPATCHER :NS4架构规定的消息入口,以NETTY框架作为基础,通过提供的HTTP服务接受业务系统边界外的http请求,并将请求转化成业务系统内部通信使用的消息协议格式。上图展示了NS4每个系统的层次结构。运行流程NS4整套系统本质上其实就是一套消息中间件服务加开发框架,整体的结构图如下: 上图展示了一个NS4整体分布式项目的运行流程。一个消息的运转流程按如下顺序:NS_DISPATCHER收到http请求并将其转化为内部消息协议放入指定的消息队列中(根据配置文件) 。NS_CONTORLLER从步骤1指定的队列接收到消息,并根据配置的服务编排开始按照顺序将消息发送到每个业务系统步骤对应的消息队列中。业务系统收到步骤2中NS_CONTROLLER指定的消息队列的信息,开始处理,处理完毕后,将结果返回。NS_CONTROLLER收到业务系统的响应,开始根据配置好的服务将返回的消息结果发送到下一个业务系统对应的消息队列中。消息被所有的业务系统处理完成后,NS_CONTROLLER把消息处理结果放入到指定的消息队列里,NS_DISPATCHER从对应的消息队列里取出消息结果,响应给http调用者。二、ns4_gear_idgen开源地址:https://github.com/newsettle/…ns4_gear_idgen (ID生成器)是基于NS4框架实现的,它支持分布式部署,生成全局唯一的 ID,其中长度、前缀、后缀、步长、进制也可根据自己的业务自由配置,还可以通过ns4_gear_idgen对NS4.0框架进行测试。优点很方便的线性扩展,能够支撑大多数业务场景。生成ID规则多样,可根据业务需求自由配置,且支持10进制、36进制、62进制。业务之间ID相互隔离,互不影响。获取ID不用频繁操作数据库,快消耗完号段内ID时才会操作数据库,减轻了数据库的压力。提前初始化号段内的ID,保证在每个号段内ID使用完之前完成初始化,避免业务使用完ID后再初始化所带来的影响。可以自定义 key_value 的大小,业务可以很方便地从原有的ID方式迁移过来。容灾性高,服务内部有号段缓存,即使DB宕机,短时间内仍能正常对外提供服务。三、ns4_gear_watchdog开源地址:https://github.com/newsettle/…ns4_gear_watchdog是ns4_frame进程的父进程,守护并管理ns4_frame进程。它的职责包括以下几个方面:对ns4_frame进行远程启动和停止、实时监测ns4_frame进程的健康状态、内存消耗、CPU使用、内部线程;收集ns4_frame实现的业务日志归集、实现业务内部实时流转的业务数据,达到实时对ns4_frame进程在线上的运行状态、实现的业务以及业务数据的流转状态等方面的监控,并精准、快速、便捷地定位出异常以及CPU、线程等运行状态。ns4_gear_watchdog是作为父进程存在的,通过父进程启动目标项目(子进程),并针对子进程应用生存的环境因素(包括系统层面的内存消耗、CPU 使用、负载、线程等)、实现功能的代码因素(代码健康程度)、业务因素等数据进行实时监控。父子进程通过 jmx 方式进行通讯,采集以上因素数据,并将这些数据保存到 ElasticSearch 中,进一步通过分析数据和现实运行情况总结制定出的指标相结合,将该以上因素数据通过微信机器人实时通知提醒相关负责人。[ns4_gear_watchdog基本结构图]四、ns4_chatbot开源地址:https://github.com/newsettle/…ns4_chatbot是一个机器人的聊天框架,集成了qqbot、WxChat、rasa以及web服务。ns4_chatbot提供微信和qq聊天接口,可以对某个群组发送系统监控消息等,还可以把ns4_gear_watchdog监控信息发送到对应的群组中。ns4_chatbot实现的功能:接受内部系统(如监控系统)的系统调用,从而把消息推送给 QQ 或者微信用户。内部系统调用服务时,需要提供以下信息:发给哪个群组发给这个群组中的哪个用户发送的消息内容可以接受 QQ、微信用户的对话,理解其意图,并且回应用户。未来展望宜信一直践行以科技推动金融发展的技术信念,并愿意将技术实践成果开源分享,以期通过宜信的实践经验推动金融科技行业的发展和创新。 目前,宜信技术学院已开源了多个宜信的技术成果与研发实践,面向软件研发行业分享宜信的技术理念,本次NS4系列模块的开源将保持长期更新和维护,也希望有更多的技术伙伴加入到开源项目中,共同维护与发展开源成果。内容来源:宜信技术学院

April 16, 2019 · 1 min · jiezi

Leaf:美团分布式ID生成服务开源

Leaf是美团基础研发平台推出的一个分布式ID生成服务,名字取自德国哲学家、数学家莱布尼茨的一句话:“There are no two identical leaves in the world.”Leaf具备高可靠、低延迟、全局唯一等特点。目前已经广泛应用于美团金融、美团外卖、美团酒旅等多个部门。具体的技术细节,可参考此前美团技术博客的一篇文章:《Leaf美团分布式ID生成服务》。近日,Leaf项目已经在Github上开源:https://github.com/Meituan-Dianping/Leaf,希望能和更多的技术同行一起交流、共建。Leaf特性Leaf在设计之初就秉承着几点要求:全局唯一,绝对不会出现重复的ID,且ID整体趋势递增。高可用,服务完全基于分布式架构,即使MySQL宕机,也能容忍一段时间的数据库不可用。高并发低延时,在CentOS 4C8G的虚拟机上,远程调用QPS可达5W+,TP99在1ms内。接入简单,直接通过公司RPC服务或者HTTP调用即可接入。Leaf诞生Leaf第一个版本采用了预分发的方式生成ID,即可以在DB之上挂N个Server,每个Server启动时,都会去DB拿固定长度的ID List。这样就做到了完全基于分布式的架构,同时因为ID是由内存分发,所以也可以做到很高效。接下来是数据持久化问题,Leaf每次去DB拿固定长度的ID List,然后把最大的ID持久化下来,也就是并非每个ID都做持久化,仅仅持久化一批ID中最大的那一个。这个方式有点像游戏里的定期存档功能,只不过存档的是未来某个时间下发给用户的ID,这样极大地减轻了DB持久化的压力。整个服务的具体处理过程如下:Leaf Server 1:从DB加载号段[1,1000]。Leaf Server 2:从DB加载号段[1001,2000]。Leaf Server 3:从DB加载号段[2001,3000]。用户通过Round-robin的方式调用Leaf Server的各个服务,所以某一个Client获取到的ID序列可能是:1,1001,2001,2,1002,2002……也可能是:1,2,1001,2001,2002,2003,3,4……当某个Leaf Server号段用完之后,下一次请求就会从DB中加载新的号段,这样保证了每次加载的号段是递增的。Leaf数据库中的号段表格式如下:+————-+————–+——+—–+——————-+—————————–+| Field | Type | Null | Key | Default | Extra |+————-+————–+——+—–+——————-+—————————–+| biz_tag | varchar(128) | NO | PRI | | || max_id | bigint(20) | NO | | 1 | || step | int(11) | NO | | NULL | || desc | varchar(256) | YES | | NULL | || update_time | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |+————-+————–+——+—–+——————-+—————————–+Leaf Server加载号段的SQL语句如下:BeginUPDATE table SET max_id=max_id+step WHERE biz_tag=xxxSELECT tag, max_id, step FROM table WHERE biz_tag=xxxCommit整体上,V1版本实现比较简单,主要是为了尽快解决业务层DB压力的问题,而快速迭代出的一个版本。因而在生产环境中,也发现了些问题。比如:在更新DB的时候会出现耗时尖刺,系统最大耗时取决于更新DB号段的时间。当更新DB号段的时候,如果DB宕机或者发生主从切换,会导致一段时间的服务不可用。Leaf双Buffer优化为了解决这两个问题,Leaf采用了异步更新的策略,同时通过双Buffer的方式,保证无论何时DB出现问题,都能有一个Buffer的号段可以正常对外提供服务,只要DB在一个Buffer的下发的周期内恢复,就不会影响整个Leaf的可用性。这个版本代码在线上稳定运行了半年左右,Leaf又遇到了新的问题:号段长度始终是固定的,假如Leaf本来能在DB不可用的情况下,维持10分钟正常工作,那么如果流量增加10倍就只能维持1分钟正常工作了。号段长度设置的过长,导致缓存中的号段迟迟消耗不完,进而导致更新DB的新号段与前一次下发的号段ID跨度过大。Leaf动态调整Step假设服务QPS为Q,号段长度为L,号段更新周期为T,那么Q * T = L。最开始L长度是固定的,导致随着Q的增长,T会越来越小。但是Leaf本质的需求是希望T是固定的。那么如果L可以和Q正相关的话,T就可以趋近一个定值了。所以Leaf每次更新号段的时候,根据上一次更新号段的周期T和号段长度step,来决定下一次的号段长度nextStep:T < 15min,nextStep = step * 215min < T < 30min,nextStep = stepT > 30min,nextStep = step / 2至此,满足了号段消耗稳定趋于某个时间区间的需求。当然,面对瞬时流量几十、几百倍的暴增,该种方案仍不能满足可以容忍数据库在一段时间不可用、系统仍能稳定运行的需求。因为本质上来讲,Leaf虽然在DB层做了些容错方案,但是号段方式的ID下发,最终还是需要强依赖DB。MySQL高可用在MySQL这一层,Leaf目前采取了半同步的方式同步数据,通过公司DB中间件Zebra加MHA做的主从切换。未来追求完全的强一致,会考虑切换到MySQL Group Replication。现阶段由于公司数据库强一致的特性还在演进中,Leaf采用了一个临时方案来保证机房断网场景下的数据一致性:多机房部署数据库,每个机房一个实例,保证都是跨机房同步数据。半同步超时时间设置到无限大,防止半同步方式退化为异步复制。Leaf监控针对服务自身的监控,Leaf提供了Web层的内存数据映射界面,可以实时看到所有号段的下发状态。比如每个号段双buffer的使用情况,当前ID下发到了哪个位置等信息都可以在Web界面上查看。Leaf SnowflakeSnowflake,Twitter开源的一种分布式ID生成算法。基于64位数实现,下图为Snowflake算法的ID构成图。第1位置为0。第2-42位是相对时间戳,通过当前时间戳减去一个固定的历史时间戳生成。第43-52位是机器号workerID,每个Server的机器ID不同。第53-64位是自增ID。这样通过时间+机器号+自增ID的组合来实现了完全分布式的ID下发。在这里,Leaf提供了Java版本的实现,同时对Zookeeper生成机器号做了弱依赖处理,即使Zookeeper有问题,也不会影响服务。Leaf在第一次从Zookeeper拿取workerID后,会在本机文件系统上缓存一个workerID文件。即使ZooKeeper出现问题,同时恰好机器也在重启,也能保证服务的正常运行。这样做到了对第三方组件的弱依赖,一定程度上提高了SLA。未来规划号段加载优化:Leaf目前重启后的第一次请求还是会同步加载MySQL,之所以这么做而非服务初始化加载号段的原因,主要是MySQL中的Leaf Key并非一定都被这个Leaf服务节点所加载,如果每个Leaf节点都在初始化加载所有的Leaf Key会导致号段的大量浪费。因此,未来会在Leaf服务Shutdown时,备份这个服务节点近一天使用过的Leaf Key列表,这样重启后会预先从MySQL加载Key List中的号段。单调递增:简易的方式,是只要保证同一时间、同一个Leaf Key都从一个Leaf服务节点获取ID,即可保证递增。需要注意的问题是Leaf服务节点切换时,旧Leaf 服务用过的号段需要废弃。路由逻辑,可采用主备的模型或者每个Leaf Key 配置路由表的方式来实现。关于开源分布式ID生成的方案有很多种,Leaf开源版本提供了两种ID的生成方式:号段模式:低位趋势增长,较少的ID号段浪费,能够容忍MySQL的短时间不可用。Snowflake模式:完全分布式,ID有语义。读者可以按需选择适合自身业务场景的ID下发方式。希望美团的方案能给予大家一些帮助,同时也希望各位能够一起交流、共建。Leaf项目Github地址:https://github.com/Meituan-Dianping/Leaf 。如有任何疑问和问题,欢迎提交至Github issues。 ...

March 8, 2019 · 1 min · jiezi

TaroEcharts-各种图表在Taro中的实践

随着React的快速发展,我们也越来越接受它的写法和思想,如今小程序如火中天,普通的编译模式早已不适应开发者的需求。人们在不断的寻求一种React能够在小程序中编译的语言框架,因此Taro便诞生了。宇宙中最强的执行官。它支持使用 React 的开发方式来编写可以同时在微信小程序、Web 、React Native 等多个平台上运行的应用。经过不断地迭代完善,已经让 Taro 浴火重生。TaroEcharts简介本项目是在实际开发中总结出来的一套基于ec-canvas封装的适用于Taro版本的图表框架。开发者可以通过简单的配置及 React 的语法,快速开发图表,满足各种可视化需求。Github地址:https://github.com/WsmDyj/ech…微信小程序预览:实现过程1 下载为了兼容小程序 Canvas,我们首先去构建ec-canvas下载到本地。其中ec-canvas是echarts官网提供的组件,我们可以自行下载或者去官网自定义构建选择自己需要的图表或插件进行下载。2 引入组件在项目中引入我们需要的组件库,这里统一将其放在src/components/ec-canvas文件夹下。大家可将该文件夹导入到自己项目中去。其中echarts.js就是刚我们自行下载的echarts图表插件,可根据实际项目需求自定义下载所需图表然后将其导入。3 创建图表(以饼图为例)3.1 新建图表组件在components文件夹下创建pieCharts.js组件。引入我们刚创建的组件import * as echarts from “./ec-canvas/echarts”;3.2 懒加载渲染图表配置我们的ec-canvasconfig = { usingComponents: { “ec-canvas”: “./ec-canvas/ec-canvas” }};在render函数中使用刚导入的ec-canvas<ec-canvas ref={this.refChart} canvas-id=“mychart-area” ec={this.state.ec}/>构建refresh函数初始化图表refresh(data) { this.Chart.init((canvas, width, height) => { const chart = echarts.init(canvas, null, { width: width, height: height }); setChartData(chart, data); return chart; }); } refChart = node => (this.Chart = node);配置懒加载图表state = { ec: { lazyLoad: true } };3.3 配置我们所需图表的option这里在setChartData进行配置,并传入charts,data参数。function setChartData(chart, data) { let option = { series : [ { name: ‘访问来源’, type: ‘pie’, center: [‘50%’, ‘50%’], radius: [0, ‘60%’], data: data, itemStyle: { emphasis: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: ‘rgba(0, 0, 0, 0.5)’ } } } ] }; chart.setOption(option);}至此饼图已经创建完成,具体的可参考饼图4 实例化图表在需要图表的页面中导入刚创建的图表(饼图)import PieChart from “../../components/PieChart”;render函数中导入<PieChart ref={this.refPieChart} />实例化图表并传入datacomponentDidMount() { const chartData = [ {value:335, name:‘直接访问’}, {value:310, name:‘邮件营销’}, {value:234, name:‘联盟广告’}, {value:135, name:‘视频广告’}, {value:1548, name:‘搜索引擎’} ]; this.pieChart.refresh(chartData); } refPieChart = (node) => this.pieChart = node至此饼图已经创建完成,饼图如此其他的都是类似的。只要照着这个方式去设置option,我们就可以创建你想要的图表了。 ## 5 其他图表的创建 #### 可滑动图表: #### 一个页面多个图表: #### 多个图表结合在一起:总结从不为人知到家喻户晓,Taro现在也逐渐被开发者所接受。在未来的道路上应该还会更火,毕竟是宇宙中最强的执行官。然而一个好的框架也是需要大部分工具辅助的。就好比ADC旁边总跟着个辅助。其中图表在Taro中目前还没有一个统一的开发规范,目前这仅是我们团队中使用的一种方式。目前也正在抽离出单独针对Taro-echarts包。志同道合欢迎提issue一起加入我们。 ...

January 17, 2019 · 1 min · jiezi

阿里开源首个深度学习框架 X-Deep Learning!

刚刚,阿里妈妈正式对外发布了X-Deep Learning(下文简称XDL)的开源代码地址,开发者们可以在Github上自主下载。此前,在11月底,阿里妈妈就公布了这项开源计划,引来了业界的广泛关注。XDL突破了现有深度学习开源框架大都面向图像、语音等低维稠密数据而设计的现状,面向高维稀疏数据场景进行了深度优化,并已大规模应用于阿里妈妈的业务及生产场景。本文将为大家详细介绍XDL的设计理念及关键技术。概述以深度学习为核心的人工智能技术,过去的几年在语音识别、计算机视觉、自然语言处理等领域获得了巨大的成功,其中以GPU为代表的硬件计算力,以及优秀的开源深度学习框架起到了巨大的推动作用。尽管以TensorFlow、PyTorch、MxNet等为代表的开源框架已经取得了巨大的成功,但是当我们把深度学习技术应用在广告、推荐、搜索等大规模工业级场景时,发现这些框架并不能很好的满足我们的需求。矛盾点在于开源框架大都面向图像、语音等低维连续数据设计,而互联网的众多核心应用场景(如广告/推荐/搜索)往往面对的是高维稀疏离散的异构数据,参数的规模动辄百亿甚至千亿。进一步的,不少产品应用需要大规模深度模型的实时训练与更新,现有开源框架在分布式性能、计算效率、水平扩展能力以及实时系统适配性的等方面往往难以满足工业级生产应用的需求。X-DeepLearning正是面向这样的场景设计与优化的工业级深度学习框架,经过阿里巴巴广告业务的锤炼,XDL在训练规模和性能、水平扩展能力上都表现出色,同时内置了大量的面向广告/推荐/搜索领域的工业级算法解决方案。系统核心能力1) 为高维稀疏数据场景而生。支持千亿参数的超大规模深度模型训练,支持批学习、在线学习等模式。2) 工业级分布式训练能力。支持CPU/GPU的混合调度,具备完整的分布式容灾语义,系统的水平扩展能力优秀,可以轻松做到上千并发的训练。3) 高效的结构化压缩训练。针对互联网样本的数据特点,提出了结构化计算模式。典型场景下,相比传统的平铺样本训练方式,样本存储空间、样本IO效率、训练绝对计算量等方面都大幅下降,推荐等场景下整体训练效率最大可提升10倍以上。4) 成熟多后端支持。单机内部的稠密网络计算复用了成熟开源框架的能力,只需要少量的分布式驱动代码修改,就可以把TensorFlow/MxNet等的单机代码运行在XDL上,获得XDL分布式训练与高性能稀疏计算的能力。内置工业级算法解决方案1)点击率预估领域的最新算法,包括深度兴趣网络(Deep Interest Network, DIN),用户兴趣演化模型(Deep Interest Evolution Network, DIEN),跨媒介网络(Cross Media Network,CMN)。2)点击率&转化率联合建模的全空间多任务模型(Entire Space Multi-task Model, ESMM)。3)匹配召回领域的最新算法——深度树匹配模型(Tree-based Deep Match,TDM)。4)轻量级通用模型压缩算法(Rocket Training)系统设计与优化XDL-Flow:数据流与分布式运行时XDL-Flow驱动整个深度学习计算图的生成与执行,包括样本流水线、稀疏表征学习、稠密网络学习。同时,XDL-Flow也负责分布式模型的存储与交换控制逻辑,分布式容灾与恢复控制等全局一致性协调的工作。在搜索、推荐、广告等场景下的样本量巨大,通常达到几十TB至数百TB,如果不能很好的优化样本流水线,样本IO系统很容易成为整个系统的瓶颈,从而导致计算硬件的利用率低下。在大规模稀疏场景下,样本读取的特点是IO密集,稀疏表征计算的特点是参数交换网络通信密集,稠密深度计算是计算密集型。XDL-Flow通过把三个主要环节异步流水线并行,较好的适配了3种不同类型任务的性能。最好的情况下,前两个阶段的延时都被隐藏了。同时,我们也正在尝试自动化的Tunning异步流水线的各个参数,包括各个Step的并行度、Buffer大小等,尽可能让用户不需要关心整个异步流水线并行的细节。AMS:高效模型服务器AMS是面向稀疏场景专门设计与优化的分布式模型存储与交换子系统。我们综合小包网络通信、参数存储结构、参数分布式策略等进行了大量的软硬件优化,使得AMS在吞吐力和水平扩展力上都大幅优于传统的Parameter Server,AMS也支持内置的深度网络计算,使得你可以使用AMS进行表征子网络的二阶计算。1)AMS通过软硬件结合在网络通信层做了大量优化,包括使用Seastar,DPDK,CPUBind,ZeroCopy等技术,充分压榨硬件性能,经过我们实际测试,大规模并发训练下,参数交换导致的小包吞吐能力是传统RPC框架的5倍以上。2)通过内置的参数动态均衡策略,可以在运行过程中找到最优的稀疏参数分布策略,有效解决传统参数服务器由于参数分布式不均匀带来的热点问题,大幅提高了系统在高并发情况下的水平扩展能力。3)AMS同样支持通过GPU加速大Batch Size场景下的Sparse Embedding计算,针对超大Batch的场景,可以起到很好的加速作用。4)AMS支持内部定义子网络。例如我们的算法解决方案中提供的Cross-Media建模,图像部分的表征子网络就是以AMS内运行的方式定义的,大幅减少了重复计算和网络吞吐。Backend Engine:桥接技术复用成熟框架的单机能力为了充分利用现有开源深度学习框架在稠密深度网络上的能力,XDL使用桥接技术(Bridging),把开源深度学习框架(本期开源版XDL支持了TensorFlow、MxNet)作为我们的单机稠密网络的计算引擎后端。用户可以在保留TensorFlow或MxNet网络开发习惯的同时,通过少量的驱动代码修改,就直接获得XDL在大规模稀疏计算上的分布式训练能力。换句话说,使用XDL时无需再学习一门新的框架语言,这带来另一个好处是XDL可以跟现有成熟的开源社区无缝对接——用户可以很轻松地将tensorflow社区的某个开源模型通过XDL拓展到工业级场景。Compact Computation:结构化计算模式大幅提升训练效率工业界稀疏场景下的样本表征,往往呈现很强的结构化特点,例如用户特征、商品特征、场景特征。这种构建方式决定了某些特征会大量出现在重复的样本中——隶属于同一个用户的多条样本中,用户特征很大一部分是相同的。结构化样本压缩正是利用海量样本中,大量局部特征重复这一特点,在存储和计算两个维度上对特征进行压缩,节省了存储、计算和通信带宽资源。样本预处理阶段,对需要聚合的特征进行排序(例如按用户ID排序,聚合用户特征);batching阶段,在tensor层面进行压缩;计算阶段,压缩特征只有在最后一层才会展开,极大节省深层网络的计算开销。 推荐场景下的效果验证表示,在典型的生产数据上,使用聚合排序的样本和完全shuffle的样本评估AUC指标一致,整体性能提升10倍以上。Online-Learning:大规模在线学习在线学习近年来在工业界开始被大规模应用,它是工程与算法的深入结合,赋予模型实时捕捉线上流量变化的能力,在一些对时效性要求很高的场景,有十分大的价值。例如在电商大促等场景下,在线学习可以更加实时的捕捉用户行为的变化,显著的提升模型的实时效果。XDL提供了一套完整的在线学习的解决方案,支持基于全量模型,读取实时消息队列里的样本进行实时持续学习,我们内置支持了Kafka等作为Message Source,并允许按照用户设置控制模型写出的周期。另外,为了避免无限制的新特征流入导致的实时模型爆炸问题,XDL内置了实时特征自动选择与过期特征淘汰等功能,保证用户使用XDL进行在线学习的简便性。1)去ID化的稀疏特征学习:传统的机器学习框架一般要求对稀疏特征进行ID化表征(从0开始紧凑编码),以此来保证训练的高效性。XDL则允许直接以原始的特征进行训练,大幅简化了特征工程的复杂度,极大地增加了全链路数据处理效率,这一特性在实时在线学习场景下显得更加有意义。2)实时特征频控:用户可以设置一个特征过滤的阈值,例如出现次数大于N次的特征才纳入模型训练,系统会自动的采用自动概率丢弃的算法进行特征选择,这样可以大幅降低无效超低频特征在模型中的空间占用。3)过期特征淘汰:长周期的在线学习时,用户也可以通过打开过期特征淘汰功能,系统会自动的对影响力弱且长周期没有碰触到的特征参数进行自动淘汰。X-DeepLearning算法解决方案典型的点击率(Click-Through Rate)预估模型DIN(Deep Interest Network)传统的Embedding&MLP类的模型并未对用户的表达做过多的工作。往往通过embedding的机制将用户的历史行为投影到一个定长的向量空间,再经过一个sum/avg pooling操作得到一个定长的用户向量表达。但是用户的兴趣是多种多样的,用一个固定的向量去表达用户不同的兴趣是非常难的。事实上用户在面对不同商品的时候,其兴趣表现也不一样,仅仅和这个商品相关的兴趣会影响用户的决策。因此我们在预估用户对一个具体商品的点击率的时候只需要表达其与此商品相关的兴趣。在DIN中我们提出了一个兴趣激活机制,通过被预估的商品去激活用户历史行为中相关的部分,从而获取用户在这个具体商品上的兴趣。论文地址:https://arxiv.org/abs/1706.06978DIEN(Deep Interest Evolution Network)DIEN主要解决两个问题:兴趣提取和兴趣演化。在兴趣提取这部分,传统的算法直接将用户的历史行为当做用户的兴趣。同时整个建模过程中的监督信息全部集中于广告点击样本上。而单纯的广告点击样本只能体现用户在决策是否点击广告时的兴趣,很难建模好用户历史每个行为时刻的兴趣。本文中我们提出了auxiliary loss 用于兴趣提取模块,约束模型在对用户每一个历史行为时刻的隐层表达能够推测出后续的行为,我们希望这样的隐层表达能更好的体现用户在每一个行为时刻的兴趣。在兴趣提取模块后我们提出了兴趣演化模块,传统的RNN类似的方法只能建模一个单一的序列,然而在电商场景 用户不同的兴趣其实有不同的演化过程。在本文中我们提出AUGRU(Activation Unit GRU),让GRU的update门和预估的商品相关。在建模用户的兴趣演化过程中,AUGRU会根据不同的预估目标商品构建不同的兴趣演化路径,推断出用户和此商品相关的兴趣。论文地址:https://arxiv.org/abs/1809.03672CMN(Cross Media Network)CMN旨在CTR预估模型中引入更多的模态数据,如图像信息。在原有ID类特征基础上,增加了图像视觉特征,共同加入广告CTR预估模型,在阿里妈妈大规模数据上取得了显著的效果提升。CMN包括多项技术特色:第一,图像内容特征抽取模型与主模型共同训练,联合优化; 第二,同时使用图像信息表达广告和用户,其中用户表达采用用户历史行为对应的图片; 第三,为处理训练涉及到的海量图像数据,提出了“高级模型服务”的计算范式,有效减少训练过程中的计算、通信、存储负载。CMN除用于图像特征引入外,对于文本、视频等内容特征也可以以合适的特征提取网络、用同样的模型处理。论文地址:https://arxiv.org/abs/1711.06505典型的转化率(Conversion Rate)预估模型ESMM(Entire Space Multi-task Model)Entire Space Multi-task Model (ESMM) 是阿里妈妈研发的新型多任务联合训练算法范式。ESMM模型首次提出了利用学习CTR和CTCVR的辅助任务迂回学习CVR的思路,利用用户行为序列数据在完整样本空间建模,避免了传统CVR模型经常遭遇的样本选择偏差和训练数据稀疏的问题,取得了显著的效果。ESMM 可以很容易地推广到具有序列依赖性的用户行为(浏览、点击、加购、购买等)预估中,构建全链路多目标预估模型。ESMM模型中的BASE子网络可以替换为任意的学习模型,因此ESMM的框架可以非常容易地和其他学习模型集成,从而吸收其他学习模型的优势,进一步提升学习效果,想象空间巨大。论文地址:https://arxiv.org/abs/1804.07931典型的匹配召回模型TDM(Tree-based Deep Match)TDM自主创新提出了一套完整的基于树的复杂深度学习推荐匹配算法框架,它通过建立用户兴趣层次树结构实现了高效的全库检索,并以此为基础赋能深度模型引入Attention等更先进的计算结构,达到了在精度、召回率以及新颖性等指标上相对于传统推荐方法的显著效果提升。进一步的,TDM设计实现了一套完整的 初始树-模型训练-树重建-模型再训练 的联合训练迭代框架,更加促进了效果的提升。联合训练赋予了TDM算法框架较好的通用性,为TDM向新场景、新领域的迁移扩展提供了良好的理论基础和极大的工程可行性。论文地址:https://arxiv.org/abs/1801.02294典型的模型压缩算法Rocket Training工业上在线模型的实时推理对响应时间提出非常严苛的要求,从而一定程度上限制了模型的复杂程度。模型复杂程度的受限可能会导致模型学习能力的降低从而带来效果的下降。目前有2种思路来解决这个问题:一方面,可以在固定模型结构和参数的情况下,用计算数值压缩来降低inference时间,同时也有设计更精简的模型以及更改模型计算方式的工作,如Mobile Net和ShuffleNet等工作。另一方面,利用复杂的模型来辅助一个精简模型的训练,测试阶段,利用学习好的小模型来进行推理。这两种方案并不冲突,在大多数情况下第二种方案可以通过第一种方案进一步降低inference时间,同时,考虑到相对于严苛的在线响应时间,我们有更自由的训练时间,有能力训练一个复杂的模型。Rocket Training属于第二种思路,它比较的轻巧优雅,方法具有很强的通用性,可以根据系统能力来定制模型复杂度,提供了一种"无极调速"手段。在阿里妈妈的生产实践中,Rocket Training可以极大地节省在线计算资源,显著提升系统应对双十一大促等流量洪峰的能力。论文地址:https://arxiv.org/abs/1708.04106BenchMark我们提供几组Benchmark数据供大家参考,重点看一下XDL在大batch、小batch等场景下的训练性能以及水平可扩展能力,以及结构化压缩训练带来的提速。基于CPU训练的深度CTR模型我们选取模型结构为Sparse Embedding DNN结构,N路Sparse特征分别做Embedding,再通过BiInteraction得到若干路NFM特征。选择两个特征规模的场景,Sparse特征总规模分别约为10亿(对应百亿参数)/100亿(对应千亿参数),dense维度为数百维,单条样本Sparse特征id数量约100+/300+个。训练模式:BatchSize=100,异步SGD训练。从bechmark结果可以看到,在高维稀疏场景下,XDL有明显的优势,在相当大并发的情况下,保持了良好的线性可扩展能力。基于GPU训练的深度CTR模型本文作者:XDL阅读原文本文来自云栖社区合作伙伴“阿里技术”,如需转载请联系原作者。

December 25, 2018 · 1 min · jiezi

年度大盘点:机器学习开源项目及框架

摘要: 2018年马上就要结束了,我们来回顾一下过去的这一年中,机器学习领域有哪些有趣的事情吧!我们先来看看Mybridge AI 中排名靠前的顶级开源项目,再聊聊机器学习今年都有哪些发展,最后探寻下新的一年中会有哪些有值得我们期待的事情。顶级的开源项目BERTBERT,全称为Bidirectional Encoder Representations from Transformers,是一种基于TensorFlow解决自然语言处理的新方法,且性能更好。我们可以使用BERT中的 预训练模型解决问题,该模型在性能上具有很大优势,比如可以识别句子中的上下文。在Github中非常受欢迎,有8848个星,完整学术论文请访问这里。DeepCreamPyDeepCreamPy是一个深度学习工具,可以像Photoshop一样重建图像中被删除的区域。我们使用图像编辑工具(比如PS)将删减的区域填充为绿色,神经网络可以对其进行复原。该项目在Github中有6365颗星。TRFLTRFL项目可用于编写TensorFlow中的强化学习代理,具体的操作文档在这里。HorizonHorizon是一个基于PyTorch构建的强化学习平台,并使用Caffe2为模型提供服务。Horizon的主要优势在于,设计者在设计这一平台的时候,考虑了生产用例。想要了解更多详细内容,请查看Facebook Research官方文档。另外,如果你想使用Horizon,可查看该使用文档。DeOldifyDeOldify是一个用于着色和恢复旧图像的深度学习库。开发者结合了几种不同的方法,来实现这一目标,其中的几种方法包括:带自注意力机制的生成对抗网络(Self-Attention Generative Adversarial Networks),Progressive Growing of GANs,以及TTUR( Two Time-Scale Update Rule)。AdaNetAdaNet是一个基于TensorFlow的库,它可以自动学习模型,且不需要很多的技术人员参与,该项目基于AdaNet算法。访问AdaNet的官方文档,请点击这里。Graph NetsGraph Nets是用于构建Sonnet和TensorFlow的DeepMind库。Graph 网络输入一个图形,输出也是一个图形。Maskrcnn-benchmarkMaskrcnn-benchmark项目可以帮助我们在Pytorch中构建对象检测和分割工具。这个库的优势在于速度快、内存效率高,可以进行多个GPU训练和推断,且为推断提供CPU支持。PocketFlowPocketFlow项目是一个加速和压缩深度学习模型的框架。它解决了大多数深度学习模型的计算费用问题。该项目最初由腾讯AI实验室的研究人员开发,了解其实现及官方文档请点击这里。MAMEToolkitMAMEToolKit是一个训练街机游戏强化学习算法的库,使用该工具可以跟踪游戏状态,同时也可以接收游戏帧数据。机器学习框架的主要发展PyTorch 1.0在今年10月份举办的PyTorch会议期间,Facebook发布了PyTorch 1.0预览版。PyTorch 1.0解决了以下问题:训练耗时长、联网问题、缓慢的可扩展性以及Python编程语言带来的一些不灵活性。PyTorch 1.0引入了一组编译工具Torch.jit,这将弥补生产和研究之间的差距。Torch.jit中包含Python中的Torch Script语言,在PyTorch 1.0中,我们可以使用图形模式构建模型,这在开发高性能和低延迟的应用程序中非常有用。Auto-Keras你或许听过自动化机器学习(automated machine learning),即自动化搜索机器学习模型的最佳参数。除Auto-Keras之外,还有其他的自动化机器学习模型,比如Google的AutoML。Auto-Keras是基于Keras和ENAS编写的,其中,ENAS是神经网络结构搜索的最新版本。TensorFlow Serving使用TensorFlow Serving系统,我们能更加轻松的将TensorFlow模型部署到生产环境中。虽然TensorFlow Serving在2017年就已经发布,但是今年更加注重将模型应用到生产环境环节。Machine Learning Javascript现在已经有一些可以允许开发人员在浏览器上运行模型的Javascript框架,比如TensorFlow.js和Keras.js。其模型实现与使用的方法,与Keras或TensorFlow等常规框架非常相似。展望未来2019年马上就要到了,随着Auto-Keras等自动化工具的发展,开发人员的工作有望变得更加轻松。除此以外,我们还拥有先进的研究以及优秀的社区,各类机器学习框架的性能还会更上一层楼。本文作者:【方向】阅读原文本文为云栖社区原创内容,未经允许不得转载。

December 17, 2018 · 1 min · jiezi

Logan:美团点评的开源移动端基础日志库

前言Logan是美团点评集团移动端基础日志组件,这个名称是Log和An的组合,代表个体日志服务。同时Logan也是“金刚狼”大叔的名号,当然我们更希望这个产品能像金刚狼大叔一样犀利。Logan已经稳定迭代了一年多的时间。目前美团点评绝大多数App已经接入并使用Logan进行日志收集、上传、分析。近日,我们决定开源Logan生态体系中的存储SDK部分(Android/iOS),希望能够帮助更多开发者合理的解决移动端日志存储收集的相关痛点,也欢迎更多社区的开发者和我们一起共建Logan生态。Github的项目地址参见:https://github.com/Meituan-Di…。背景随着业务的不断扩张,移动端的日志也会不断增多。但业界对移动端日志并没有形成相对成体系的处理方式,在大多数情况下,还是针对不同的日志进行单一化的处理,然后结合这些日志处理的结果再来定位问题。然而,当用户达到一定量级之后,很多“疑难杂症”却无法通过之前的定位问题的方式来进行解决。移动端开发者最头疼的事情就是“为什么我使用和用户一模一样的手机,一模一样的系统版本,仿照用户的操作却复现不出Bug”。特别是对于Android开发者来说,手机型号、系统版本、网络环境等都非常复杂,即使拿到了一模一样的手机也复现不出Bug,这并不奇怪,当然很多时候并不能完全拿到真正完全一模一样的手机。相信很多同学见到下面这一幕都似曾相识:用(lao)户(ban):我发现我们App的XX页面打不开了,UI展示不出来,你来跟进一下这个问题。你:好的。于是,我们检查了用户反馈的机型和系统版本,然后找了一台同型号同版本的手机,试着复现却发现一切正常。我们又给用户打个电话,问问他到底是怎么操作的,再问问网络环境,继续尝试复现依旧未果。最后,我们查了一下Crash日志,网络日志,再看看埋点日志(发现还没报上来)。你内心OS:奇怪了,也没产生Crash,网络也是通的,但是为什么UI展示不出来呢?几个小时后……用(lao)户(ban):这问题有结果了吗?你:我用了各种办法复现不出来……暂时查不到是什么原因导致的这个问题。用(lao)户(ban):那怪我咯?你:……如果把一次Bug的产生看作是一次“凶案现场”,开发者就是破案的“侦探”。案发之后,侦探需要通过各种手段搜集线索,推理出犯案过程。这就好比开发者需要通过查询各种日志,分析这段时间App在用户手机里都经历了什么。一般来说,传统的日志搜集方法存在以下缺陷:日志上报不及时。由于日志上报需要网络请求,对于移动App来说频繁网络请求会比较耗电,所以日志SDK一般会积累到一定程度或者一定时间后再上报一次。上报的信息有限。由于日志上报网络请求的频次相对较高,为了节省用户流量,日志通常不会太大。尤其是网络日志等这种实时性较高的日志。日志孤岛。不同类型的日志上报到不同的日志系统中,相对孤立。日志不全。日志种类越来越多,有些日志SDK会对上报日志进行采样。面临挑战美团点评集团内部,移动端日志种类已经超过20种,而且随着业务的不断扩张,这一数字还在持续增加。特别是上文中提到的三个缺陷,也会被无限地进行放大。查问题是个苦力活,不一定所有的日志都上报在一个系统里,对于开发者来说,可能需要在多个系统中查看不同种类的日志,这大大增加了开发者定位问题的成本。如果我们每天上班都看着疑难Bug挂着无法解决,确实会很难受。这就像一个侦探遇到了疑难的案件,当他用尽各种手段收集线索,依然一无所获,那种心情可想而知。我们收集日志复现用户Bug的思路和侦探破案的思路非常相似,通过搜集的线索尽可能拼凑出相对完整的犯案场景。如果按照这个思路想下去,目前我们并没有什么更好的方法来处理这些问题。不过,虽然侦探破案和开发者查日志解决问题的思路很像,但实质并不一样。我们处理的是Bug,不是真实的案件。换句话说,因为我们的“死者”是可见的,那么就可以从它身上获取更多信息,甚至和它进行一次“灵魂的交流”。换个思路想,以往的操作都是通过各种各样的日志拼凑出用户出现Bug的场景,那可不可以先获取到用户在发生Bug的这段时间产生的所有日志(不采样,内容更详细),然后聚合这些日志分析出(筛除无关项)用户出现Bug的场景呢?个案分析新的思路重心从“日志”变为“用户”,我们称之为“个案分析”。简单来说,传统的思路是通过搜集散落在各系统的日志,然后拼凑出问题出现的场景,而新的思路是从用户产生的所有日志中聚合分析,寻找出现问题的场景。为此,我们进行了技术层面的尝试,而新的方案需要在功能上满足以下条件:支持多种日志收集,统一底层日志协议,抹平日志种类带来的差异。日志本地记录,在需要时上报,尽可能保证日志不丢失。日志内容要尽可能详细,不采样。日志类型可扩展,可由上层自定义。我们还需要在技术上满足以下条件:轻量级,包体尽量小API易用没有侵入性高性能横空出世在这种背景下,Logan横空出世,其核心体系由四大模块构成:日志输入日志存储后端系统前端系统最佳实践日志输入常见的日志类型有:代码级日志、网络日志、用户行为日志、崩溃日志、H5日志等。这些都是Logan的输入层,在不影响原日志体系功能的情况下,可将内容往Logan中存储一份。Logan的优势在于:日志内容可以更加丰富,写入时可以携带更多信息,也没有日志采样,只会等待合适的时机进行统一上报,能够节省用户的流量和电量。以网络日志为例,正常情况下网络日志只记录端到端延时、发包大小、回包大小字段等等,同时存在采样。而在Logan中网络日志不会被采样,除了上述内容还可以记录请求Headers、回包Headers、原始Url等信息。日志存储Logan存储SDK是这个开源项目的重点,它解决了业界内大多数移动端日志库存在的几个缺陷:卡顿,影响性能日志丢失安全性日志分散Logan自研的日志协议解决了日志本地聚合存储的问题,采用“先压缩再加密”的顺序,使用流式的加密和压缩,避免了CPU峰值,同时减少了CPU使用。跨平台C库提供了日志协议数据的格式化处理,针对大日志的分片处理,引入了MMAP机制解决了日志丢失问题,使用AES进行日志加密确保日志安全性。Logan核心逻辑都在C层完成,提供了跨平台支持的能力,在解决痛点问题的同时,也大大提升了性能。为了节约用户手机空间大小,日志文件只保留最近7天的日志,过期会自动删除。在Android设备上Logan将日志保存在沙盒中,保证了日志文件的安全性。详情请参考:美团点评移动端基础日志库——Logan后端系统后端是接收和处理数据中心,相当于Logan的大脑。主要有四个功能:接收日志日志解析归档日志分析数据平台接收日志客户端有两种日志上报的形式:主动上报和回捞上报。主动上报可以通过客服引导用户上报,也可以进行预埋,在特定行为发生时进行上报(例如用户投诉)。回捞上报是由后端向客户端发起回捞指令,这里不再赘述。所有日志上报都由Logan后端进行接收。日志解析归档客户端上报的日志经过加密和压缩处理,后端需要对数据解密、解压还原,继而对数据结构化归档存储。日志分析不同类型日志由不同的字段组合而成,携带着各自特有信息。网络日志有请求接口名称、端到端延时、发包大小、请求Headers等信息,用户行为日志有打开页面、点击事件等信息。对所有的各类型日志进行分析,把得到的信息串连起来,最终汇集形成一个完整的个人日志。数据平台数据平台是前端系统及第三方平台的数据来源,因为个人日志属于机密数据,所以数据获取有着严格的权限审核流程。同时数据平台会收集过往的Case,抽取其问题特征记录解决方案,为新Case提供建议。前端系统一个优秀的前端分析系统可以快速定位问题,提高效率。研发人员通过Logan前端系统搜索日志,进入日志详情页查看具体内容,从而定位问题,解决问题。目前集团内部的Logan前端日志详情页已经具备以下功能:日志可视化。所有的日志都经过结构化处理后,按照时间顺序展示。时间轴。数据可视化,利用图形方式进行语义分析。日志搜索。快速定位到相关日志内容。日志筛选。支持多类型日志,可选择需要分析的日志。日志分享。分享单条日志后,点开分享链接自动定位到分享的日志位置。Logan对日志进行数据可视化时,尝试利用图形方式进行语义分析简称为时间轴。每行代表着一种日志类型。同一日志类型有着多种图形、颜色,他们标识着不同的语义。例如时间轴中对代码级日志进行了日志类别的区分:利用颜色差异,可以轻松区分出错误的日志,点击红点即可直接跳转至错误日志详情。个案分析流程用户遇到问题联系客服反馈问题。客服收到用户反馈。记录Case,整理问题,同时引导用户上报Logan日志。研发同学收到Case,查找Logan日志,利用Logan系统完成日志筛选、时间定位、时间轴等功能,分析日志,进而还原Case“现场”。最后,结合代码定位问题,修复问题,解决Case。定位问题结合用户信息,通过Logan前端系统查找用户的日志。打开日志详情,首先使用时间定位功能,快速跳转到出问题时的日志,结合该日志上下文,可得到当时App运行情况,大致推断问题发生的原因。接着利用日志筛选功能,查找关键Log对可能出问题的地方逐一进行排查。最后结合代码,定位问题。当然,在实际上排查中问题比这复杂多,我们要反复查看日志、查看代码。这时还可能要借助一下Logan高级功能,如时间轴,通过时间轴可快速找出现异常的日志,点击时间轴上的图标可跳转到日志详情。通过网络日志中的Trace信息,还可以查看该请求在后台服务详细的响应栈情况和后台响应值。未来规划机器学习分析。首先收集过往的Case及解决方案,提取分析Case特征,将Case结构化后入库,然后通过机器学习快速分析上报的日志,指出日志中可能存在的问题,并给出解决方案建议;数据开放平台。业务方可以通过数据开放平台获取数据,再结合自身业务的特性研发出适合自己业务的工具、产品。平台支持PlatformiOSAndroidWebMini ProgramsSupport√√√√目前Logan SDK已经支持以上四个平台,本次开源iOS和Android平台,其他平台未来将会陆续进行开源,敬请期待。测试覆盖率由于Travis、Circle对Android NDK环境支持不够友好,Logan为了兼容较低版本的Android设备,目前对NDK的版本要求是16.1.4479499,所以我们并没有在Github仓库中配置CI。开发者可以本地运行测试用例,测试覆盖率可达到80%或者更高。开源计划在集团内部已经形成了以Logan为中心的个案分析生态系统。本次开源的内容有iOS、Android客户端模块、数据解析简易版,小程序版本、Web版本已经在开源的路上,后台系统,前端系统也在我们开源计划之中。未来我们会提供基于Logan大数据的数据平台,包含机器学习、疑难日志解决方案、大数据特征分析等高级功能。最后,我们希望提供更加完整的一体化个案分析生态系统,也欢迎大家给我们提出建议,共建社区。ModuleOpen SourceProcessingPlanningiOS√ Android√ Web √ Mini Programs √ Back End √Front End √团队介绍周辉,项目发起人,美团点评资深移动架构师。姜腾,项目核心开发者。立成,项目核心开发者。白帆,项目核心开发者。招聘点评平台移动研发中心,Base上海,为美团点评集团大多数移动端提供底层基础设施服务,包含网络通信、移动监控、推送触达、动态化引擎、移动研发工具等。同时团队还承载流量分发、UGC、内容生态、整合中心等业务研发,长年虚位以待有志于专注移动端研发的各路英雄。欢迎投递简历:hui.zhou#dianping.com。

October 12, 2018 · 1 min · jiezi

「造个轮子」——cicada(轻量级 WEB 框架)

前言俗话说 「不要重复造轮子」,关于是否有必要不再本次讨论范围。创建这个项目的主要目的还是提升自己,看看和知名类开源项目的差距以及学习优秀的开源方式。好了,现在着重来谈谈 cicada 这个项目的核心功能。我把他定义为一个快速、轻量级 WEB 框架;没有过多的依赖,核心 jar 包仅 30KB。也仅需要一行代码即可启动一个 HTTP 服务。特性现在来谈谈重要的几个特性。当前版本主要实现了基本的请求、响应、自定义参数以及拦截器功能。功能虽少,但五脏俱全。在今后的迭代过程中会逐渐完善上图功能,有好的想法也欢迎提 https://github.com/crossoverJie/cicada/issues。快速启动下面来看看如何快速启动一个 HTTP 服务。只需要创建一个 Maven 项目,并引入核心包。<dependency> <groupId>top.crossoverjie.opensource</groupId> <artifactId>cicada-core</artifactId> <version>1.0.0</version></dependency>如上图所示,再配置一个启动类即可。public class MainStart { public static void main(String[] args) throws InterruptedException { CicadaServer.start(MainStart.class,"/cicada-example") ; }}配置业务 Action当然我们还需要一个实现业务逻辑的地方。cicada 提供了一个接口,只需要实现该接口即可实现具体逻辑。创建业务 Action 实现 top.crossoverjie.cicada.server.action.WorkAction 接口。@CicadaAction(value = “demoAction”)public class DemoAction implements WorkAction { private static final Logger LOGGER = LoggerBuilder.getLogger(DemoAction.class) ; private static AtomicLong index = new AtomicLong() ; @Override public WorkRes<DemoResVO> execute(Param paramMap) throws Exception { String name = paramMap.getString(“name”); Integer id = paramMap.getInteger(“id”); LOGGER.info(“name=[{}],id=[{}]” , name,id); DemoResVO demoResVO = new DemoResVO() ; demoResVO.setIndex(index.incrementAndGet()); WorkRes<DemoResVO> res = new WorkRes(); res.setCode(StatusEnum.SUCCESS.getCode()); res.setMessage(StatusEnum.SUCCESS.getMessage()); res.setDataBody(demoResVO) ; return res; }}同时需要再自定义类中加上 @CicadaAction 注解,并需要指定一个 value,该 value 主要是为了在请求路由时能找到业务类。这样启动应用并访问 http://127.0.0.1:7317/cicada-example/demoAction?name=12345&id=10 便能执行业务逻辑同时得到服务端的返回。目前默认支持的是 json 响应,后期也会加上模板解析。服务中也会打印相关日志。灵活的参数配置这里所有的请求参数都封装在 Param 中,可以利用其中的各种 API 获取请求数据。之所以是灵活的:我们甚至可以这样请求:http://127.0.0.1:7317/cicada-example/demoAction?jsonData=“info”: { “age”: 22, “name”: “zhangsan” }这样就可以传递任意结构的数据,只要业务处理时进行解析即可。自定义拦截器拦截器是一个框架的基本功能,可以利用拦截器实现日志记录、事务提交等通用工作。为此 cicada 提供一个接口: top.crossoverjie.cicada.server.intercept.CicadaInterceptor。我们只需要实现该接口即可编写拦截功能:@Interceptor(value = “executeTimeInterceptor”)public class ExecuteTimeInterceptor implements CicadaInterceptor { private static final Logger LOGGER = LoggerBuilder.getLogger(ExecuteTimeInterceptor.class); private Long start; private Long end; @Override public void before(Param param) { start = System.currentTimeMillis(); } @Override public void after(Param param) { end = System.currentTimeMillis(); LOGGER.info(“cast [{}] times”, end - start); }}这里演示的是记录所有 action 的执行时间。目前默认只实现了 action 的拦截,后期也会加入自定义拦截器。拦截适配器虽说在拦截器中提供了 before/after 两个方法,但也不是所有的方法都需要实现。因此 cicada 提供了一个适配器:top.crossoverjie.cicada.server.intercept.AbstractCicadaInterceptorAdapter我们需要继承他便可按需实现其中的某个方法,如下所示:@Interceptor(value = “loggerInterceptor”)public class LoggerInterceptorAbstract extends AbstractCicadaInterceptorAdapter { private static final Logger LOGGER = LoggerBuilder.getLogger(LoggerInterceptorAbstract.class) ; @Override public void before(Param param) { LOGGER.info(“logger param=[{}]",param.toString()); }}性能测试既然是一个 HTTP 服务框架,那性能自然也得保证。在测试条件为:300 并发连续压测两轮;1G 内存、单核 CPU、1Mbps。用 Jmeter 压测情况如下:同样的服务器用 Tomcat 来压测看看结果。Tomcat 的线程池配置:<Executor name=“tomcatThreadPool” namePrefix=“consumer-exec-” maxThreads=“510” minSpareThreads=“10”/>我这里请求的是 Tomcat 的一个 doc 目录,虽说结果看似 cicada 的性能比 Tomcat 还强。但其实这个对比过程中的变量并没有完全控制好,Tomcat 所返回的是 HTML,而 cicada 仅仅返回了 json,当然问题也不止这些。但还是能说明 cicada 目前的性能还是不错的。总结本文没有过多讨论 cicada 实现原理,感兴趣的可以看看源码,都比较简单。在后续的更新中会仔细探讨这块内容。同时不出意外 cicada 会持续更新,未来也会加入更多实用的功能。甚至我会在适当的时机将它应用于我的生产项目,也希望更多朋友能参与进来一起把这个「轮子」做的更好。项目地址:https://github.com/crossoverJie/cicada你的点赞与转发是最大的支持。 ...

September 3, 2018 · 2 min · jiezi