Skip to main content

问题汇总和解答

Q:LiteFlow支持事务么?

A:不能说支持或者说不支持,因为LiteFlow和事务没有本质上的关系。LiteFlow只不过在本地帮你把代码进行组件化和可编排化,事务还是按照原先的方式去做。例如,你完全可以加@Transactional来开启spring事务:

@Transactional
public void testIsAccess() {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1", 101);
}

那么,这个链路中的所有组件,只要有一个组件发生异常,那么执行过的本地事务就会回滚,同理,你可以在任意地点加编程式事务。

同理,如果涉及到分布式事务,你也可以采用任意一种分布式事务的解决方案来做,这本质上已经脱离了LiteFlow的讨论范畴。

Q:LiteFlow适用于什么场景?

A:LiteFlow适用于具有复杂逻辑,逻辑复用性比较强的业务系统,可以利用LiteFlow框架对业务进行解耦,编排,复用,动态更新,使代码更加优雅。

LiteFlow使用场景不限业务,只要你的业务系统可以根据业务边界来划分出来一个个独立的组件逻辑。既可以使用LiteFlow框架来优化你的代码。

Q:是否可以做审批流或者角色轮转的流程?

A:其实在开篇LiteFLow是什么已经有提到过,LiteFlow不做基于角色流转的流程,只做逻辑流程。并且LiteFlow在以后,也不会做基于角色流转的流程,因为LiteFlow要保持轻量和易用性,是一个无状态的流程编排工具。如果你的业务是基于角色流转的,推荐使用Flowable。

Q:是否可以运行到一半手动停止,然后下次继续运行链路?

A:不可以。LiteFlow是一个无状态的规则引擎。不对中间状态进行存储。LiteFlow更希望业务一次性运行完,并且自己保证其幂等性。如果你确实有业务场景,需要运行到一半手动停止。那么建议你去使用Flowable等一些有状态的流程引擎框架。

Q:Slot里的数据是线程安全的吗?

A:LiteFlow虽然提供了默认的Slot实现,但是更建议用户自己去实现Slot(这点在文档中数据槽那章也提到过)。Slot本质上是一个普通的值对象,虽然LiteFlow能保证Slot本身的线程安全(指在多线程情况下,多个请求Slot不会串),但是Slot内数据的线程安全性是无法保障的,这需要用户自己去定义其线程安全的属性。比如你在Slot里定义了一个int的变量,多个异步节点对其进行增加,那当然会有线程安全的问题。你需要在你自己定义的Slot内部去声明一个AtomicInteger对象,从而保证线程安全。

Q:流程要如何保存到数据库中,如何定义模型?

A:在LiteFlow框架中,你可以用两种办法来解决。

第一种是利用自定义配置源功能。你可以将配置信息(xml/json/yml)原样保存到数据库中 ,然后在自定义配置源中将其读出来。这种方式有一个明显的缺点:数据库中如何去保存全量的配置信息,总不见得就用一个字段保存整段xml吧。如果数据库要对整段配置信息进行信息的拆分字段存储。那在自定义配置源中,就必须要自行组装成xml/json/yml再返回了。这个也是有一定工作量的。

第二种是后来推出的代码动态构造规则。其实官方更建议用这种方式去从数据库构建规则。在这种模式下,数据库就可以对配置信息进行拆分字段存储,而不用关心配置格式(xml/json/yml)。你可以在执行execute之前的任意时段,去用代码去构建节点和规则。建议是在启动项目时去构建。这样就能完美解决数据库的信息拆分存储了。

Q:为什么Slot要用map持有存储,而不是放在threadlocal中呢?

A:用ThreadLocal去实现,理论上是可以实现的。但是可以这样实现,不代表要用这种方式去做。其目的在于ThreadLocal虽然能实现,但是无法管理。你无法在ThreadLocal上做更多的扩展,而自己实现的这种,更容易做管理和任意扩展。

Q:LiteFlow性能如何?

