状态机

有限状态机

定义:FSM - finite-state machine,表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。

  • 状态是描述系统对象在某个时刻所处的状况。
  • 转移指示状态变更,一般是通过外部事件为条件触发状态的转移。
  • 动作是对给定状态下要进行的操作。

简而言之,状态机是由事件、状态、动作三大部分组成。三者的关系是:事件触发状态的转移,状态的转移触发后续动作的执行。其中动作不是必须的,也可以只进行状态转移,不进行任何操作。

优点:状态的转移和业务逻辑基于时间完全解耦
image

以下是短信活动状态机示例:
image

关键概念

  • 状态State:一般在状态转移图中用圆圈表示。
  • 事件Event:表示从一种状态迁移到另一种状态的触发机制。对应状态转换图中的箭头部分。
  • 动作Action: 表示状态转换后,执行的动作,但不是必须的,也可以状态转换后不执行任何动作。
  • 转移Transition:表示状态转换,从原始状态迁移到目的状态的一个过程。
  • 条件Guard:表示发生状态转移需满足的条件。

实现方式

状态机的实现方式有以下几种:
1、基于条件判断实现
适用场景
适用于业务状态个数少或者状态间跳转逻辑比较简单的场景。

缺陷
当触发事件和业务状态之间对应关系不是简单的一对一时,就需要嵌套多个条件分支判断,分支逻辑会变得异常复杂;当状态流程有变更时,也需要改动分支逻辑,不符合开闭原则,代码可读性和扩展性非常差。

2、基于状态模式实现
适用场景
适用于业务状态不多且状态转移简单的场景,相比于前面的if/switch条件分支法,当业务状态流程新增或修改时,影响粒度更小,范围可控,扩展性更强。

缺陷
同样难以应对业务流程状态转移复杂的场景,此场景下使用状态模式会引入非常多的状态类和方法,当状态逻辑有变更时,代码也会变得难以维护。

3、基于DSL实现
DSL 全称是 Domain-Specific Languages,指的是针对某一特定领域,具有受限表达性的一种计算机程序设计语言。不同于通用的编程语言,DSL只用在某些特定的领域,聚焦于解决该领域系统的某块问题。DSL通常分为 内部 DSL ( Internal DSLs ),外部 DSL ( external DSLs ) 。

使用DSL作为开发工具,可以用更加清晰和更具表达性的形式来描述系统的行为。DSL 也是目前实现状态机比较推荐的方式,可以根据自身的需要选用内部 DSL 或者外部DSL 来实现。

内部 DSL :业务系统如果只希望通过代码直接进行状态机的配置,那么可以选择使用内部 DSL,特点是简单直接,不需要依赖额外的解析器和组件。
外部 DSL :可以利用外部存储和通用脚本语言的解析能力,实现运行时动态配置、支持可视化配置和跨语言应用场景。

外部 DSL 本质上就是将状态转移过程用其他外部语言进行描述,比如使用 XML 的方式。

<state id= "STATE1">
  <transition event="EVENT1"  target="STATE2">
    <action method="action1()"/>
  </transition>
</state>
 
<state id= "STATE2">
</state>

Java开源的状态机框架基本上都是基于DSL的实现方式。

开源框架

1、Spring Statemachine
优点:功能十分完备,除了支持基本的状态机配置外,还具备可嵌套的子状态机、基于zk的分布式状态机和外部存储持久化等丰富的功能特性。

缺点:Spring Statemachine 在每个 statemachine 实例内部保存了当前状态机上下文相关的属性,也就是说是有状态的(这一点从触发状态机流转只需事件作为参数也可以看出来),所以使用单例模式的状态机实例不是线程安全的。要保证线程安全性只能每次通过工厂模式创建一个新的状态机实例,这种方式在高并发场景下,会影响系统整体性能。

代码层次结构稍显复杂,二次开发改造成本大,一般场景下也并不需要使用如此多的功能,使用时观感上显得比较沉重。

2、Squirrel-foundation
squirrel-foundation 是一款轻量级的状态机库,设计目标是为企业使用提供轻量级、高度灵活、可扩展、易于使用、类型安全和可编程的状态机实现。

优点:和目标理念一致,与 Spring Statemachine 相比,不依赖于spring框架,设计实现方面更加轻量,虽然也是有状态的设计,但是创建状态机实例开销较小,功能上也更加简洁,相对比较适合二次开发。

缺点:过于强调“约定优于配置”的理念,不少默认性的处理,比如状态转移后动作是通过方法名来调用,不利于操作管理。

3、Cola Statemachine
Cola Statemachine 是阿里COLA开源框架里面的一款状态机框架,和前面两者最大的不同就是:无状态的设计——触发状态机流转时需要把当前状态作为入参,状态机实例中不需要保留当前状态上下文消息,只有一个状态机实例,也就直接保证了线程安全性和高性能。

优点:轻量级无状态,安全,性能高。设计简洁,方便扩展。

缺点:不支持嵌套、并行等高级功能。

开发实践

设计目标

  • 无状态高性能
  • 功能简洁
  • 动作异步执行

状态机配置可视化,结合外部DSL的方式(比如JSON的方式,存储到数据库中),支持更快速的配置。
image

核心流程

  • 沿用开源状态机的内部DSL流式接口设计,在应用启动时扫描状态机定义
  • 创建异步处理线程池支持业务的后置动作;
  • 解析状态机的DSL配置,初始化状态机实例;
  • 构建执行上下文,存放各个状态机的实例和其他执行过程信息;
  • 状态机触发时,根据触发条件和当前状态,自动匹配转移过程,推动状态机流转;
  • 执行后置同步/异步处理操作。

参考

状态机引擎在vivo营销自动化中的深度实践

posted @ 2023-08-01 07:52  NewQ  阅读(216)  评论(0编辑  收藏  举报