# damocles-worker 的配置解析

damocles-worker 是数据封装的执行主体,我们来了解一下它的配置文件结构和配置方式。

damocles-worker 的配置文件采用了 toml 格式,需要注意的是,这种格式中,以 # 开头的行将被视为注释,不会生效。

以 mock 实例为例,一份基础的配置大概会是这样:

[worker]
# name = "worker-#1"
# rpc_server.host = "192.168.1.100"
# rpc_server.port = 17891

[metrics]
#enable = false
#http_listen = "0.0.0.0:9000"

[sector_manager]
rpc_client.addr = "/ip4/127.0.0.1/tcp/1789"
# rpc_client.headers = { User-Agent = "jsonrpc-core-client" }
# piece_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiMS0xMjUiLCJwZXJtIjoic2lnbiIsImV4dCI6IiJ9.JenwgK0JZcxFDin3cyhBUN41VXNvYw-_0UUT2ZOohM0"

[sealing]
# allowed_miners = [10123, 10124, 10125]
# allowed_sizes = ["32GiB", "64GiB"]
enable_deals = true
# disable_cc = true
# max_deals = 3
# min_deal_space = "8GiB"
max_retries = 3
# seal_interval = "30s"
# recover_interval = "60s"
# rpc_polling_interval = "180s"
# ignore_proof_check = false

[[sealing_thread]]
location = "./mock-tmp/store1"
# plan = "snapup"
# sealing.allowed_miners = [10123, 10124, 10125]
# sealing.allowed_sizes = ["32GiB", "64GiB"]
# sealing.enable_deals = true
# sealing.disable_cc = true
# sealing.max_deals = 3
# sealing.min_deal_space = "8GiB"
# sealing.max_retries = 3
# sealing.seal_interval = "30s"
# sealing.recover_interval = "60s"
# sealing.rpc_polling_interval = "180s"
# sealing.ignore_proof_check = false

[[sealing_thread]]
location = "./mock-tmp/store2"

[[sealing_thread]]
location = "./mock-tmp/store3"

[[attached]]
# name = "persist-store1"
location = "./mock-tmp/remote"

[processors.limitation.concurrent]
# add_pieces = 5
# pc1 = 3
# pc2 = 2
# c2 = 1

[processors.limitation.staggered]
# pc1 = "5min"
# pc2 = "4min"

[processors.ext_locks]
# gpu1 = 1

[processors.static_tree_d]
# 2KiB = "./tmp/2k/sc-02-data-tree-d.dat"

# fields for the add_pieces processor
# [[processors.add_pieces]]

# fields for tree_d processor
[[processors.tree_d]]
# auto_restart = true

# fields for pc1 processors
[[processors.pc1]]
# bin = "./dist/bin/damocles-worker-plugin-pc1"
# args = ["--args-1", "1", --"args-2", "2"]
numa_preferred = 0
cgroup.cpuset = "4-5"
envs = { RUST_LOG = "info" }
# auto_restart = true
# inherit_envs = true

[[processors.pc1]]
numa_preferred = 0
cgroup.cpuset = "6-7"
# auto_restart = true
# inherit_envs = true

[[processors.pc1]]
numa_preferred = 1
cgroup.cpuset = "12-13"
# auto_restart = true
# inherit_envs = true

# fields for pc2 processors
[[processors.pc2]]
# cgroup.cpuset = "24-27"
# auto_restart = true
# inherit_envs = true

[[processors.pc2]]
cgroup.cpuset = "28-31"
# auto_restart = true
# inherit_envs = true

# fields for c2 processor
[[processors.c2]]
cgroup.cpuset = "32-47"
# auto_restart = true
# inherit_envs = true

下面我们将逐一分析其中的可配置项。

# [worker]

worker 配置项用于配置本实例的一些基础信息。

# 基础配置范例

[worker]
# 实例名,选填项,字符串类型
# 默认以连接 `damocles-manager` 所使用的网卡 IP 地址作为实例名
# name = "worker-#1"

# rpc 服务监听地址,选填项,字符串类型
# 默认为 "0.0.0.0",即监听本机所有地址
# rpc_server.host = "192.168.1.100"

# rpc 服务监听端口,选填项,数字类型
# 默认为 17890
# rpc_server.port = 17891