A:LiteFlow本身性能优秀,几乎没有什么额外的损耗,在压测过程中,基于复杂的价格逻辑引擎的业务系统,三十多个组件,在实测中可以跑到单机1500多的TPS。当然,这是基于良好的组件实现逻辑的前提下。如果你的组件里有一个bad sql,或者大量的IO操作,RPC调用操作,那么任何框架也无法提升你业务的TPS。这里只能说LiteFlow框架本身对系统几乎无额外损耗,如果你的系统使用了LiteFlow但是TPS/QPS很低的话,那么请从你的组件实现逻辑入手排查。

Q:是否支持逆向执行,来实现回滚等操作?

A:不支持,如果要实现本地回滚,请用事务来控制,如果涉及分布式事务的回滚,也有分布式事务的解决方案可以用。

但是之后的版本可能会出一个特性,在执行的过程中,如果遇到某个Exception去执行额外的链路,如果真的想逆向执行,可以把回滚组件放到这个里面。

Q:是否支持界面编排?

A:暂时不支持,但是在LiteFlow规划蓝图中,最终是要实现界面编排的。我本身不擅长前端,也请有这方面经验的同学能联系我。帮忙一起贡献开源。

Q:可以配置多个规则文件吗?

A:可以。用逗号或者分号隔开即可。

Q:如何做高可用,分布式的编排?

A:LiteFlow是轻量级的单服务编排,你可以把它理解为一个工具包。和高可用,分布式没有关系。

你一个业务系统里面有50个组件,liteflow可以编排,复杂一点的也可以。但是你多个业务系统,想要用一个链路,去编排不同服务里的组件。先去调用A服务的组件a,再去调用B服务的组件b,再去调用C服务的组件c,这种LiteFlow并不支持。

变相的实现,只有你独立出来一个服务X,然后服务X写3个组件(x1,x2,x3)分别用rpc去调用a,b,c,然后把x1,x2,x3编排成一个链路。

但是对LiteFlow来说,它运行的组件也只是X服务中的3个组件,至于组件里面是rpc调用还是其他网络IO操作,这和LiteFlow本身没有关系,因为已经涉及到业务实现层了。

Q:DataBus为什么采用queue和array来维护数据槽索引和数据槽对象的关系,为什么不直接使用数组?

A:在早期版本中,的确是用数组来维护SLOT的存储,为了解决并发问题,在offerSlot这个方法上采用synchronized来控制,这样会存在3个问题:

1.这种重量级锁性能很差

2.而且存在非公平的竞争关系,竞争会进一步增加系统的开销。

3.数组为了获取到可用的SLOT,会进行遍历,直到获取到可用的,如果前面都1000个都被占用了,就要遍历1001遍才能获取到可用的。

为了性能考虑,后来的版本采用了无锁化设计,采用CAS来解决,这样更加优雅且性能高。在开源框架中,能不用重量级锁就不用,无锁化且保证并发安全性是最优雅的做法。

Q:chain嵌套的时候slot对象是共享还是独自的,slotIndex存在冲突可能?

A:LiteFlow对SLOT的定义是:同一个请求链路中,SLOT为共享数据。

所以嵌套的时候SLOT对象是共享的,如果是独立的,那就无法适用同一个请求,一个上下文这个设计理念。

SLOT只有在执行FlowExecutor.execute才会进行分配,然后会放在ThreadLocal里面,在碰到嵌套链路时,也会实际执行嵌套链路里的组件,其实本质上和放在同一个链路里没有太多区别,因为都是同一个线程(或者主线程派发的子线程)中,所以能实现SLOT的共享机制

这里还有个例外,就是隐式流程(关注这个概念可以参照使用详细指南/隐式流程一章),隐式流程也是会执行FlowExecutor.execute这个方法,但是在处理时,隐式流程不会去分配SLOT,而是把上主流程中的slotIndex传递过去,这样也就实现了即使是隐式流程,也能SLOT共享的特性。

slotIndex不可能存在冲突,这和offerSlot的逻辑有关。前面已经解释过了。

Q:监控的插入点方式?

A:目前监控的逻辑插入点是在NodeComponent里面的execute里面写代码做统计的,这块目前的确比较耦合,并没有抽出来专门做。监控这块目前的确未仔细去做,只是一个非常简陋的监控,等有界面管理的时候,这块会重新设计模型去花精力去完善。