- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the help center为指导。
8年前关闭。
我从事开发回合制休闲 MMORPG 游戏服务器。
处理网络的低级引擎(不是我们编写的),
多线程、定时器、服务器间通信、主游戏循环等
由 C++ 编写。高级游戏逻辑由 Python 编写。
我的问题是关于我们游戏中的数据模型设计。
一开始我们只是尝试将一个播放器的所有数据加载到 RAM 和一个共享数据中
客户端登录时缓存服务器并安排计时器定期将数据刷新到
数据缓存服务器和数据缓存服务器将数据持久化到数据库中。
但是我们发现这种方法有一些问题
1) 一些数据需要即时保存或查看,例如任务进度,
升级,元素和金钱 yield 等。
2)根据游戏逻辑,有时我们需要查询一些离线玩家的
数据。
3) 部分全局游戏世界数据需要在不同游戏之间共享
可能在不同主机或不同进程上运行的实例
同一个主机。这是我们需要在游戏之间放置数据缓存服务器的主要原因
逻辑服务器和数据库。
4) 玩家需要在游戏实例之间自由切换。
以下是我们过去遇到的困难:
1)所有的数据访问操作应该是异步的,避免网络I/O
阻塞主游戏逻辑线程。我们必须将消息发送到数据库或
缓存服务器然后在回调函数中处理数据回复消息和
继续进行游戏逻辑。写一些温和的东西很快就会变得痛苦
复杂的游戏逻辑,需要多次与 db 和游戏逻辑对话
分散在许多回调函数中,难以理解和
维持。
2)临时数据缓存服务器使事情变得更加复杂,我们难以维护
数据一致性并有效地更新/加载/刷新数据。
3)游戏内数据查询效率低下繁琐,需要查询游戏逻辑
许多信息,如库存、元素信息、头像状态等。一些
还需要事务机制,例如,如果一个步骤失败了整个
操作应该是回滚。我们尝试在 RAM 中设计一个好的数据模型系统,
构建了大量复杂的索引以缓解大量信息查询,添加
交易支持等。我很快意识到我们正在构建的是一个内存
数据库系统,我们正在重新发明轮子...
最后我转向无堆栈python,我们删除了缓存服务器。所有数据
保存在数据库中。游戏逻辑服务器直接查询数据库。无堆叠
python的微tasklet和channel,我们可以在synchronized中编写游戏逻辑
道路。编写和理解要容易得多,生产力也大大提高
改进。
其实底层的DB访问也是异步的:一个客户端tasklet
向另一个专用 DB I/O 工作线程发出请求,并且 tasklet 是
一个 channel 被屏蔽了,但是整个游戏主逻辑没有被屏蔽,其他
客户端的 tasklet 将被调度并自由运行。当 DB 数据回复
被阻塞的 tasklet 将被唤醒并在“break”时继续运行
点'(继续?)。
有了上面的设计,我有一些问题:
1) 数据库访问将比以前的缓存解决方案更频繁,是否
DB可以支持高频率的查询/更新操作吗?是否有一些成熟的缓存
近期需要redis、memcached等解决方案吗?
2) 我的设计有什么严重的缺陷吗?你们能给我一些更好的吗
建议,尤其是关于游戏内数据管理模式的建议。
任何建议将不胜感激,谢谢。
最佳答案
我曾使用过一个以类似方式运行的 MMO 引擎。然而,它是用 Java 编写的,而不是 Python。
关于你的第一组要点:
1) 异步数据库访问 我们实际上走了另一条路,避免了“主游戏逻辑线程”。所有游戏逻辑任务都作为新线程产生。与 I/O 相比,线程创建和销毁的开销完全消失在本底噪声中。这也保留了将每个“任务”作为一种相当简单的方法的语义,而不是一个令人抓狂的回调链,否则会以其他方式结束(尽管仍然存在这种情况。)这也意味着所有游戏代码都必须是并发,我们越来越依赖带有时间戳的不可变数据对象。
2) 临时缓存 我们使用了很多 WeakReference 对象(我相信 Python 有类似的概念吗?),并且还利用了数据对象之间的拆分,例如“播放器”和“加载器”(实际上是数据库访问方法)例如“播放器SQLLoader;”实例保存了一个指向它们的加载器的指针,加载器被一个全局“工厂”类调用,该类将处理缓存查找与网络或 SQL 加载。数据类中的每个“Setter”方法都会调用方法 changed
,这是 myLoader.changed (this);
的继承样板
为了处理来自其他事件服务器的加载对象,我们使用了使用相同数据类的“代理”对象(再次说,“播放器”),但我们关联的加载器类是一个网络代理,它会(同步,但超过千兆本地网络)在另一台服务器上更新该对象的“主”副本;反过来,“主”副本将调用 changed
本身。
我们的 SQL UPDATE
逻辑有一个计时器。如果后端数据库收到了 UPDATE
在最后 ($n) 秒内(我们通常将其保持在 5 秒左右),它会将对象添加到“脏列表”中。后台计时器任务会定期唤醒并尝试将仍在“脏列表”上的任何对象异步刷新到数据库后端。
由于全局工厂维护对所有核心对象的弱引用,并且会在任何实时服务器上查找给定游戏对象的单个实例化副本,因此我们永远不会尝试实例化由单个 DB 记录支持的一个游戏对象的第二个副本,因此游戏的 RAM 状态可能一次与其 SQL 图像不同长达 5 或 10 秒这一事实无关紧要。
我们的整个 SQL 系统在 RAM(是的,很多 RAM)中运行,作为另一台勇敢地尝试写入磁盘的服务器的镜像。 (由于“老化”,那台糟糕的机器平均每 3-4 个月烧毁一次 RAID 驱动器。RAID 很好。)
值得注意的是,当从缓存中删除对象时,必须将对象刷新到数据库中,例如由于超出缓存 RAM 限额。
3) 内存数据库 ......我没有遇到过这种确切的情况。我们确实有“类事务”逻辑,但这一切都发生在 Java 的 getter/setter 级别上。
而且,关于你的后一点:
1) 是的,PostgreSQL 和 MySQL 尤其能很好地处理这个问题,尤其是当您使用数据库的 RAMdisk 镜像来尝试最大程度地减少实际硬盘磨损时。然而,根据我的经验,MMO 确实倾向于对数据库进行比严格必要的更多的锤击。我们的“5 秒规则”* 是专门为避免必须“正确”解决问题而制定的。我们的每个二传手都会调用 changed
.在我们的使用模式中,我们发现一个对象通常要么更改了 1 个字段,然后一段时间没有事件,要么发生“ Storm ”更新,其中许多字段连续更改。构建适当的事务左右(例如,通知对象它即将接受许多写入,并且应该等待片刻再将其保存到数据库中)将涉及更多的计划、逻辑和系统的主要重写;所以,相反,我们绕过了这种情况。
2)好吧,上面是我的设计:-)
事实上,我目前正在开发的 MMO 引擎更多地依赖于内存中的 SQL 数据库,并且(我希望)会做得更好一些。但是,该系统是使用实体-组件-系统模型构建的,而不是我上面描述的 OOP 模型。
如果您已经基于 OOP 模型,那么转向 ECS 是一个非常好的范式转变,如果您可以让 OOP 为您的目的工作,那么最好坚持使用您的团队已经知道的内容。
*- “5 秒规则”是美国的一种口语“民间信仰”,即食物掉到地上后,如果在 5 秒内捡起来仍然可以吃。
关于python - 需要关于MMORPG数据模型设计、数据库访问和stackless python的建议,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8660622/
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 4 年前。 Improv
PowerShell Web Access 允许您通过 Web 浏览器运行 PowerShell cmdlet。它显示了一个基于 Web 的控制台窗口。 有没有办法运行 cmdlet 而无需在控制台窗
我尝试在无需用户登录的情况下访问 Sharepoint 文件。 我可以通过以下任一方式获取访问 token 方法一: var client = new RestClient("https://logi
我目前正在尝试通过 Chrome 扩展程序访问 Google 服务。我的理解是,对于 JS 应用程序,Google 首选的身份验证机制是 OAuth。我的应用目前已成功通过 OAuth 向服务进行身份
假设我有纯抽象类 IHandler 和派生自它的类: class IHandler { public: virtual int process_input(char input) = 0; };
我有一个带有 ThymeLeaf 和 Dojo 的 Spring 应用程序,这给我带来了问题。当我从我的 HTML 文件中引用 CSS 文件时,它们在 Firebug 中显示为中止。但是,当我通过在地
这个问题已经有答案了: JavaScript property access: dot notation vs. brackets? (17 个回答) 已关闭 6 年前。 为什么这不起作用? func
我想将所有流量重定向到 https,只有 robot.txt 应该可以通过 http 访问。 是否可以为 robot.txt 文件创建异常(exception)? 我的 .htaccess 文件: R
我遇到了 LinkedIn OAuth2: "Unable to verify access token" 中描述的相同问题;但是,那里描述的解决方案并不能解决我的问题。 我能够成功请求访问 toke
问题 我有一个暴露给 *:8080 的 Docker 服务容器. 我无法通过 localhost:8080 访问容器. Chrome /curl无限期挂断。 但是如果我使用任何其他本地IP,我就可以访
我正在使用 Google 的 Oauth 2.0 来获取用户的 access_token,但我不知道如何将它与 imaplib 一起使用来访问收件箱。 最佳答案 下面是带有 oauth 2.0 的 I
我正在做 docker 入门指南:https://docs.docker.com/get-started/part3/#recap-and-cheat-sheet-optional docker-co
我正在尝试使用静态 IP 在 AKS 上创建一个 Web 应用程序,自然找到了一个带有 Nginx ingress controller in Azure's documentation 的解决方案。
这是我在名为 foo.js 的文件中的代码。 console.log('module.exports:', module.exports) console.log('module.id:', modu
我试图理解访问键。我读过https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-se
我正在使用 MGTwitterEngine"将 twitter 集成到我的应用程序中。它在 iOS 4.2 上运行良好。当我尝试从任何 iOS 5 设备访问 twitter 时,我遇到了身份验证 to
我试图理解访问键。我读过https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-se
我正在使用以下 API 列出我的 Facebook 好友。 https://graph.facebook.com/me/friends?access_token= ??? 我想知道访问 token 过
401 Unauthorized - Show headers - { "error": { "errors": [ { "domain": "global", "reas
我已经将我的 django 应用程序部署到 heroku 并使用 Amazon s3 存储桶存储静态文件,我发现从 s3 存储桶到 heroku 获取数据没有问题。但是,当我测试查看内容存储位置时,除
我是一名优秀的程序员,十分优秀!