# 本地 piece 文件目录, 选填项, 字符串数组类型
# 如果设置了此项, worker 会从设置的目录中加载 piece 文件
# 否则将会从 damocles-manager 加载远程 piece 文件
# 如果 "/path/to/{your_local_pieces_dir01, your_local_pieces_dir02, ...}/piece_file_name" 文件不存在, worker 也会从 damocles-manager 加载
# local_pieces_dirs = ["/path/to/your_local_pieces_dir01", "/path/to/your_local_pieces_dir02"]

绝大多数情况下,本配置项内的各个字段无需手工配置。

仅在一些特殊情况,诸如:

  • 希望按照自己的编排习惯命名每个 damocles-worker 实例
  • 不希望监听所有网卡 IP,仅允许本地的 rpc 请求
  • 一台机器上部署了多个 damocles-worker,为避免端口冲突,需要进行区分
  • damocles-worker 可以直接访问 piece_store 目录,可配置 local_pieces_dir 从本地加载 piece 文件

等场景,需要按需手动配置这里的选项。

# [metrics]

metrics 提供了监控指标 (prometheus) 相关的选项。

# 基础配置范例

[metrics]
# 是否启用 prometheus exporter, 选填项,布尔类型
# 默认值为 false
# 当启用时,会监听 "http_listen" 所设置的 IP 和端口,提供 prometheus exporter
#enable = false

# prometheus exporter 监听的地址,选填项,地址类型
# 默认值为 "0.0.0.0:9000"
#http_listen = "0.0.0.0:9000"

# [sector_manager]

sector_manager 用于配置 damocles-manager 相关的信息,以使得 damocles-worker 可以正确的连接到对应的服务。

# 基础配置范例

[sector_manager]
# 构造 rpc 客户端时使用的连接地址,必填项,字符串类型
# 可以接受 `multiaddr` 格式,也可以接受诸如 `http://127.0.0.1:1789`,`ws://127.0.0.1:1789` 这样的 url 格式
# 通常情况下,使用 `multiaddr` 格式以和其他组件保持一致
rpc_client.addr = "/ip4/127.0.0.1/tcp/1789"

# 构造 rpc 客户端时使用的 http 头信息,选填项,字典类型
# 默认为 null
# rpc_client.headers = { User-Agent = "jsonrpc-core-client" }

# 请求订单 piece 数据时携带的校验 token, 选填项,字符串类型
# 默认为 null
# 当本实例允许封装带有订单数据的扇区时,通常需要设置此项
# 此项的值通常即为所使用的 venus 系列服务的 sophon-auth组件产生的 token 值
# piece_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiMS0xMjUiLCJwZXJtIjoic2lnbiIsImV4dCI6IiJ9.JenwgK0JZcxFDin3cyhBUN41VXNvYw-_0UUT2ZOohM0"

# [sealing]

sealing 用于配置封装过程中的通用参数选项。

# 基础配置范例

[sealing]
# 允许的`SP`,选填项,数字数组格式
# 默认为 null,允许来自任何 `SP` 的任务
# 配置后,仅可执行来自数组中罗列的 `SP` 的封装任务
# allowed_miners = [10123, 10124, 10125]

# 允许的扇区大小,选填项,字符串数组格式
# 默认为 null, 允许任意大小的扇区任务
# 配置后,仅可执行符合数组中罗列的扇区大小的任务
# allowed_sizes = ["32GiB", "64GiB"]

# 是否允许向扇区内添加订单,选填项,布尔类型
# 默认为 false
# 当设置为 true 时,通常需要同时设置 `sector_manager` 中的 `piece_token` 项
# enable_deals = true

# 是否禁用 cc 扇区,选填项,布尔类型
# 默认为 false
# enable_deals 为 true 时,开启此选项,将持续等待,直到获得分配的订单,而不是启动 cc 扇区
# disable_cc = true

# 允许向扇区内添加的最大订单数量,选填项,数字类型
# 默认为 null
# max_deals = 3

# 一个扇区中填充的订单的最小体积,选填项,字节字符串格式
# 默认为 null
# min_deal_space = "8GiB"

# 封装过程中遇到 temp 类型的错误时,重试的次数,选填项,数字格式
# 默认为 5
# max_retries = 3

