ET框架Actor Location:分布式MMO中实体迁移后消息如何可靠送达指南
2026/9/17 4:00:23 网站建设 项目流程

ET框架Actor Location:分布式MMO中实体迁移后消息如何可靠送达指南

【免费下载链接】ETUnity3D Client And C# Server Framework项目地址: https://gitcode.com/GitHub_Trending/et/ET

做分线MMO时,玩家从1线切到2线,旧连接标识立刻失效,再走一步消息就丢了。用ET框架(Unity客户端加C#服务端的开源双端框架)搭分布式游戏服务端,这类问题是最高频的一类,而它的Actor Location位置服务就是专门为此设计的解法。

消息为什么在换线后会丢

先分清两个标识符。ET里每个实体都有一个Entity.Id,终身不变,相当于身份证号;而对象创建时分配的InstanceId只在所在进程内有效,相当于居住证号。换城市(进程),证号就换发。

标识符作用范围实体迁移进程后
Entity.Id全局唯一永远不变
InstanceId仅当前进程有效变成新号

所以问题可以拆成三层:消息要投递到具体某个实体;发送方往往不知道这个实体现在在哪个进程;实体还可能随时迁移,地址可能在消息到达前就过期了。三层里任何一层没处理好,消息就会丢。

位置服务到底做了什么

ET的Actor Location机制把这三层分开解决。

第一层:把实体自己变成邮箱。给实体挂上MailBoxComponent组件,它就成为一个Actor,消息排队逐条处理。像公司前台的快递架,包裹按序放,人按序取,保证同一对象的逻辑绝不并发。

第二层:位置服务负责回答"他在哪"。框架部署一个Location进程,所有挂信箱的实体创建时都会把Entity.Id和InstanceId的映射注册上去。发送方不知道地址时先查一次位置服务;发送成功后缓存结果,之后直接走缓存,失败才重新查。

第三层:锁加重试负责处理"地址过期"。实体迁移前,先删除本进程的记录,再在位置服务上对自己的key加锁,此时其他进程对同一key的请求会进入队列等待。迁移完成后解锁、更新新地址,排队请求继续执行。如果消息真的发到了旧地址,框架会自动重新查地址并重试,最多5次,仍失败才抛异常交给业务处理。

// 发送方只拿Entity.Id发,查地址、缓存、重试全在框架内部 var sender = Game.Scene.GetComponent<ActorLocationSenderComponent>() .Get(unitId); sender.Send(actorLocationMessage);

看懂这三层之后,你可以跟着走一遍,从跑起demo到验证位置服务本身。

四步把ET的Actor Location跑起来

  1. 克隆仓库:git clone https://gitcode.com/GitHub_Trending/et/ET,注意必须clone新工程,不要在旧工程里覆盖。
  2. 初始化:项目根目录执行pwsh ./Scripts/Initialize-Project.ps1。环境要求.NET 8和Unity 2022.3.62,Book/1.1运行指南.md列了完整依赖清单。
  3. 跑demo:用Unity打开工程后,双击 Packages/cn.etetet.statesync/Scenes/Init.unity,点Play,客户端登录流程会完整走一遍。
  4. 验证位置服务:项目根目录执行"Test --Name=Actorlocation_.*" | dotnet ./Bin/ET.App.dll --SceneName=Test,12条位置服务用例全部通过,说明注册、查询、锁、重试这条链路是通的。

跑通之后,这套机制的承载能力可以看看仓库里已有的数据。

这套机制扛得住多少量

README里的Benchmark记录:100万次PingPong消息往返平均耗时4秒左右,也就是平均每秒收发20万条消息,远超主线程需求。商业项目《千古风流》线上跑的是64核128G单物理机1.5万在线,策划为生态限制到6000人时CPU占用约30%,Release版还能翻倍到3万在线。另外,Packages/cn.etetet.actorlocation/包内自带12条测试用例,覆盖锁超时自动解锁、迁移重试、多类型存储等场景,位置服务每次改动都有回归保障。

能力有了,日常开发里还有几个高频坑值得先知道。

高频坑点速查

  1. 现象:A调B、B调C、C调A,三个进程集体无响应。原因:邮箱是串行队列,handler阻塞整条队列形成环。解决:handler里另开协程处理逻辑,不等待返回。
  2. 现象:发消息报Actor不存在。原因:实体正在迁移进程。解决:框架自动重试5次,业务侧捕获异常后重新发起请求。
  3. 现象:await之后继续用旧对象引用,偶发崩溃。原因:await期间Entity可能已被销毁。解决:用EntityRef在await后重新获取(仓库开发规则明确要求)。
  4. 现象:锁泄漏或解锁失败。原因:没用token闭环。解决:LockWithToken取token,解锁时带同一个lockToken调用UnLock。
  5. 现象:初始化脚本直接报错。原因:中文目录或没装.NET 8。解决:工程路径保持英文,按运行指南补齐依赖。

排完这些坑,剩下的就是照着规范写业务代码了。

回到开头那个换线场景:你不再需要关心玩家在哪个进程,对着Entity.Id发就行。想深挖原理,读 Book/5.4Actor模型.md 和 Book/5.5Actor Location-ZH.md 两篇,里面用中国邮政的比喻讲得很透;写代码时,以cn.etetet.actorlocation包里的12条测试用例为准绳。

【免费下载链接】ETUnity3D Client And C# Server Framework项目地址: https://gitcode.com/GitHub_Trending/et/ET

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询