使用Spring Boot、Spring State Machine Framework和Zookeeper构建分布式状态机 - ÖzdinçÇelikel


通过将Apache Zookeeper与Java Spring State Machine框架集成在一起,为构建分布式状态机提供一个框架。
所谓Java Spring State Machine框架:应用程序现在处于并且可能以有限数量的状态存在。然后会发生一些事情,将您的应用程序从一种状态转移到另一种状态。状态机由触发器驱动,触发器基于事件或计时器。
状态机的分布式属性在默认状态机实现的基础上带有一个抽象层,目前仅存在一个基于Apache Zookeeper的实现,Apache Zookeeper是一种分布式应用程序的 协调服务。我的建议是在深入了解之前,通过此链接阅读官方的Spring State Machine文档。

对于此示例,状态机将具有3个状态:
UNPARID --->PAY事件--->WAITING --->RECEIVE事件 --->DONE

为了使用Spring Boot状态机框架,将使用maven将所需的依赖项注入到项目结构中:

<dependency> 
<groupId>org.springframework.statemachine </ groupId> 
<artifactId>spring-statemachine-core </ artifactId> 
<version>2.1.3.RELEASE </ version> 
</dependency>

导入此依赖项后,不要忘记干净的target /目录,再次将项目文件安装到本地存储库,并通过以下maven命令在target /目录下生成类:

mvn clean && mvn install && mvn complie

在此示例中,有4个容器是状态机的主机。这些容器将通过docker-compose进行编排。其中三个容器将执行相同的分布式状态机,其余的将作为Apache Zookeeper二进制文件的主机。在每个容器中执行状态机时,它们都将使用相同的Apache Zookeeper实例-znode-进行分发。因此,通过使用Apache Zookeeper建立状态机的分布式属性。Spring还有一个很好的例子来理解这种用法​​。
首先,需要一个Spring Configuration类,该类带有@Configuration注释,并充当bean定义的容器。

@Configuration                       
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<States, Events> {...}

下一个要做的事情是配置状态,事件 -启动状态转换的触发器,以及在动作处理期间触发的转换动作,您可以阅读本章 有关配置类内部的内容:

@Override
public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
        throws Exception {
            transitions
            .withExternal()
            .source(States.UNPAID).
             target(States.WAITING_FOR_RECEIVE)
            .event(Events.PAY)
            .action(transitionAction())
            
            .and()
            
            .withExternal()
            .source(States.WAITING_FOR_RECEIVE)
            .target(States.DONE)
            .event(Events.RECEIVE)
            .action(transitionAction())
            
            .and()
            
            .withExternal()
            .source(States.DONE).target(States.UNPAID)
            .event(Events.STARTFROMSCRATCH)
            .action(transitionAction());
}

在Configuration类内部,需要通过传递curotorClient来实例化集合,curotorClient是用于简化Zookeeper功能的使用的API,并且basePath指示基本的Zookeeper 路径,将用于创建znodes,强烈建议您依次阅读官方文档习惯术语。

@Bean                           
public StateMachineEnsemble<States, Events> stateMachineEnsemble() throws Exception {                                              
return new ZookeeperStateMachineEnsemble<States, Events>(curatorClient(), "/zkPath");                           }

stateMachineEnsemble bean很快会在最后一步中用于声明分布式状态机。
创建CuratorFramework实例时,应知道托管Apache Zookeeper二进制文件的计算机的IP /主机名。将docker-compose用作编排工具,以便将定位Apache Zookeeper的计算机的主机名作为环境变量传递。除此之外,将使用Zookeeper默认端口2181,如下:

@Bean                           
public CuratorFramework curatorClient() throws Exception {
      String zkConnectionString = "zookeeper:2181";  
      RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
       CuratorFramework client = CuratorFrameworkFactory.builder()
                                      .defaultData(new byte[0])
                                      .retryPolicy(retryPolicy)
                                      .connectString(zkConnectionString)
                                      .build();                              
      client.start();                               
      CuratorFrameworkState state = client.getState();                                    
      System.out.println(
"State ----> " + state.name());                               
      return client;                           
}

下面是最后一步,使用如上所述注入的stateMachineEnsemble bean 声明分布式状态机:

@Override                           
public void configure(StateMachineConfigurationConfigurer
<States, Events> config) throws Exception {
config                                       
 .withDistributed()
 .ensemble(stateMachineEnsemble());
}

当zookeeper和statemachines连接时,Z序节点可以或者与查询内置zookeeper命令或CuratorFramework内置的方法:

实现的细节见链接,整个项目在