# 封装过程中遇到 temp 类型的错误时,重试的间隔,选填项,时间字符串格式
# 默认为 "30s", 即30秒
# recover_interval = "30s"

# 空闲的 `sealing_thread` 申请封装任务的间隔, 选填项,时间字符串格式
# 默认为 "30s", 即30秒
# seal_interval = "30s"

# rpc 状态轮询请求的间隔,选填项,时间字符串格式
# 默认为 "180s", 即180秒
# 封装过程中,部分环节使用了轮询方式来获取非实时的信息,如消息上链等。
# 这个值有助于避免过于频繁的请求占用网络资源
# rpc_polling_interval = "180s"

# 是否跳过 proof 的本地校验环节,选填项,布尔格式
# 默认为 false
# 通常只在诸如测试之类的情况下设置此项
# ignore_proof_check = false

# 无法从 `damocles_manager` 获取任务时,重试的次数,选填项,数字类型
# 默认为 3
# request_task_max_retries = 3

sealing 中的配置项通常有根据经验预设的默认项,这使得我们在绝大多数情况下无需自行配置。

# 特殊配置范例

# 1. 测试网络,仅为特定 SP 提供服务

allowed_miners = [2234, 2236, 2238]

# 2. 大规模集群,降低网络占用

# 在可恢复的异常中,有相当一部分是网络抖动带来的,增大自动恢复的间隔时间降低请求频率
recover_interval = "90s"

# 正常过程中的轮询请求也增大间隔时间降低请求频率
rpc_polling_interval = "300s"

# 3. 增大扇区异常自愈的可能性

# 增大自动恢复的尝试次数
max_retries = 10

# 增大自动恢复的间隔时间
recover_interval = "60s"

# [[sealing_thread]]

sealing_thread 用于为每个扇区工作线程进行配置。一份配置文件中可以存在多个 sealing_thread 配置组。

sealing_thread 会继承 [sealing] 中的配置。可以使用 sealing.* 覆盖掉 [sealing] 的配置。

# 基础配置范例

[[sealing_thread]]
# 扇区数据目录路径,必填项,字符串类型
# 建议使用绝对路径,数据目录和工作线程是一对一绑定的
location = "/mnt/nvme1/store"

# 任务类型,选填项,字符串类型
# 默认值为 null
# 可选项: sealer | snapup | rebuild | unseal | wdpost, 当不填写时,默认等效为 sealer
# plan = "snapup"

# 封装过程的定制参数,仅对当前工作线程生效
# sealing.allowed_miners = [10123, 10124, 10125]
# sealing.allowed_sizes = ["32GiB", "64GiB"]
# sealing.enable_deals = true
# sealing.disable_cc = true
# sealing.max_retries = 3
# sealing.seal_interval = "30s"
# sealing.recover_interval = "60s"
# sealing.rpc_polling_interval = "180s"
# sealing.ignore_proof_check = false
# sealing.request_task_max_retries = 3

[[sealing_thread]]
location = "/mnt/nvme2/store"


[[sealing_thread]]
location = "/mnt/nvme3/store"

sealing_thread 的数量和对应的数据路径需要根据规划情况编排。

为了方便组合搭配,每个 sealing_thread 可以配置独立的 sealing 子项,它满足:

  • 可配置项的命名、类型、效果与通用的 sealing 项保持一致

  • 仅对当前工作线程生效

  • 未配置时使用通用的 sealing 项内的值

# 特殊配置范例

# 1. 两个工作线程,分别为不同的 SP 服务

[[sealing_thread]]
location = "/mnt/nvme2/store"
sealing.allowed_miners = [1357]


[[sealing_thread]]
location = "/mnt/nvme3/store"
sealing.allowed_miners = [2468]

# 2. 两个工作线程,分别为不同的扇区大小服务

[[sealing_thread]]
location = "/mnt/nvme2/store"
sealing.allowed_sizes = ["32GiB"]


[[sealing_thread]]
location = "/mnt/nvme3/store"
sealing.allowed_sizes = ["64GiB"]

# sealing_thread 配置热更新

在 damocles v0.5.0 之前版本,我们只能通过修改 sealing_thread 配置后并重启 damocles-worker 完成配置更新。 在有些场景下很不方便,例如:扇区重建时我们希望能够在不重启 damocles-worker 的情况下修改指定的 sealing_threadplan 配置项。

