ActorGo GitHub
返回官网

ACTORGO / GETTING STARTED

新手指南

先用可直接落地的示例新增 Actor、开放 Actor HTTP、接入 AGP;再按状态模型、消息运行时、协议入口、异步协作、集群与组件生命周期理解整个框架。

Go 1.26.1+4 个上手步骤9 类框架设计开发者视角
01

QUICK START

五分钟跑通第一个请求

快速上手部分只做一件事:创建一个可被调用的顶层 Actor,然后依次从进程内、HTTP 和 AGP 入口访问它。三种入口最终复用同一张 Method Table。

01创建工程

初始化 Go Module,安装 ActorGo,并准备最小节点配置。

02新增 Actor

嵌入 Base,声明 AliasID,在 OnInit 注册稳定 Method ID。

03选择入口

本地调用直接 Invoke;后台接口挂 HTTP;实时客户端使用 AGP。

terminalINSTALL
mkdir actorgo-quickstart && cd actorgo-quickstart
go mod init example.com/actorgo-quickstart
go get github.com/actorgo-game/actorgo@latest

建议的学习顺序:先完成 Actor + HTTP 的 JSON 请求,确认 Method ID、Handler 和响应链路正确,再接入 TCP / WebSocket 与 Protobuf 客户端。

开发环境与依赖边界

GO

Go 1.26.1+

版本以仓库 go.mod 为准。先用 go version 确认工具链,再初始化 Module 并安装 ActorGo。

PROTO

Protobuf 工具链

使用 PB 契约时准备 protoc 与 Go 插件;JSON 快速上手不依赖代码生成。

LOCAL

单机零中间件

Standalone 模式可直接运行 Actor、HTTP、TCP 与 WebSocket,不需要先启动 NATS。

CLUSTER

按需启动集群依赖

切换 Cluster 后再准备 NATS 或 RabbitMQ,并单独配置 NATS / ETCD Discovery。

02

ADD AN ACTOR

新增第一个 Actor

顶层 Actor 是外部请求的业务边界。下面的示例定义 JSON 请求与响应,注册 Method ID 1001,并随应用启动。代码结构与当前 ActorGo API 保持一致。

hello_actor.goACTOR + TYPED HANDLER
package main

import (
    cfacade "github.com/actorgo-game/actorgo/facade"
    cactor "github.com/actorgo-game/actorgo/net/actor"
)

const HelloMethodID uint32 = 1001

type HelloRequest struct {
    Name string `json:"name"`
}

type HelloResponse struct {
    Greeting string `json:"greeting"`
}

type HelloActor struct { cactor.Base }

func (*HelloActor) AliasID() string { return "hello" }

func (a *HelloActor) OnInit() {
    a.Methods().Register(HelloMethodID, a.hello)
}

func (a *HelloActor) hello(
    _ *cfacade.RequestContext,
    req *HelloRequest,
) (*HelloResponse, error) {
    return &HelloResponse{Greeting: "Hello, " + req.Name}, nil
}
profile.jsonLOCAL NODE
{
  "env": "local",
  "debug": true,
  "print_level": "debug",
  "node": {
    "3": [{
      "node_id": "0.0.3.1",
      "enabled": true,
      "address": "127.0.0.1:9080"
    }]
  }
}
main.goREGISTER + STARTUP
package main

import "github.com/actorgo-game/actorgo"

func main() {
    app := actorgo.Configure(
        "profile.json",
        "0.0.3.1",
        actorgo.Standalone,
    )
    app.AddActors(&HelloActor{})
    app.Startup()
}

AliasID 是服务边界顶层 Actor 在启动时创建,方法会写入应用级 Method Table。

Method ID 必须稳定业务方法建议集中管理,编号大于 5,并纳入协议版本控制。

03

ACTOR HTTP

开放 Actor HTTP 接口

HTTP Actor 不需要重复编写 Controller。注册组件后,所有顶层 Actor 的业务方法统一通过 POST /actor/{methodID} 暴露,Body 仍在目标 Actor 的 Mailbox 中解码。

main.goHTTP COMPONENT
import httpactor "github.com/actorgo-game/actorgo/net/httpactor"

