服务编排 
一言以蔽之
- 运行在云端的工作流编排引擎
工作流
- 处理一组数据的一系列任务
- 描述某事物从未完成到完成,或从原始到处理的路径
- 例子
定义
- 任务(Task):任务是组装工作流的最小的基础单元,工作流中至少有一项任务。任务由执行器(Worker)轮询执行
- 工作流(Workflow):即工作流程(业务流程),由若干任务组成,代表了真实的业务需求。如下图所示,每一步为一个任务。
- 执行器(Worker):Worker是实现了Worker接口的独立进程,它通过轮询任务队列的方式来获取任务,执行完任后,调用管理接口主动推送任务执行结果
概念关系
工作流与微服务
姿势 
- 定义用来组装业务流程的任务
- 定义由若干任务组装的业务流程
- 创建任务执行器定期轮询任务
- 查看流程执行结果
如何工作
高层架构
- 架构亮点 - API层与存储层提供了可插拔特性,可以与不同的后端和队列服务提供者一起工作
运行时模型
- Conductor遵循基于RPC的通讯模型
- Workers 作为远程系统通过HTTP协议与Conductor Servers通信
- 通过任务队列为Workers调度任务
- 支持不同的数据库作为存储和索引的实现
系统组件
特性
- 分布式服务系统,可以高效的存储工作流状态信息
- 允许创建流程、业务流程,其中每个单独的任务都可以由相同/不同的微服务实现
- 具有合理默认值的各种可配置属性,可以微调工作流和任务执行,例如速率限制,并发执行限制等
- 基于JSON DSL定义的执行流程
- 高性能,能够扩展到数百万个并发运行的流程
- 支持同步处理所有任务
- 支持由客户端抽象的队列服务
- 支持事件处理,可以通过外部操作来控制工作流
- 支持多语言的客户端(Java、Python等)
- 内置丰富的逻辑处理能力(Decision/Sub-Workflow/Fork/Join/Do-While/Wait/Event/Error Handling等)
- 提供了可观察、可追踪等若干管控能力
目的
以现有分布式微服务为基础数据,搭建分布式服务编排平台。目标是现有服务无需特殊改造即能灵活装配出新的业务能力,更好地发挥现有服务的业务价值,减少冗余的服务数量。提供丰富的编排能力,适应客户丰富的业务场景,并保障配置的业务流程能高效运行。除了以上基本功能外,还保证分布式数据的一致性、高并发、跨可用区高可用。
价值
服务编排系统可以帮助我们编排现有的微服务,以提高现有业务的整合能力,极大程度实现服务重用、服务增强,减少了开发成本,从而实现企业的降本增效,以及加速企业新业务研发。
场景
- 奈飞 - 内容工程
- 内容提取与传送
- 内容本地化
- 内容质量控制
- 现有业务增强,比如资产交易形态的转变
- 打通现有孤立业务,比如打通HR/CMS/OA独立的系统功能
- 根据现有业务编织新业务,比如复用现有的CMS
工程解析
| Artifact | Description |
|---|---|
| conductor-common | Common models used by various conductor modules |
| conductor-core | Core Conductor module |
| conductor-redis-persistence | Persistence and queue using Redis/Dynomite |
| conductor-cassandra-persistence | Persistence using Cassandra |
| conductor-mysql-persistence | Persistence and queue using MySQL |
| conductor-postgres-persistence | Persistence and queue using Postgres |
| conductor-es6-persistence | Indexing using Elasticsearch 6.X |
| conductor-rest | Spring MVC resources for the core services |
| conductor-ui | node.js based UI for Conductor |
| conductor-contribs | Optional contrib package that holds extended workflow tasks and support for SQS, AMQP, etc |
| conductor-client | Java client for Conductor that includes helpers for running worker tasks |
| conductor-client-spring | Client starter kit for Spring |
| conductor-server | Spring Boot Web Application |
| conductor-azureblob-storage | External payload storage implementation using AzureBlob |
| conductor-redis-lock | Workflow execution lock implementation using Redis |
| conductor-zookeeper-lock | Workflow execution lock implementation using Zookeeper |
| conductor-grpc | Protobuf models used by the server and client |
| conductor-grpc-client | gRPC server Application |
| conductor-grpc-server | gRPC client to interact with the gRPC server |
| conductor-test-harness | Integration and regression tests |
核心亮点
- 无状态
- 多数据中心
- 分布式锁
- 基于中间件的任务队列
- 可插拔组件
- 模块化加载
Worker实现
* 实现Worker Interface
public class SampleWorker implements Worker {
private String taskDefName;
public SampleWorker(String taskDefName) {
this.taskDefName = taskDefName;
}
@Override
public String getTaskDefName() {
return taskDefName;
}
@Override
public TaskResult execute(Task task) {
TaskResult result = new TaskResult(task);
result.setStatus(Status.COMPLETED);
//Register the output of the task
result.getOutputData().put("outputKey1", "value");
result.getOutputData().put("oddEven", 1);
result.getOutputData().put("mod", 4);
return result;
}
}
- 轮询任务队列
public static void main(String[] args) {
TaskClient taskClient = new TaskClient();
taskClient.setRootURI("http://localhost:8080/api/"); //Point this to the server API
int threadCount = 2; //number of threads used to execute workers. To avoid starvation, should be same or more than number of workers
Worker worker1 = new SampleWorker("task_1");
Worker worker2 = new SampleWorker("task_5");
// Create TaskRunnerConfigurer
TaskRunnerConfigurer configurer = new TaskRunnerConfigurer.Builder(taskClient, Arrays.asList(worker1, worker2))
.withThreadCount(threadCount)
.build();
// Start the polling and execution of tasks
configurer.init();
}