v0.5.0 之后支持 sealing_thread 配置热更新。在指定的 sealing_thread 中的 location 目录下创建名为 config.toml 的热更新配置文件,该配置文件的内容与 [[sealing_thread]] 内容完全一致,此配置文件中的配置项会覆盖 damocles-worker 中对应的 [[sealing_thread]] 的配置项,并且修改此配置文件不需要重启 damocles-worker 即可生效。

damocles-worker 中的 sealing_thread 会在新的扇区任务开始之前检查 location 目录下的 config.toml 文件,如果 config.toml 文件的内容发生了变化或者此文件删除了都会重新加载或移除此文件的配置。

注意:

  • 热更新配置文件 config.toml 无法覆盖 sealing_thread 中的 location 配置项。
  • damocles-worker 主配置文件不支持热更新。

# 基础配置范例

# /path/to/the_sealing_thread_location/config.toml

# 任务类型,选填项,字符串类型
# 默认值为 null
# 可选项: sealer | snapup | rebuild | unseal | wdpost, 当不填写时,默认等效为 sealer
# plan = "rebuild"

# 封装过程的定制参数,仅对当前工作线程生效
# sealing.allowed_miners = [10123, 10124, 10125]
# sealing.allowed_sizes = ["32GiB", "64GiB"]
# sealing.enable_deals = true
# sealing.disable_cc = true
# sealing.max_retries = 3
# sealing.seal_interval = "30s"
# sealing.recover_interval = "60s"
# sealing.rpc_polling_interval = "180s"
# sealing.ignore_proof_check = false
# sealing.request_task_max_retries = 3

# [[attached]]

attached 用于配置已完成的扇区持久化数据保存的位置,允许同时配置多个。

# 基础配置范例

[[attached]]
# 名称, 选填项,字符串类型
# 默认为路径对应的绝对路径
# name = "remote-store1"

# 路径,必填项,字符串类型
# 建议直接填写绝对路径
location = "/mnt/remote/10.0.0.14/store"

# 只读,选填项,布尔类型
# 默认值为 false
# readonly = true

由于需要在 damocles-workerdamocles-manager 之间协调存储位置信息,而在很多情况下,同一个持久化存储目录在damocles-worker 机器和 damocles-manager 机器上的挂载路径不完全一致,因此我们决定使用 name 作为协调的基础信息。

如果持久化存储目录在所有机器上的挂载路径都统一的话,配置时也可以选择在 damocles-workerdamocles-manager 两侧都不配置 name。这种情况下,两者都会使用绝对路径作为 name,也能匹配。

# [processors]

processors 用于配置封装执行器,和封装计算过程中的一些信息。

这个配置项实际上分为三个子项,我们逐一分析。

# [processors.limitation.concurrent]

processors.limitation.concurrent 用于配置指定封装阶段的并行任务数量控制。这是为了降低指定阶段的资源相互争抢的情况。

需要注意的是,当配置了外部执行器时,外部执行器的数量和允许的并发总量也会影响并行任务数量。

# 基础配置范例

[processors.limitation.concurrent]
# add_pieces 阶段的并发数限制,选填项,数字类型
# add_pieces = 5

# tree_d 阶段的并发数限制,选填项,数字类型
# tree_d = 1

# pc1 阶段的并发数限制,选填项,数字类型
# pc1 = 3

# pc2 阶段的并发数限制,选填项,数字类型
# pc2 = 1

# c2 阶段的并发数限制,选填项,数字类型
# c2 = 1

举例来说,如果设置了 pc2 = 2,那么同一时间最多只会有两个扇区可以执行 pc2 阶段的任务。

# [processors.limitation.staggered]

processors.limitation.staggered 用于配置指定封装阶段并行任务错开启动的时间间隔。配置此项后当指定阶段有多个任务同时启动时,damocles-worker 会依次根据配置的时间间隔启动任务,以避免任务同时启动造成磁盘 IO 等资源紧张的问题。

# 基础配置范例

[processors.limitation.staggered]
# 多个 pc1 任务依次启动的时间间隔,选填项,字符串类型 (e.g. "1s", "2min")
# pc1 = "5min"
# pc2 = "4min"