app := actorgo.Configure("profile.json", "0.0.3.1", actorgo.Standalone)
app.AddActors(&HelloActor{})
app.Register(httpactor.NewComponent("actor-api", app.Address()))
app.Startup()
curlJSON REQUEST
curl -X POST "http://127.0.0.1:9080/actor/1001" \
  -H "Content-Type: application/json" \
  -H "X-ActorGo-Timeout-Ms: 3000" \
  -d '{"name":"developer"}'
200Request 成功

响应 Body 为业务 Response,并保持请求使用的 JSON 或 Protobuf 编码。

202Notify 已接收

通知成功进入 Mailbox,不返回业务 Body。

4xx / 5xx统一错误

参数、认证、超时和框架状态会映射为明确的 HTTP 状态码。

用于后台与服务集成:HTTP 适合管理后台、机器人、运维工具和内部服务;实时游戏长连接仍建议使用 AGP。

04

AGP CONNECTION

接入 TCP 与 WebSocket

AGP 连接器只负责连接、分帧和 Packet 传输,业务仍按 Method ID 分发到同一个 HelloActor。TCP 使用长度帧,WebSocket 的一条 Binary Message 对应一个 Packet。

main.goTCP + WEBSOCKET
import (
    cfacade "github.com/actorgo-game/actorgo/facade"
    "github.com/actorgo-game/actorgo/net/connector"
    "github.com/actorgo-game/actorgo/net/parser"
)

app.Register(parser.New("client", []cfacade.IConnector{
    connector.NewTCP(":9000"),
    connector.NewWS(":9001"),
}))
入口传输格式适用场景
TCPuint32 big-endian length + Packet PB原生客户端、稳定长连接
WebSocket1 Binary Message = 1 Packet浏览器与跨平台客户端
业务 BodyJSON / Protobuf由每次调用的 Codec 决定

客户端不提交 ActorPath客户端只发送 Method ID 与 Body,服务端保留路由控制权。

先定义协议,再写 Handler生产项目建议用 Protobuf 管理请求、响应与跨版本兼容。

05

CORE CONCEPTS

框架的四个核心对象

ActorGo 把业务状态、调用协议与基础设施分成清晰的边界。开发时先确定状态归属,再定义方法契约,最后选择入口和部署方式。

Actor

封装状态与行为,通过单一 Mailbox 串行处理消息。

Method Table

用稳定 Method ID 注册 Typed Handler,并自动定位顶层 Actor。

RequestContext

承载 Transport、Codec、Session、RequestID 与 Metadata。

Body Codec

JSON 与 Protobuf 始终同时注册,可按调用选择编码。

RequestContext用途
Transport标识 AGP、HTTP 或 Cluster 入口
Codec决定本次业务 Body 使用 JSON 或 Protobuf
Session保存 Sid、Uid、IP 和自定义 Data
RequestID用于请求关联,Method ID 由 Message 持有
Metadata跨入口透传调用元数据
06

FRAMEWORK LAYERS

框架分层与能力类别

把 ActorGo 看成一组可以独立理解、组合使用的设计类别。它不是只提供 Actor 容器,而是覆盖接入、调用、分布式、基础设施和运行保障的完整服务端骨架。

运行时

Application + Actor System

Application 统一编排组件生命周期;Actor System 管理 Actor、路由、超时和事件订阅。

状态模型

Top-level + Child Actor

顶层 Actor 作为服务边界,动态子 Actor 承载玩家、房间、战局等运行时状态。

调用模型

Method ID + Typed Handler

稳定方法 ID 连接所有入口,运行前校验请求与响应类型,运行时直接分发。

接入层

AGP + HTTP Actor

TCP、WebSocket 与 HTTP 共享业务方法表,协议差异收敛在边界层。

分布式

Cluster + Discovery

跨节点传输与服务发现解耦,可分别选择 NATS、RabbitMQ、NATS Discovery 或 ETCD。

基础设施

Component Ecosystem

数据库、缓存、HTTP、任务与诊断能力通过组件生命周期按需装配。

可靠性

Deadline + Panic Isolation

超时贯穿调用链,Handler、事件和定时器异常被限制在当前工作单元。

可观测性

Structured Log + Gops

慢 Handler 阈值、结构化日志、运行状态和 Go 进程诊断组成基础观测面。

07

ACTOR MODELING

