跳转至

部署和维护 / 架构、扩容与限制资源

本文主要介绍 DataFlux Func 的整体架构,以及如何进行扩容来提高处理能力。

1. 架构

在系统内部,是典型的「生产者 -> 消费者」模型。任何一次 Python 函数的执行,都会经过「生成任务 -> 入队 -> 出队 -> 执行 -> 返回结果」的流程。

任何 Python 函数,实际都会先包装成「任务」进入其所属的「工作队列」(从 #0 开始编号),之后由对应的「工作单元」(从 worker-0 开始编号)从队列取出后执行。

flowchart TB
    USER[用户]
    FUNC_SERVER[Func Server 服务]
    REDIS_QUEUE_N[Redis 队列 #N]
    FUNC_WORKER_N[Func Worker-N 服务]
    FUNC_BEAT[Func Beat 服务]

    USER --HTTP 请求--> FUNC_SERVER

    FUNC_SERVER --函数执行任务入队--> REDIS_QUEUE_N

    REDIS_QUEUE_N --函数执行任务出队--> FUNC_WORKER_N

    FUNC_BEAT --"函数执行任务入队
    (定时任务)"--> REDIS_QUEUE_N

1.1 服务及其用途

DataFlux Func 包含多个服务,每个服务都有其不同的职责,具体服务如下:

服务 用途
server Web 服务,提供如下功能:
1. Web 界面
2. API 接口
3. 维护订阅器
worker-{队列序号} 工作单元,用于执行用户脚本,包括:
1. 同步 API(旧版「授权链接」)
2. 异步 API(旧版:批处理)
3. 定时任务(旧版:自动触发配置)
同时也会处理一些系统级后台任务
具体见队列说明
beat 定时任务的触发器
mysql 数据库
redis 缓存 / 函数执行任务队列

1.2 工作单元与队列监听关系

对于服务 worker-{队列序号}(工作单元),每个 Worker 服务都仅监听特定的若干个队列:

队列与工作单元之间不必一一对应

队列与工作单元并不是必须一一对应,如:工作单元 worker-0 并非只能监听队列 #0 的任务,每个工作单元都可以监听任意一个或多个队列

并且,同一个队列也可以被多个工作单元同时监听,也可以不被监听(不推荐)

独立部署 Func 与观测云部署 Func 的队列不同

由于大部分独立部署 Func 都是较为轻度使用,为了减少不必要的资源消耗,独立部署 Func 的工作单元数量小于队列数量

相反,观测云附属 Func 由于承接观测云监控器、消息发送模块(Message Desk)等重度业务,工作单元与队列一一对应,且比独立部署 Func 存在更多编号的工作单元和队列

工作单元 队列
独立部署
队列
观测云附属
worker-0 #0, #4, #7, #8, #9 #0
worker-1 #1 #1
worker-2 #2 #2
worker-3 #3 #3
worker-4 - #4
worker-5 #5 #5
worker-6 #6 #6
worker-7 - #7
worker-8 - #8
worker-9 - #9
worker-10 - #10
worker-11 - #11
worker-12 - #12
worker-13 - #13
worker-14 - #14
worker-15 - #15
工作单元 队列
独立部署
队列
观测云附属
worker-0 #0, #4, #7, #8, #9 #0
worker-1 #1 #1
worker-2 #2 #2
worker-3 #3 #3
worker-4 - #4
worker-5 #5 #5
worker-6 #6 #6
worker-7 - #7
worker-8 - #8
worker-9 - #9
工作单元 队列
worker-0 #0
worker-1-6 #1, #2, #3, #4, #5, #6
worker-7 #7
worker-8-9 #8, #9

2. 服务 / 队列及其职责与扩容建议

扩容需要更多硬件投入

扩容需要所在服务器提供更高的性能要求,包括且不限于服务器本身、数据库服务、Redis 等

一般来说,对 DataFlux Func 的扩容实际只需要增加对应服务的副本数即可,因此,用于应当首先了解自己实际业务情况,以便针对性地进行扩容。

完整的服务、队列及其职责、扩容建议如下:

服务 / 队列 职责
独立部署
职责
观测云附属
默认 Pod 数量
观测云附属
扩容建议
server Web 服务,提供如下功能:
1. Web 界面
2. API 接口
3. 维护订阅器
← 同左 1 一般不需要扩容
server-inner (无此服务) Web 服务,专供观测云在集群内部调用 API 1 一般不需要扩容
worker-0
队列 #0
系统工作单元,不直接参与用户代码的处理 ← 同左 2 一般不需要扩容
worker-1
队列 #1
执行来自同步 API(旧版:授权链接)的函数任务 ← 同左 1 需要提高同步 API(旧版:授权链接)并发量时可扩容
worker-2
队列 #2
执行来自定时任务(旧版:自动触发配置)的函数任务 ← 同左 1 需要提高定时任务(旧版:自动触发配置)并发量时可扩容
worker-3
队列 #3
执行来自异步 API(旧版:批处理)的函数任务 ← 同左 1 需要提高异步 API(旧版:批处理)并发量时可扩容
worker-4
队列 #4
(预留) (预留) 0 不需要扩容
worker-5
队列 #5
调试代码执行
即在 Web 界面直接运行函数
← 同左 1 需要支持更多用户同时开发脚本时扩容
worker-6
队列 #6
执行来自连接器订阅消息处理的函数任务 ← 同左 1 需要提高连接器订阅消息处理并发量时可扩容
worker-7
队列 #7
(预留) 执行观测云系统业务的函数任务
如:通过观测云后台管理员登录、更新各类缓存、释放消息聚合池等
2 监控器总数量较多时扩容
worker-8
队列 #8
(预留) 执行观测云阈值检测等普通监控器相关的函数任务 5 当普通监控器数量较多时扩容
worker-9
队列 #9
(预留) 执行观测云高级检测、智能监控的函数任务 3 当普通高级检测、智能监控器数量较多时扩容
worker-10
队列 #10
(无此服务) 执行观测云接收用户上报事件的函数任务 1 当用户上报事件量较大时扩容
worker-11
队列 #11
(无此服务) 执行观测云 Message Desk 消息发送任务 3 当消息发送量较大时扩容
worker-12
队列 #12
(无此服务) (预留) 0 不需要扩容
worker-13
队列 #13
(无此服务) (预留) 0 不需要扩容
worker-14
队列 #14
(无此服务) 执行观测云中,需要立即响应用户操作的 AI 相关处理
如:调用「自动编写 Pipeline」等
2 当需要支持更多用户同时编写 Pipleline 人数较多时扩容
worker-15
队列 #15
(无此服务) 执行观测云中,需要立即响应用户操作的 AI 相关处理
如:调用「告警压缩合并」的处理等
2 当使用 AI 聚合告警的监控器较多时扩容
beat 定时任务的触发器 ← 同左 1 不得扩容,保证全局单副本
mysql 数据库 (无此服务) - 不需要扩容,有更高需求可选择自建或云服务
redis 缓存 / 函数执行任务队列 (无此服务) - 不需要扩容,有更高需求可选择自建或云服务
服务 / 队列 职责
独立部署
职责
观测云附属
扩容建议
server Web 服务,提供如下功能:
1. Web 界面
2. API 接口
3. 维护订阅器
← 同左 一般不需要扩容
server-inner (无此服务) Web 服务,专供观测云在集群内部调用 API 一般不需要扩容
worker-0
队列 #0
系统工作单元,不直接参与用户代码的处理 ← 同左 一般不需要扩容
worker-1
队列 #1
执行来自同步 API(旧版:授权链接)的函数任务 ← 同左 需要提高同步 API(旧版:授权链接)并发量时可扩容
worker-2
队列 #2
执行来自定时任务(旧版:自动触发配置)的函数任务 ← 同左 需要提高定时任务(旧版:自动触发配置)并发量时可扩容
worker-3
队列 #3
执行来自异步 API(旧版:批处理)的函数任务 ← 同左 需要提高异步 API(旧版:批处理)并发量时可扩容
worker-4
队列 #4
(预留) (预留) 不需要扩容
worker-5
队列 #5
调试代码执行
即在 Web 界面直接运行函数
← 同左 需要支持更多用户同时开发脚本时扩容
worker-6
队列 #6
执行来自连接器订阅消息处理的函数任务 ← 同左 需要提高连接器订阅消息处理并发量时可扩容
worker-7
队列 #7
(预留) 执行观测云系统业务、消息发送的函数任务
如:通过观测云后台管理员登录、更新各类缓存、释放消息聚合池、Message Desk 消息发送
当消息发送量大时扩容
worker-8
队列 #8
(预留) 执行观测云阈值检测等普通监控器相关的函数任务 当普通监控器数量较多时扩容
worker-9
队列 #9
(预留) 执行观测云高级检测、智能监控的函数任务 当普通高级检测、智能监控器数量较多时扩容
beat 定时任务的触发器 ← 同左 不得扩容,保证全局单副本
mysql 数据库 (无此服务) 不需要扩容,有更高需求可选择自建或云服务
redis 缓存 / 函数执行任务队列 (无此服务) 不需要扩容,有更高需求可选择自建或云服务
服务 职责 扩容建议
server Web 服务,提供如下功能:
1. Web 界面
2. API 接口
3. 维护订阅器
一般不需要扩容
worker-0
队列 #0
系统工作单元,不直接参与用户代码的处理 一般不需要扩容
worker-1-6
队列 #1、#2、#3、#4、#5、#6
默认情况下,负责函数同步调用处理,如:
1. 授权链接处理
2. 订阅消息处理
需要提高授权链接、订阅消息处理并发数时可扩容
worker-7
队列 #7
默认情况下,负责调试代码处理(即在 Web 界面直接运行函数) 需要支持更多用户同时开发脚本时扩容
worker-8-9
队列 #8、#9
默认情况下,负责函数异步调用处理,如:
1. 自动触发处理
2. 批处理
需要提高自动触发、批处理处理并发数时扩容
beat 定时任务的触发器 不得扩容,保证全局单副本
mysql 数据库 不需要扩容,有更高需求可选择自建或云服务
redis 缓存 / 函数执行任务队列 不需要扩容,有更高需求可选择自建或云服务

示例:当需要增强定时任务的处理能力时...

由上文可知,定时任务位于「队列 #8」,「队列 #8」对应「服务 worker-8」,因此扩容「服务 worker-8」即可

估算扩容量

以常见的 worker-8 为例:

worker-8 在观测云附属版中主要负责执行监控器任务。假设一次检测任务需要 T 毫秒,那么 1 分钟可以执行 60 × 1,000 ÷ T 次检测。默认情况下,worker-8 每个 Pod 开启 5 进程。

即单个 worker-8 Pod 的检测能力为 5 × (60 × 1,000 ÷ T) 个监控器。

公式

Text Only
1
2
A = 5 × (60 × 1,000 ÷ T)
  = 300,000 ÷ T

A:检测能力

T:检测任务执行耗时(毫秒)

根据监控器每次执行时长不同,可以列出下面的表格:

单次检测耗时 单个 Pod 检测能力 相较于基准
300 1,000 167%
500 600 基准
800 375 63%
1,000 300 50%
2,000 150 25%
3,000 100 17%

反过来,假设一致监控器总数为 M,那么,所需的 Pod 数量则可以根据 M ÷ (5 × (60 × 1,000 ÷ T)) 得出。

公式

Text Only
1
2
P = M ÷ (300,000 ÷ T)
  = M × T ÷ 300,000

P:所需 Pod 数量

M: 监控器数量

T:检测任务执行耗时(毫秒)

根据监控器数量、每次执行时长不同,可以列出下面的表格:

监控器数量 单次检测耗时 所需 Pod 数量 相较于基准
1,000 300 1 50%
1,000 500 2 基准
1,000 800 3 150%
1,000 1,000 4 200%
1,000 2,000 7 350%
1,000 3,000 10 500%
监控器数量 单次检测耗时 所需 Pod 数量 相较于基准
5,000 300 5 56%
5,000 500 9 基准
5,000 800 14 156%
5,000 1,000 17 189%
5,000 2,000 34 378%
5,000 3,000 50 556%
监控器数量 单次检测耗时 所需 Pod 数量 相较于基准
10,000 300 10 59%
10,000 500 17 基准
10,000 800 27 159%
10,000 1,000 34 200%
10,000 2,000 67 394%
10,000 3,000 100 588%

操作方法

单机部署的 DataFlux Func 可以通过修改配置({安装目录}/docker-stack.yaml),增加对应服务的 deploy.replicas 实现扩容。

请参考官方文档

有关 deploy.replicas 选项的完整信息,请参考 Docker 官方文档:Docker Documentation / Compose file deploy reference / replicas

以提升 worker-8 处理能力为例,具体修改部分如下:

示例仅为节选

示例仅展示关键修改部分,实际操作时请注意配置完整

docker-stack.yaml 关键修改部分
1
2
3
4
5
services:
  worker-8:
    deploy:
      # 同时启动【2个】处理队列 8 的工作单元
      replicas: 2

3. 限制资源

限制资源需要根据实际业务合理调整

请根据实际业务合理调整资源限制

一味限制资源,可能会导致任务执行变长,或内存不足无法完成代码的执行

操作方法

单机部署的 DataFlux Func 可以通过修改配置({安装目录}/docker-stack.yaml),增加对应服务的 deploy.resources 实现限制资源。

请参考官方文档

有关 deploy.resources 选项的完整信息,请参考 Docker 官方文档:Docker Documentation / Compose file deploy reference / resources

默认情况下,每个 worker-N 副本最多会占满 5 个 CPU 核心(即每个工作单元中,有 5 个工作进程)。

以限制 worker-8占用资源为例,具体修改部分如下:

示例仅为节选

示例仅展示关键修改部分,实际操作时请注意配置完整

docker-stack.yaml 关键修改部分
1
2
3
4
5
6
7
services:
  worker-8:
    deploy:
      resources:
        limits:
          cpus  : '2.50' # 限制 CPU 最多使用 2.5 个核心
          memory: 4G     # 限制内存 最多使用 4 GB

4. 拆分工作单元

新版中所有工作单元已经拆分

在独立部署 Func 3.2.0 及以后版本中,默认已经拆分了所有非预留的工作单元,用户可以根据需要启用预留的队列

在观测云附属 Func 1.77.145 及以后版本中,默认已经拆分了所有工作单元,不再需要用户自行拆分

特殊情况下,可以将默认合并的工作单元(如:worker-1-6)进行拆分,实现更细粒度的任务调度,实现对负责特定队列的工作单元扩容与资源限制。

假设根据业务需求,DataFlux Func 对订阅处理的性能要求较高,且希望订阅消息处理不和同步 API(旧版:授权链接)处理不会相互干扰,那么可以从 worker-1-6 将拆分为 worker-1-5worker-6

操作方法

单机部署的 DataFlux Func 可以通过修改配置({安装目录}/docker-stack.yaml),新增、修改对应服务,并修改 command 中指定的队列序号,即可实现拆分工作单元。

指定工作单元监听的队列,通过 ./run-worker-by-queue.sh 后的参数实现,服务名称本身主要作为标注使用,建议与实际监听队列一致,避免混乱

示例仅为节选

示例仅展示关键修改部分,实际操作时请注意配置完整

docker-stack.yaml 关键修改部分
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
services:
  # 删除原先的「worker-1-6」,改为如下内容

  worker-1-5:
    # 指定工作单元处理 1 ~ 5 号工作队列
    command: ./run-worker-by-queue.sh 1 2 3 4 5

  worker-6:
    # 指定工作单元处理 6 号工作队列
    command: ./run-worker-by-queue.sh 6