举例来说,如果设置了 pc1 = "5min",当两个 pc1 任务同时启动时,会先执行第一个任务 5 分钟后执行第二个任务。

# [processors.ext_locks]

processors.ext_locks 用于配置一些自定义的锁限制,它是和 [[processors.{stage_name}]] 中的 locks 配置项联动使用的。 这个配置项允许使用者自定一些限制条件,并令不同的外部处理器受其约束。

# 基础配置范例

[processors.ext_locks]
# some_name = some_number

# 特殊配置范例

processors.ext_locks 自身是不能独立生效的。

# 一块 GPU,pc2 和 c2 公用
[processors.ext_locks]
gpu = 1

[[processors.pc2]]
locks = ["gpu"]

[[processors.c2]]
locks = ["gpu"]

这样,pc2 c2 会各启动一个外部处理器,两者将会产生竞争关系,也就意味着两者将不会同时发生。

# 两块 GPU,pc2 和 c2 公用
[processors.ext_locks]
gpu1 = 1
gpu2 = 1

[[processors.pc2]]
locks = ["gpu1"]

[[processors.pc2]]
locks = ["gpu2"]

[[processors.c2]]
locks = ["gpu1"]

[[processors.c2]]
locks = ["gpu2"]

这样,pc2 c2 会各启动两个外部处理器,将会产生两两竞争的关系,从而允许限制一块 GPU 上只能执行其中一个阶段的任务。

# [processors.static_tree_d]

processors.static_tree_d 是为了提升 cc 扇区 的效率而引入的配置项。

当为相应扇区大小配置了静态文件路径时,将会直接使用此文件作为 cc 扇区 的 tree_d 文件,而不会尝试再次生成。

# 基础配置范例

[processors.static_tree_d]
2KiB = "/var/tmp/2k/sc-02-data-tree-d.dat"
32GiB = "/var/tmp/32g/sc-02-data-tree-d.dat"
64GiB = "/var/tmp/64g/sc-02-data-tree-d.dat"

# [[processors.{stage_name}]]

这是用于配置外部执行器的配置组。

目前 {stage_name} 可选

  • add_pieces 用于 Add pieces 阶段
  • tree_d 用于 Tree D 的生成阶段
  • pc1 用于 PreCommit1 阶段
  • pc2 用于 PreCommit2 阶段
  • synth_proof 用于生成 Synthetic proof 阶段
  • c2:用于 Commit2 阶段
  • transfer:用于自定义本地数据和持久化数据存储之间的传输方式
  • unseal: 用于 Unseal 阶段

每一个这样的配置组意味着将启动一个对应阶段的外部执行器。如果没有为上述的某个 {stage_name} 配置组配置任何内容,且配置中不存在对应的 [[processors.{stage_name}]] 这一行配置, 则 damocles-worker 不会为此 {stage_name} 启动子进程,damocles-worker 会使用内建的执行器代码在 sealing_thread 中直接执行对应的 {stage_name} 任务。这样 {stage_name} 任务的并发数量取决于对应的 sealing_thread 数量 和 [processors.limitation.concurrent] 中配置的 {stage_name} 并发数量。不配置外部执行器省去了序列化任务参数和任务输出等额外步骤,但是失去了更强大的并发控制,cgroup 控制和自定义算法等能力。可以根据使用场景自行取舍。

[[processors.{stage_name}]] 可选的配置项包含:

[[processors.pc1]]
# 自定义外部执行器可执行文件路径,选填项,字符串类型
# 默认会使用主进程对应的可执行文件路径,执行 damocles-worker 内建的执行器
# bin = "./dist/bin/damocles-worker-plugin-pc1"

# 自定义外部执行器的参数,选填项,字符串数组类型
# 默认值为 null,将使用 `damocles-worker` 自己的执行器默认参数
# args = ["--args-1", "1", --"args-2", "2"]

# 外部执行器子进程准备就绪的时间,选填项,时间类型
# 默认为 5s
# stable_wait = "5s"

# numa 亲和性分区 id,选填项,数字类型
# 默认值为 null,不会设置亲和性
# 需要根据宿主机的 numa 分区进行填写
# numa_preferred = 0

# cpu 核绑定和限制选项,选填项,字符串类型
# 默认值为 null,不设置绑定
# 值的格式遵循标准 cgroup.cpuset 格式
# cgroup.cpuset = "4-5"