Actor 状态与层级设计

Actor 的价值不是“每个对象一个 goroutine”,而是给可变状态指定唯一所有者。只有这个 Actor 能修改自己的状态,其他对象必须通过消息表达意图。

TOP-LEVEL顶层 Actor

在应用启动时注册,是外部请求和跨节点调用的服务边界。它的 Method ID 会写入 Application 方法表。

路径
NodeID.ActorID
生命周期
随节点启动和停止
适合
Gate、Match、World、Center
DYNAMIC子 Actor

由父 Actor 在运行时创建,只安装本地 Mailbox,不向外暴露方法表。首次路由可通过 OnFindChild 动态恢复。

路径
NodeID.ActorID.ChildID
生命周期
由父 Actor 管理
适合
Player、Room、Battle、Scene

开发者建模准则

01

围绕一致性边界拆分。需要原子更新的一组状态放在同一个 Actor;无需一致性的状态不要强行合并。

02

顶层 Actor 负责路由,子 Actor 负责实体状态。外部客户端不能传 target,服务端拥有最终路由权。

03

避免同步自调用。Actor 不能同步 Invoke 自己;父到子使用 InvokeChild / NotifyChild,避免重新排队到父 Mailbox。

04

让 Handler 足够短。串行模型消除了锁,但长时间阻塞会直接扩大同一 Actor 后续消息的排队时间。

游戏场景建模示例

不要按数据表机械拆 Actor,应从“谁拥有可变状态、哪些修改必须串行、哪些实体需要独立扩缩容”出发确定边界。

实时对战

Match · Room · Player

Match Actor 负责匹配队列,Room / Battle Actor 拥有单局状态,Player 子 Actor 保存局内玩家快照。

MMORPG

World · Scene · Entity

World Actor 维护全局服务边界,Scene Actor 按区域拆分,Entity 子 Actor 承载玩家与 NPC 的动态状态。

SLG

Player · City · Alliance

围绕玩家、城池和联盟的一致性边界拆分 Actor;跨实体操作通过消息编排并设计幂等。

大厅与社交

Lobby · Guild · Chat

大厅处理入口编排,Guild Actor 串行化公会状态,Chat Actor 按频道或房间隔离消息流。

08

MESSAGE RUNTIME

消息运行时与方法契约

AGP、HTTP、本地 Invoke 和集群消息最终都变成同一种内部 Message。运行时只在边界处做协议转换,Actor 内部始终处理 typed request。

01Resolve

Method Table 根据 Method ID 定位顶层 Actor。

02Clone

克隆 RequestContext、Session 与 Metadata,隔离可变状态。

03Queue

Message 进入目标 Actor 的单一 Mailbox。

04Decode

网络字节按本次 Codec 解码;进程内 typed value 跳过序列化。

05Invoke

Typed Handler 串行执行并生成 InvokeResult。

06Recycle

回写结果后释放 Context 并将 Message 放回对象池。

单一调度循环Mailbox、Event 与 Timer 在同一个 Actor goroutine 中被 select 和串行执行。

进程内零编解码当 payload 已是目标 Go 类型时直接调用;只有网络字节才经过 Body Codec。

超时不阻塞 Actor结果通道带缓冲;即使调用方已经超时,Actor 完成工作后也能安全回收 Message。

Typed Handler 如何注册

所有顶层入口共用同一张方法表。注册时校验签名,重复 ID 或非法 Handler 会在 Actor 初始化阶段直接暴露。

player_actor.goMETHOD · 1001
const LoginMethodID uint32 = 1001

func (a *PlayerActor) OnInit() {
    a.Methods().Register(LoginMethodID, a.Login)
}

func (a *PlayerActor) Login(
    ctx *facade.RequestContext,
    request *playerv1.LoginRequest,
) (*playerv1.LoginResponse, error) {
    return &playerv1.LoginResponse{}, nil
}
REQUESTfunc(*RequestContext, *Request) (*Response, error)
NOTIFYfunc(*RequestContext, *Request) error
09

PROTOCOL & ENTRY

协议、会话与调用入口

客户端只提交 Method ID 与 Body,不指定 Actor Target。外部请求先进入顶层 Actor,再由服务端决定是否访问动态子 Actor。

