# Akka.Cluster 模块
# 1. 模块定位
Air.Cloud.Modules.Akka 提供基于 Akka.NET Akka.Cluster 的 Actor 集群运行时封装。它负责托管 ActorSystem 生命周期、构建 Cluster HOCON、扫描并注册业务 Actor、提供 Tell / Ask 消息入口,并为多业务域共用同一个 Cluster 提供 Domain、Role、命名前缀和授权钩子。
该模块不是服务注册中心,也不替代 Kafka、Nexus、HTTP 或 gRPC。推荐用法是:服务内部并发、同类服务多实例协作、需要 Actor 模型隔离状态或任务执行时使用 Akka;跨微服务通信仍优先走已有消息队列或 RPC 标准。
# 2. 包名
<PackageReference Include="Air.Cloud.Modules.Akka" Version="10.0.0-alpha-260601" />
源码项目:
src/modules/Air.Cloud.Modules.Akka/Air.Cloud.Modules.Akka.csproj
# 3. 注册方式
模块包含 Startup : AppStartup,在 Air.Cloud 启动扫描中会自动绑定 AkkaSettings 并注册 Cluster 服务。
手动注册时可以使用:
services.AddAkkaCluster(options =>
{
options.SystemName = "order-service";
options.Host = "0.0.0.0";
options.Port = 4053;
options.Roles.Add("order");
options.SeedNodes.Add("akka.tcp://order-service@order-0:4053");
});
注册后可注入:
public class OrderAppService
{
private readonly IAkkaClusterService _akka;
public OrderAppService(IAkkaClusterService akka)
{
_akka = akka;
}
public Task<string> PingAsync()
{
return _akka.Ask<string>("order-worker", new PingMessage());
}
}
# 4. 配置示例
{
"AkkaSettings": {
"Enabled": true,
"SystemName": "air-cloud-cluster",
"Host": "0.0.0.0",
"Port": 4053,
"Roles": [ "order", "inventory" ],
"SeedNodes": [
"akka.tcp://air-cloud-cluster@node-0:4053",
"akka.tcp://air-cloud-cluster@node-1:4053"
],
"AskTimeoutSeconds": 10,
"ShutdownTimeoutSeconds": 30,
"Domains": {
"Order": {
"Role": "order",
"ActorNamePrefix": "order",
"AllowCrossDomainMessages": true
},
"Inventory": {
"Role": "inventory",
"ActorNamePrefix": "inventory",
"AllowCrossDomainMessages": false
}
}
}
}
| 配置项 | 说明 | 默认值 |
|---|---|---|
Enabled | 是否启用 Akka.Cluster 运行时 | true |
SystemName | ActorSystem 名称,同一 Cluster 内必须一致 | air-cloud |
Host | 当前节点监听地址 | 0.0.0.0 |
Port | 当前节点监听端口,0 表示自动分配 | 0 |
Roles | 当前节点角色集合 | 空集合 |
SeedNodes | 入群种子节点地址,不是主节点 | 空集合 |
AskTimeoutSeconds | Ask 默认超时秒数 | 10 |
ShutdownTimeoutSeconds | ActorSystem 关闭等待秒数 | 30 |
Domains | 多业务域隔离配置 | 空字典 |
Hocon | 追加 HOCON 配置 | 空 |
当 SeedNodes 为空时,模块会自动 Join(SelfAddress),形成单节点 Cluster,便于本地开发和测试。
# 5. Actor 注册
业务 Actor 可以使用 AkkaActorAttribute 自动注册:
[AkkaActor("worker", Domain = "Order", Role = "order")]
public class OrderWorkerActor : ReceiveActor
{
public OrderWorkerActor()
{
Receive<CreateOrderCommand>(command =>
{
Sender.Tell(new CreateOrderResult(command.OrderId));
});
}
}
如果 Domains:Order:ActorNamePrefix = "order",最终 Actor 名称为:
order-worker
发送消息:
akka.Tell("order-worker", new CreateOrderCommand("order-001"));
var result = await akka.Ask<CreateOrderResult>(
"order-worker",
new CreateOrderCommand("order-001"));
# 5.1 Actor 构造函数依赖
手动 ActorOf<TActor> 和 AkkaActorAttribute 自动注册都会使用当前应用 IServiceProvider 创建 Actor。业务 Actor 可以直接通过构造函数声明依赖:
public interface IOrderFormatter
{
string Format(string orderId);
}
[AkkaActor("worker", Domain = "Order", Role = "order")]
public class OrderWorkerActor : ReceiveActor
{
public OrderWorkerActor(IOrderFormatter formatter)
{
Receive<CreateOrderCommand>(command =>
{
Sender.Tell(new CreateOrderResult(formatter.Format(command.OrderId)));
});
}
}
依赖仍按普通 DI 方式注册:
services.AddSingleton<IOrderFormatter, OrderFormatter>();
如果需要手动创建带运行期参数的 Actor,可以使用 ActorOf 的有参重载。显式参数会和 DI 依赖一起匹配构造函数:
public class OrderWorkerActor : ReceiveActor
{
public OrderWorkerActor(IOrderFormatter formatter, string shardName)
{
Receive<CreateOrderCommand>(command =>
{
Sender.Tell($"{shardName}:{formatter.Format(command.OrderId)}");
});
}
}
akka.ActorOf<OrderWorkerActor>("order-worker-a", "shard-a");
同名 Actor 仍保持注册表单例语义:如果 order-worker-a 已经存在,再次调用 ActorOf 会返回已有 IActorRef,不会重新创建 Actor,也不会重新应用新的构造参数。
# 6. 多业务域共用 Cluster
框架层允许同一个 Cluster 承载多个业务域,业务方决定是否采用该部署模式。框架层提供以下兜底:
| 保障 | 行为 |
|---|---|
| Domain | Actor 描述保留业务域元数据 |
| Role | Actor 只在匹配角色的节点注册 |
| ActorNamePrefix | 避免不同业务域同名 Actor 冲突 |
| AuthorizationHandler | 可拦截跨业务域消息 |
| Registry | 同名 Actor 后注册会覆盖,要求业务域使用前缀隔离 |
示例:
{
"AkkaSettings": {
"SystemName": "air-cloud-cluster",
"Roles": [ "order", "inventory" ],
"Domains": {
"Order": {
"ActorNamePrefix": "order",
"AllowCrossDomainMessages": true
},
"Inventory": {
"ActorNamePrefix": "inventory",
"AllowCrossDomainMessages": false
}
}
}
}
Order 和 Inventory 可以都声明 [AkkaActor("worker")],最终注册为 order-worker 与 inventory-worker。
# 7. 授权扩展
默认 DefaultAkkaMessageAuthorizationHandler 允许所有消息。业务可以注册自定义实现:
public class DomainMessageAuthorizationHandler : IAkkaMessageAuthorizationHandler
{
public bool CanSend(AkkaActorDescriptor descriptor, object message)
{
if (message is not IBusinessDomainMessage domainMessage)
{
return true;
}
return descriptor.Domain == domainMessage.TargetDomain;
}
}
任一授权处理器返回 false 时,Tell / Ask 会抛出 UnauthorizedAccessException。
# 8. 故障与排查
| 现象 | 可能原因 | 处理建议 |
|---|---|---|
ActorSystem has not started | 在宿主启动前访问 ActorSystem 或直接调用发送入口 | 确认通过 IHostedService 启动,或先调用 StartAsync |
| Actor 未注册 | Role 不匹配、缺少 AkkaActorAttribute、程序集未加载 | 检查 Roles 与 Attribute 上的 Role 是否一致 |
| Actor 构造失败 | 构造函数依赖未注册,或显式参数类型与构造函数不匹配 | 检查 DI 注册,并确认 ActorOf 传入参数顺序和类型能匹配目标构造函数 |
| 发送被拒绝 | 自定义授权处理器返回 false | 检查 Domain 策略和消息来源 |
| 同名 Actor 被覆盖 | 多业务域未配置 ActorNamePrefix | 为每个 Domain 配置唯一前缀 |
| 多节点无法入群 | SystemName 不一致、地址不可达、SeedNodes 配错 | 保证同一 Cluster 使用相同 SystemName 并开放端口 |
# 9. 验证命令
dotnet test test/Air.Cloud.UnitTest/Air.Cloud.UnitTest.csproj --filter "FullyQualifiedName~Modules.Akka"
dotnet test test/Air.Cloud.IntegrationTest/Air.Cloud.IntegrationTest.csproj --filter "FullyQualifiedName~Modules.Akka"
当前工作区中,Akka 集成测试覆盖真实 ActorSystem 启停、单节点 Cluster、Actor 消息、Role/Domain 隔离和跨业务域授权策略。