# 外部执行器的附加环境变量,选填项,字典类型
# 默认值为 null
# envs = { RUST_LOG = "info" }

# 本执行器允许的并发任务数量上限
# 默认值为 null,无限制,但任务具体是否并发执行,视使用的外部执行器实现而定
# 主要使用在 pc1 这样可以多个并行的环节,可以有效节约共享内存、线程池等资源
# concurrent = 4

# 自定义的外部限制锁名称,选填项,字符串数组类型
# 默认值为 null
# locks = ["gpu1"]

# 当子进程退出时,是否自动重启,选填项,布尔类型
# 默认值为 true
# auto_restart = true

# 是否继承 worker 守护进程的环境变量,选填项,布尔类型
# 默认值为 true
inherit_envs = true

# 基础配置范例

[processors.limitation.concurrent]
add_pieces = 8
pc1 = 4
pc2 = 2
c2 = 1

[[processors.pc1]]
numa_preferred = 0
cgroup.cpuset = "0-7"
concurrent = 2
envs = { FIL_PROOFS_USE_MULTICORE_SDR = "1" }
auto_restart = true

[[processors.pc1]]
numa_preferred = 1
cgroup.cpuset = "12-19"
concurrent = 2
envs = { FIL_PROOFS_USE_MULTICORE_SDR = "1" }
auto_restart = true

[[processors.pc2]]
cgroup.cpuset = "8-11,24-27"
envs = { FIL_PROOFS_USE_GPU_COLUMN_BUILDER = "1", FIL_PROOFS_USE_GPU_TREE_BUILDER = "1", CUDA_VISIBLE_DEVICES = "0" }
auto_restart = true

[[processors.pc2]]
cgroup.cpuset = "20-23,36-39"
envs = { FIL_PROOFS_USE_GPU_COLUMN_BUILDER = "1", FIL_PROOFS_USE_GPU_TREE_BUILDER = "1", CUDA_VISIBLE_DEVICES = "1" }
auto_restart = true

[[processors.c2]]
cgroup.cpuset = "28-35"
envs = { CUDA_VISIBLE_DEVICES = "2,3" }
auto_restart = true


[[processors.tree_d]]
cgroup.cpuset = "40-45"
auto_restart = true

以上是基于一台 48C + 4GPU 的设备的 processors.{stage_name} 配置范例,在这套配置下,将启动:

  • 2 个 pc1 外部执行器,采用 MULTICORE_SDR 模式,各分配 8 核,允许 2 个并发任务,且内存分配优先使用本 numa 分区
  • 2 个 pc2 外部执行器,各分配 8 核,各使用一块 GPU
  • 1 个 c2 外部执行器,分配 8 核,使用一块 GPU
  • 1 个 tree_d 外部执行器,分配 6 核

# 特殊配置范例

# 1. 使用 patch 了闭源的、经过算法优化的 c2 外部执行器
[[processors.c2]]
bin = "/usr/local/bin/damocles-worker-c2-optimized"
cgroup.cpuset = "40-47"
envs = { CUDA_VISIBLE_DEVICES = "2,3" }
# 2. 使用外包模式的 c2 外部执行器
[[processors.c2]]
bin = "/usr/local/bin/damocles-worker-c2-outsource"
args = ["--url", "/ip4/apis.filecoin.io/tcp/10086/https", "--timeout", "10s"]
envs = { LICENCE_PATH = "/var/tmp/c2.licence.dev" }
# 3. GPU 不足的情况下使用 CPU 模式弥补 pc2 计算能力
[[processors.pc2]]
cgroup.cpuset = "8-11,24-27"
envs = { FIL_PROOFS_USE_GPU_COLUMN_BUILDER = "1", FIL_PROOFS_USE_GPU_TREE_BUILDER = "1", CUDA_VISIBLE_DEVICES = "0" }

[[processors.pc2]]
cgroup.cpuset = "20-23,36-45"
# 4. 最优配比下,pc1 总量为奇数,无法平分
[processors.limitation.concurrent]
pc1 = 29
pc2 = 2
c2 = 1