入口传输格式用途 / 返回
TCPuint32 big-endian length + Packet PB长连接客户端
WebSocket一条 Binary Message 对应一个 Packet子协议 agp.v1
HTTPPOST /actor/{methodID}Request 200 · Notify 202
ClusterProtobuf ClusterMessageInvoke / Notify
HTTP JSON 示例
POST /actor/1001   Content-Type: application/json

Request 成功返回 200;Notify 成功返回 202;错误 Body 统一为 HTTPError。

Session 是快照,不是共享对象

排队和跨节点时会复制 Sid、Uid、IP 与 Data map,避免传输层与 Actor 同时修改可变状态。

Codec 是逐调用属性

Protobuf 与 JSON 始终同时注册。Codec 为 0 时使用应用默认值;默认值只能在 Startup 前修改。

外部入口不接受 Target

客户端只提供 Method ID 与 Body。完整 ActorPath 只用于服务端内部访问动态子 Actor。

Deadline 贯穿调用链

RequestContext 包含 context.Context,取消和截止时间会跨 Mailbox 与集群边界继续生效。

AGP 必须遵守的协议约束

PACKET

控制包固定 Protobuf

Packet 与 ClusterMessage 固定使用 Protobuf;JSON / PB 只决定业务 Body 的编解码。

MESSAGE

三种业务消息

客户端交互只有 Request、Response、Notify;Request 返回结果,Notify 成功入队即结束。

METHOD

业务 ID 必须大于 5

1–5 保留给 Handshake、Heartbeat、Cancel、GoAway 与 Kick,业务 Method ID 在节点内全局唯一。

WS

WebSocket 只收 Binary

一条 Binary Message 对应一个 Packet,并声明 agp.v1 子协议;Text Message 会被拒绝。

10

EVENT, TIMER & CHILD

事件、定时器与子 Actor

方法调用解决明确的请求与通知;事件、定时器和子 Actor 则负责领域内的异步协作。三者都回到 Actor 自己的串行执行上下文,避免额外并发状态。

Event

按事件名订阅,可用 UniqueID 限定接收者。事件进入 Actor 自己的 Event 队列,并在 Actor goroutine 中串行处理。

适合领域内广播与状态联动

Timer

基于全局分层时间轮触发,再把 timerID 投递回 Actor 队列。支持循环、单次、固定时刻和自定义 Schedule。

适合回合、超时、刷新与周期任务

Child Actor

由父 Actor 管理动态生命周期;父级负责首次路由,也可在 OnFindChild 中按需恢复子 Actor。

适合玩家、房间、场景等动态实体

async 参数要谨慎:定时器支持异步触发选项,但一旦业务函数脱离 Actor goroutine,就需要由开发者自己保证并发安全。

11

LOCAL & CLUSTER

集群、发现与远程调用

本节点使用 Invoke / Notify,跨节点使用 InvokeNode / NotifyNode。只有服务端内部定向访问子 Actor 时才使用完整 ActorPath。

cluster.goINVOKE
ctx := facade.NewRequestContext(context.Background())
ctx.Codec = facade.CodecProtobuf

// 本节点顶层方法
result := app.ActorSystem().Invoke(ctx, methodID, req)

// 指定远端节点;底层可选择 NATS 或 RabbitMQ
result = app.ActorSystem().InvokeNode(
    ctx, "center-1", methodID, req,
)
NNATS

默认选择,适合节点间低延迟 RPC,部署与使用更轻量。

RRabbitMQ

需要统一 MQ 基础设施时可选,当前实现为尽力投递。

01Discovery

维护 NodeID、NodeType 与节点信息。可使用 NATS 或 ETCD,独立于消息传输选择。

02Node Selection

业务根据服务类型和路由策略选择节点,再调用 InvokeNode / NotifyNode。

03Cluster Transport

把 RequestContext、Method ID、Payload 与 Deadline 编码为 Protobuf ClusterMessage。

04Remote Dispatch

目标节点仍通过本地 Method Table 定位顶层 Actor,调用方不需要知道远端 ActorPath。

跨节点传输的实际语义

DISCOVERY

发现与传输独立

Discovery 可选择 NATS 或 ETCD;Cluster Transport 可独立选择 NATS 或 RabbitMQ。

REQUEST

