Skip to content

Actor 与有状态服务

Task 适合无状态计算:函数执行完,结果进入对象存储,函数本身不保留任何状态。但有些场景需要一个长期存活的对象来维护状态,比如推理服务加载一次模型,后续请求复用;参数服务器持续更新权重;游戏环境需要持续推进。

这种场景用 Task 不太自然,Actor 就是 Ray 对这个问题的解答。

Actor 的基本用法

python
@ray.remote
class Counter:
    def __init__(self):
        self.value = 0

    def incr(self):
        self.value += 1
        return self.value

counter = Counter.remote()
refs = [counter.incr.remote() for _ in range(3)]
print(ray.get(refs))  # [1, 2, 3]

Counter.remote() 创建远程实例。counter.incr.remote() 提交 Actor 方法调用。

Actor 的执行模型

默认情况下,同一个 Actor 的方法调用按顺序执行。可以把 Actor 看成一个带状态的 Worker 加一个消息队列。

这种模型牺牲了单个 Actor 内部的并行性,换来状态一致性。

Actor 适合什么

场景为什么用 Actor
模型推理服务模型加载一次,多个请求复用
参数服务器状态持续更新
数据库/外部服务连接连接对象不可序列化,放在 Actor 内
强化学习环境环境状态需要持续推进
缓存或计数器状态由 Actor 串行维护

Actor 和 Object Store 的区别

ray.put 更适合不可变大对象:

python
weights_ref = ray.put(weights)

Actor 更适合可变状态:

python
model_server = ModelServer.remote(weights_path)
prediction_ref = model_server.predict.remote(batch)

如果每次更新都生成新对象,可以用 Object Store。如果对象要被原地维护,并且方法调用需要顺序语义,用 Actor。

Actor 的常见问题

Actor 很方便,但也容易变成瓶颈。最常见的问题是“所有请求都打到一个 Actor”。Actor 方法默认串行执行,队列一长,延迟就上去了。

其他常见问题:

  • Actor 方法里做了长时间阻塞(比如调外部 API),后续方法全部排队等待。
  • Actor 持有大对象,重启代价高。
  • 忘记声明 GPU 资源,Actor 被调度到没有 GPU 的节点。

解决思路:

  • 用多个 Actor 做分片,分散请求。
  • 读多写少的状态拆出来用 ray.put
  • 用并发 Actor(max_concurrency)或 async Actor。
  • 显式声明资源,确保调度到正确的节点。

Supervisor 模式

工程里常用一个 Actor 管理多个子 Actor:

Supervisor 可以负责:

  • 路由请求。
  • 重启失败子 Actor。
  • 聚合状态。
  • 控制并发。

Mini Ray 的 Actor 实现

Mini Ray 用一个独立线程承载 Actor 实例:

  1. RemoteActorClass.remote() 调用 Runtime.create_actor()
  2. 运行时创建 queue.Queue() 作为 Actor mailbox。
  3. Actor 线程初始化类实例。
  4. 每个方法调用放入队列。
  5. Actor 线程逐个取出消息并执行。
  6. 方法返回值写入 ObjectStore

Mini Ray 的实现虽然简化了(用线程代替进程,用字典代替共享内存),但保留了 Actor 的核心设计:一个长期存活的执行单元,通过消息队列串行处理方法调用。

小练习

Counter 改造成 KVStore

python
@ray.remote
class KVStore:
    def __init__(self):
        self.data = {}

    def put(self, key, value):
        self.data[key] = value

    def get(self, key):
        return self.data.get(key)

再思考:如果有 100 万个 key,所有请求都打到一个 Actor 会有什么问题?你会怎么分片?

面向学习目的的 Ray Core 中文导读与 Mini Ray 机制预览。