[[processors.pc1]]
numa_preferred = 0
cgroup.cpuset = "0-41"
concurrent = 14
envs = { FIL_PROOFS_USE_MULTICORE_SDR = "1" }

[[processors.pc1]]
numa_preferred = 1
cgroup.cpuset = "48-92"
concurrent = 15
envs = { FIL_PROOFS_USE_MULTICORE_SDR = "1" }

# 5. 希望优先集中使用 numa 0 区完成 pc1
[processors.limitation.concurrent]
pc1 = 29
pc2 = 2
c2 = 1

[[processors.pc1]]
numa_preferred = 0
cgroup.cpuset = "0-47"
concurrent = 16
envs = { FIL_PROOFS_USE_MULTICORE_SDR = "1" }

[[processors.pc1]]
numa_preferred = 1
cgroup.cpuset = "48-86"
concurrent = 13
envs = { FIL_PROOFS_USE_MULTICORE_SDR = "1" }

# cgroup.cpuset 配置注意事项

  • 针对启用 multicore sdr 的 PC1 外部处理器,cgroup.cpuset 尽量以整个 L3 cache 下的 CPU cores 为单位配置。如果需要配置 L3 cache 下的部分 CPU cores 必须保证每个 L3 cache 下 CPU cores 数量一致。

    rust-fil-proofs (opens new window) 中规定,当启用 multicore sdr 时,CPU 核心数量和这些 CPU 核心对应的 CPU 共享缓存 (通常是 L3 cache) 的数量必须是整数倍数关系。如果外部执行器使用的是 rust-fil-proofs 或者基于 rust-fil-proofs 开发,则必须遵守这个规则,否则可以忽略。damocles-worker 默认的执行器是基于 rust-fil-proofs 开发的。

  • cgroup.cpuset 中的 CPU cores 尽量不要跨 NUMA 节点,跨 NUMA 节点会使得 CPU 访问内存速度变慢 (damocles-cluster v0.5.0 之后,支持加载 NUMA 亲和的 hugepage 内存文件,如果启用该功能可以跨 NUMA 节点分配 cpuset 不会产生影响)

    如果配置的 CPU cores 均在同一 NUMA 节点,可以将 processors.{stage_name}.numa_preferred 配置为对应的 NUMA 节点 id。

使用 damocles-worker-util 查看 CPU 信息

./damocles-worker-util hwinfo

Output:

