返回 登录
0

Netflix Conductor:微服务编排引擎

原文Netflix Conductor : A microservices orchestrator
作者:Viren Baraiya, Vikram Singh 翻译:Daisy 责编:仲培艺

Conductor是Netflix开源的一款微服务编排引擎,托管在GitHub上,使用Apache License 2.0许可。

Conductor是受到Netflix需要运行全球流媒体业务流程的启发,而构建的基于云的微服务编排引擎。

下面是一些流程案例:

  • 用来提取内容的Studio合作伙伴集成;
  • 基于IMF的内容提取;
  • 在Netflix中设置新标题流程;
  • 内容提取、编码和部署到CDN。

通常,其中的部分流程会专门使用pub/sub组合直接REST调用,并使用一个数据库来管理状态编排。但随着微服务数量和流程复杂性的增加,如果没有中央协调器,那么获得这些分布式工作流的难度就会加大。

为什么不使用对等编排?

Pub/sub模型适用于一些简单的流程,对等编排很难进行扩展,并且很快就发现了很多问题:

  • 流程流被嵌套在多个应用代码内;
  • 通常,围绕输入/输出、SLAs等方面存在的紧耦合和假设,导致很难适应不断变化的需求;
  • 几乎没有办法系统地回答:“进程完成情况”。

Netflix将Conductor构建为一个编排引擎,可以满足以下需求,在应用中消除样板需求,并提供一个反应流:

  • 使用JSON DSL描述的工作流蓝图;
  • 跟踪和管理工作流;
  • 可以暂停、恢复和重新启动任务;
  • 可视化的用户流程界面;
  • 可根据需要,同步处理所有执行任务;
  • 处理工作流能够扩展到百万级别;
  • 可抽离客户端的排队服务;
  • 支持HTTP或其他传输方式,如gRPC。

Conductor已经在Netflix内部使用了近一年。Netflix称其已经帮助编排超过260万个流程,从简单的线性工作流程到运行多天的非常复杂的动态工作流程都有。

图片描述

Conductor的架构图

该引擎的核心是状态机服务,也叫作决策器服务。当工作流事件(例如:任务完成、失败等),决策器将工作流蓝图与工作流的当前状态组合,识别下一个状态,并调度适当的任务或更新工作流的状态。

Decider使用分布式队列管理任务调度。Netflix一直在Dynomite上使用dyno-queues来管理分布式延迟队列。Dynomitedyno-queues都已经开源,这里是当初的开源文章

任务实现Worker

工作流任务由Worker实现,并通过API层进行通信。Worker通过编排引擎调用REST端点或者通过实现定期检查挂起的任务轮询循环来实现。轮询模型允许用户在Workers上处理背压,并在可能时,基于队列深度提供自动可伸缩性。Conductor提供API来检查每个Worker的工作负载大小,这样就可以自动伸缩Worker实例。

图片描述

Worker与引擎直接通信图

  • API层——使用HTTP或gRPC轻松集成各个不同的客户端。
  • 存储——使用Dynomite作为存储方案,Elasticsearch作为索引流执行方案。存储API是可插拔的,可用于各种存储系统,包括传统的RDBMS或Apache Cassandra。

核心概念

工作流定义

工作流是使用基于JSON的DSL定义的,工作流蓝图定义了需要执行的一系列任务。要么是控制任务(例如:叉、连接、决策、子工作流等),要么是Worker任务。工作流还可以进行版本控制,可以灵活地进行升级和迁移。

工作流定义概述:

 {
  "name": "workflow_name",
  "description": "Description of workflow",
  "version": 1,
  "tasks": [
    {
      "name": "name_of_task",
      "taskReferenceName": "ref_name_unique_within_blueprint",
      "inputParameters": {
        "movieId": "${workflow.input.movieId}",
        "url": "${workflow.input.fileLocation}"
      },
      "type": "SIMPLE",
      ... (any other task specific parameters)
    },
    {}
    ...
  ],
  "outputParameters": {
    "encoded_url": "${encode.output.location}"
  }
}

任务定义

每个任务行为都由其任务定义模板控制。每个任务定义会提供任务参数,例如,超时,重试策略等。任务有两种,一个是Worker,运行在远端机器上的用户任务;一个System,运行在引擎的JVM上的任务。后者用来对Worker执行任务进行branch、fork、join。Worker任务通过HTTP或者gRPC(基于HTTP/2)和Conductor通信。

任务定义JSON代码片段:

 {
  "name": "encode_task",
  "retryCount": 3,
  "timeoutSeconds": 1200,
  "inputKeys": [
    "sourceRequestId",
    "qcElementType"
  ],
  "outputKeys": [
    "state",
    "skipped",
    "result"
  ],
  "timeoutPolicy": "TIME_OUT_WF",
  "retryLogic": "FIXED",
  "retryDelaySeconds": 600,
  "responseTimeoutSeconds": 3600
}

输入/输出

输入任务JSON代码片段:

{
      "name": "name_of_task",
      "taskReferenceName": "ref_name_unique_within_blueprint",
      "inputParameters": {
        "movieId": "${workflow.input.movieId}",
        "url": "${workflow.input.fileLocation}"
      },
      "type": "SIMPLE"
    }

未来计划

  • 支持AWS Lambda(或类似)函数作为无服务器任务;
  • 与容器编排框架进行更紧密的集成,这样工作实例就可以自动扩展;
  • 记录每个任务的执行数据;
  • 从UI上实现创建和管理工作流蓝图。
评论