微服务编排引擎 Netflix/Conductor 的精简/升级版实现 Brook

背景

这几年低代码的概念被说得很多,却不是什么新概念,这本身已经算是历史悠久了。从广义甚至可以说,平时我们做的代码设计:抽象、模块化、链条化、脚本化等,本身就是在"造"一个低代码引擎来降低/减少重复的工作量。

虽然网络上概念火热、讨论众多,但是作为一个后端开发者却没有什么好的选择------90%都是纯表单驱动的搭建工具。而我更想要一个原始的编排引擎,能构建出微服务编排、工作流等:

  • 模型驱动为主
  • 扩展简单方便
  • 可以调试定位
  • 只有点和线

实现

我调研了众多的引擎实现方案,发现比较契合的有 conductortemporal 。其中 conductor 是通过 DSL 进行流程编排,而 temporal 则通过写代码进行编排(可以更好地解决流程调试 DEBUG 的问题)。感兴趣的,可以点击链接进行更多地了解。

对于编排方式,秉承(中心化)用户不引入 SDK 、不写代码,可视化编排工具能更好集成的原则,现阶段我更倾向于选择 DSL。

但是在深度研究使用 conductor 后,我发现 conductor 的几个重要缺陷:

  • 不支持接口级流程编排(接口级编排恰恰是微服务编排的主要场景:多个接口按组合形成一个新的接口)。接口级是需要乃至毫秒级响应的接口。
  • 节点(Task)扩展很麻烦,主逻辑中存在大量具体节点相关的逻辑
  • 调度性能差

所以,结合多年的工作流和流程编排经验,我重新实现了 conductor,取名为 Brook。Brook 非常的轻量,不仅支持微服务,还支持应用内逻辑的编排执行(像责任链一样,还可以是动态的)。同时它不仅能中心化部署,还是嵌入到应用中运行。

Brook 仓库地址:github.com/mytang0/bro...

快速使用

为了最大限度地发挥 Brook 引擎的轻量级特性,其核心组件(仅依赖于一些必要的工具包)和使用 SPI(服务提供商接口)的中间件扩展之间进行了刻意的分离。因此,无论应用程序实现框架如何,都可以无缝依赖引擎JAR并初始化相关实例。

不使用 Springboot

xml 复制代码
<dependencies>
    <dependency>
        <groupId>xyz.mytang0.brook</groupId>
        <artifactId>>brook-engine</artifactId>
        <version>${brook.version}</version>
    </dependency>
</dependencies>

Springboot(推荐)

xml 复制代码
<dependencies>
    <dependency>
        <groupId>xyz.mytang0.brook</groupId>
        <artifactId>>brook-spring-boot-starter</artifactId>
        <version>${brook.version}</version>
    </dependency>
</dependencies>

样例(Demo)

运行

  • 克隆项目
bash 复制代码
git clone https://github.com/mytang0/brook.git
  • 导入 IDE
  • 运行Demo(brook-demo/brook-demo-spring)

DSL

只有一个 HTTP 节点的流程定义

bash 复制代码
{
  "name": "test-http",
  "description": "for showtime",
  "taskDefs": [
    {
      "type": "HTTP",
      "name": "test-http",
      "input": {
        "uri": "http://127.0.0.1:8080/flow/metadata",
        "method": "GET",
        "params": {
          "flowName": "${flow.input.flowName}"
        }
      }
    }
  ],
  "output": "${test-http.output}"
}

SPI

简单的编排节点扩展(Task 扩展)

typescript 复制代码
package xyz.mytang0.brook.demo.service;

import xyz.mytang0.brook.common.utils.JsonUtils;
import xyz.mytang0.brook.common.utils.TimeUtils;
import xyz.mytang0.brook.spring.boot.annotation.Taskable;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
public class DemoService {

    @Taskable(type = "test-void", description = "for testing")
    public void vd() {
    }

    @Taskable(type = "test-hello", description = "for testing")
    public String hello(String name) {
        return "Hello, " + name + " .";
    }

    @Taskable(type = "test-list", description = "for testing")
    public String list(List<Object> list) {
        return "list: " + JsonUtils.toJsonString(list);
    }

    @Taskable(type = "test-array", description = "for testing")
    public String array(Object[] array) {
        return "array: " + JsonUtils.toJsonString(array);
    }

    @Taskable(type = "test-map", description = "for testing")
    public String map(Map<String, Object> map) {
        return "map: " + JsonUtils.toJsonString(map);
    }


    @Taskable(type = "test-throw-iae", description = "for testing")
    public void throwIae() {
        throw new IllegalArgumentException();
    }

    @Taskable(type = "test-timeout", description = "for testing")
    public void timeout(Integer sleepSeconds) {
        if (sleepSeconds == null) {
            sleepSeconds = 5;
        }
        TimeUtils.sleep(sleepSeconds, TimeUnit.SECONDS);
    }
}
相关推荐
golang学习记14 分钟前
Go 嵌入结构体方法访问全解析:从基础到进阶陷阱
后端
NAGNIP31 分钟前
程序员效率翻倍的快捷键大全!
前端·后端·程序员
qq_2562470538 分钟前
从“人工智障”到“神经网络”:一口气看懂 AI 的核心原理
后端
无心水39 分钟前
分布式定时任务与SELECT FOR UPDATE:从致命陷阱到优雅解决方案(实战案例+架构演进)
服务器·人工智能·分布式·后端·spring·架构·wpf
用户4001883093741 分钟前
手搓本地 RAG:我用 Python 和 Spring Boot 给 AI 装上了“实时代码监控”
后端
用户34140819912543 分钟前
/dev/binder 详解
后端
Gopher_HBo1 小时前
Go进阶之recover
后端
程序员布吉岛1 小时前
写了 10 年 MyBatis,一直以为“去 XML”=写注解,直到看到了这个项目
后端
却尘1 小时前
一篇小白也能看懂的 Go 字符串拼接 & Builder & cap 全家桶
后端·go
茶杯梦轩1 小时前
从零起步学习Redis || 第七章:Redis持久化方案的实现及底层原理解析(RDB快照与AOF日志)
redis·后端