CPU topology:
Machine (503.55 GiB)
├── Package (251.57 GiB) (*** *** *** 32-Core Processor)
│   ├── NUMANode (#0 251.57 GiB)
│   ├── L3 (#0 16 MiB)
│   │   └── PU #0 + PU #1 + PU #2 + PU #3
│   ├── L3 (#1 16 MiB)
│   │   └── PU #4 + PU #5 + PU #6 + PU #7
│   ├── L3 (#2 16 MiB)
│   │   └── PU #8 + PU #9 + PU #10 + PU #11
│   ├── L3 (#3 16 MiB)                       
│   │   └── PU #12 + PU #13 + PU #14 + PU #15
│   ├── L3 (#4 16 MiB)                       
│   │   └── PU #16 + PU #17 + PU #18 + PU #19
│   ├── L3 (#5 16 MiB)
│   │   └── PU #20 + PU #21 + PU #22 + PU #23
│   ├── L3 (#6 16 MiB)
│   │   └── PU #24 + PU #25 + PU #26 + PU #27
│   └── L3 (#7 16 MiB)
│       └── PU #28 + PU #29 + PU #30 + PU #31
└── Package (251.98 GiB) (*** *** *** 32-Core Processor)
    ├── NUMANode (#1 251.98 GiB)
    ├── L3 (#8 16 MiB)
    │   └── PU #32 + PU #33 + PU #34 + PU #35
    ├── L3 (#9 16 MiB)
    │   └── PU #36 + PU #37 + PU #38 + PU #39
    ├── L3 (#10 16 MiB)
    │   └── PU #40 + PU #41 + PU #42 + PU #43
    ├── L3 (#11 16 MiB)
    │   └── PU #44 + PU #45 + PU #46 + PU #47
    ├── L3 (#12 16 MiB)
    │   └── PU #48 + PU #49 + PU #50 + PU #51
    ├── L3 (#13 16 MiB)
    │   └── PU #52 + PU #53 + PU #54 + PU #55
    ├── L3 (#14 16 MiB)
    │   └── PU #56 + PU #57 + PU #58 + PU #59
    └── L3 (#15 16 MiB)
        └── PU #60 + PU #61 + PU #62 + PU #63

...

从输出的信息可以看到这台机器有两个 NUMANode, 每个 NUMANode 上有 8 个 L3 Cache,每个 L3 cache 下有 4 个 CPU 核。

  • NUMANode #0 上的 CPU cores: 0-31
  • NUMANode #1 上的 CPU cores: 31-63

以这台机器为例,如果配置 processors.pc1.cgroup.cpuset = "0-6" 是不满足 rust-fil-proofs 规则的。

  1. PU#0, PU#1, PU#2, PU#3, 这 4 个 CPU cores 属于 L3#0
  2. PU#4, PU#5, PU#6, 这 3 个 CPU cores 属于 L3#1

此时 CPU 的共享缓存数量为 2 (L3#0, L3#1), 并且配置的 CPU cores 数量不一致,不满足 rust-fil-proofs 规则,无法启动。正确的配置可以是 processors.pc1.cgroup.cpuset = "0-7"

# 一份最简可工作的配置文件范例

[sector_manager]
rpc_client.addr = "/ip4/{some_ip}/tcp/1789"

# 根据实际资源规划
[[sealing_thread]]
location = "{path to sealing store1}"

[[sealing_thread]]
location = "{path to sealing store2}"

[[sealing_thread]]
location = "{path to sealing store3}"

[[sealing_thread]]
location = "{path to sealing store4}"

[[sealing_thread]]
location = "{path to sealing store5}"

[[sealing_thread]]
location = "{path to sealing store6}"

[[sealing_thread]]
location = "{path to sealing store7}"

[[sealing_thread]]
location = "{path to sealing store8}"


[remote_store]
name = "{remote store name}"
location = "{path to remote store}"

[processors.static_tree_d]
32GiB = "{path to static tree_d for 32GiB}"
64GiB = "{path to static tree_d for 64GiB}"

# 根据实际资源规划
[processors.limitation.concurrent]
pc1 = 4
pc2 = 2
c2 = 1

[[processors.pc1]]
numa_preferred = 0
cgroup.cpuset = "0-7"
concurrent = 2
envs = { FIL_PROOFS_USE_MULTICORE_SDR = "1" }

[[processors.pc1]]
numa_preferred = 1
cgroup.cpuset = "12-19"
concurrent = 2
envs = { FIL_PROOFS_USE_MULTICORE_SDR = "1" }


[[processors.pc2]]
cgroup.cpuset = "8-11,24-27"
envs = { FIL_PROOFS_USE_GPU_COLUMN_BUILDER = "1", FIL_PROOFS_USE_GPU_TREE_BUILDER = "1", CUDA_VISIBLE_DEVICES = "0" }

[[processors.pc2]]
cgroup.cpuset = "20-23,36-39"
envs = { FIL_PROOFS_USE_GPU_COLUMN_BUILDER = "1", FIL_PROOFS_USE_GPU_TREE_BUILDER = "1", CUDA_VISIBLE_DEVICES = "1" }


[[processors.c2]]
cgroup.cpuset = "28-35"
envs = { CUDA_VISIBLE_DEVICES = "2,3" }


[[processors.tree_d]]
cgroup.cpuset = "40-45"

在按实际情况进行规划并填写相应信息后,以上就是一份:

  • 只进行 cc 扇区
  • 32GiB 和 64GiB 扇区免 tree_d
  • 一体化资源分配

的最简配置文件了。

# 参考 venus 社区用户测试案例

参考案例 1 (opens new window) 特点:PC1 精确限核,C2 采用 gpuproxy 方式完成,具有很强的可扩展性。缺点是配置复杂,需要根据实际环境调整任务数

参考案例 2 (opens new window) 特点:PC2 和 C2 共享 1 个 GPU,可能会产生一些 C2 任务将积压

参考案例 3 (opens new window) 特点:2 组 PC2 与分别与 2 组 C2 共享 GPU 资源

参考案例 4 (opens new window) 特点:适用于低配置机器使用,在 NVMe 上创建 96G 的 swap 空间,但这可能会导致某些任务做得比较慢