请求响应可关联

Invoke 使用 Request / Reply;RabbitMQ 通过 ReplyTo 与 CorrelationId 关联响应并执行本地超时。

NOTIFY

通知单向发布

Notify 不等待业务响应。RabbitMQ 直接发布到目标 remote routing key,不设置 ReplyTo。

BACKPRESSURE

明确背压与交付语义

工作队列满时 Request 返回 RESOURCE_EXHAUSTED、Notify 丢弃;当前 RabbitMQ 实现为尽力投递。

12

APPLICATION & COMPONENT

应用与组件生命周期

Application 是节点进程的组合根。组件按注册顺序启动、按逆序停止,使数据库、连接器、Actor System 等依赖关系可以确定性释放。

01Set

注入 Application

02Init

按注册顺序初始化

03OnAfterInit

所有组件就绪后执行

04OnBeforeStop

逆序准备关闭

05OnStop

逆序释放资源

Profile 与节点

Profile 支持 include 合并、环境、日志级别、配置目录和节点设置。node_id 可写精确值、正则或列表,用一套配置描述同类型节点。

连接入口

TCP / WebSocket Connector、AGP Parser、HTTP Actor 与 Gin 都是边界适配器,业务 Actor 不感知监听器细节。

资源组件

GORM、Mongo、Redis 和 Data Config 在 Init 阶段建立资源,在逆序 OnStop 阶段释放,避免业务自行管理全局连接。

运行保障

Logger、Gops、Cron 和关闭钩子覆盖日志、诊断、计划任务与优雅停机,组件异常会被记录并尽量继续关闭流程。

13

INFRASTRUCTURE & PRODUCTION

基础设施与生产实践

Actor 模型减少了共享状态问题,但不会自动解决慢 I/O、重复消息、协议兼容和观测缺口。上线前应显式确认这些工程边界。

设置调用边界

为 Invoke 设置端到端 CallTimeout,并配置 ExecutionTimeout 记录慢 Handler。

避免阻塞 Actor

Handler 应保持短小。慢数据库、外部 HTTP 或长计算应拆分,避免占住 Actor 串行执行权。

尊重串行语义

Actor 不能同步 Invoke 自己;父 Actor 调子 Actor 使用 InvokeChild,避免消息重入导致死锁。

固定协议契约

Method ID 与 Protobuf 定义应版本化管理;切换默认 Codec 只在 Startup 前执行。

明确交付语义

RabbitMQ 当前为非持久、自动删除队列和尽力投递;关键业务需自行设计幂等与补偿。

建立观测基线

记录 RequestID、Method ID、ActorPath、耗时和错误码,结合 Gops 排查运行时问题。

隔离持久化细节

将 GORM、Mongo 与 Redis 封装在组件或仓储层,不让 Actor 业务直接依赖连接生命周期。

覆盖关键测试

重点验证 Method 表、Codec、上下文取消、子 Actor、连接协议和集群响应关联。

推荐分层让 Actor 保留领域语义
game/
├── api/          # Protobuf 契约与 Method ID
├── actor/        # 状态、Handler、事件与定时器
├── service/      # 跨 Actor 用例编排
├── repository/   # 数据访问接口与实现
├── component/    # 外部资源与生命周期适配
├── profile/      # 节点与环境配置
└── cmd/          # 各节点启动入口

按需组合基础设施

组件通过 Application 生命周期统一注入。只注册节点真正需要的能力,并通过接口或仓储层隔离业务代码与基础设施实现。

GinGORMMongoDBRedisCronGopsData Config
接入与 API

Connector · Parser · HTTP Actor · Gin

数据与状态

GORM · MongoDB · Redis · Data Config · Distributed Lock

运行与工具

Cron · Gops · Logger · Profile · Time Wheel · Snowflake

提交前执行核心验证

优先覆盖协议编解码、Method Table、连接边界、HTTP 分发和 Actor 上下文生命周期;集群项目还应补充真实双节点与压力测试。

terminalCORE TESTS
go test ./net/proto ./net/serializer ./net/method \
  ./net/parser ./net/httpactor ./net/actor ./net/connector

下一步

从一个顶层 Actor 开始

先在单机模式完成业务闭环,再根据真实规模拆分节点。
获取源码