从《红色警戒:复兴》论MongoDB设计模式的重要性

作者:猿媛牧场/男/上海 作者介绍:某四大会计师事务所高级技术专家,在分布式系统架构性能优化有丰富的实践经验。MongoDB Professionor 中国15位获得者之一。长期从事SQL-NoSQL的转型、MongoDB数据治理、高可用及弹性扩展。多年实践DevOps,通过自动化的实践完成了从人工救火到吃瓜运维的成功转型。多次实践、建设、推进海量TB级数据架构重组、建模、业务分析。

前言

在2016年5月份的某一天,我和菠萝同学怀着对昔日《红警95》的缅怀之情,相约脱胎于开源项目OpenRA,来自制Server、Web、个人系统等,重现《红警95》的昔日光芒。继而取名《红色警戒:复兴》。

在经过了将近一年的蛰伏后,作为《红色警戒:复兴》的联合创始人,终于有幸在今年4月份见证他的第一次公开亮相。

《红色警戒:复兴》官方网站

为何选用MongoDB

在构建项目之初,曾以为的天马行空、伟大蓝图在实际操作过程中遇到了非常多的阻碍。脱胎于开源项目,用.NET实现的游戏引擎,当我们还在为windows服务器不稳定而纠结的时候,MS发布了.NET CORE!这一振奋人心的事情立马让我们决定去大干一番!

(中间省略1万字……)

然后在实际开发过程中,遇到了一个比较棘手的问题。我们希望记录下战斗中所有的战斗数据以供后期采用统计分析方法对收集来的大量数据进行分析,提取有用信息并形成结论而对数据加以详细研究、概括总结。

我们先来看一个gif图

坦克海

从该gif中,我们可以看到红色玩家单位中有大量的坦克并摧毁了绿色玩家的建筑、士兵、坦克等单位,这一场战斗的数据是会直接记录到我们的MongoDB中,最后当游戏结束时作统一处理。

这里考验数据库性能的点在于,我们需要记录这一回合中,红色玩家有多少A单位、B单位……,其中包括建筑、士兵、坦克、飞机、防御单位等。在游戏过程中的所有游戏数据我们都是存mongo的,考虑到大量的计算,MySQL无法胜任。

因此最终的DB选型就是MongoDB作为游戏中的数据计算容器,MySQL作为最终的数据落盘容器。这也是许多项目采用的一种MongoDB+MySQL的解决方案。

设计模式惹的祸

在使用MongoDB记录数据的时候,通过OPS记录,发现当游戏进度推进至20分钟后(注意这个时间点,由于游戏特性,决定了往往在激战20分钟后,会出现经济大于生产的情况),兵种数量急剧增加,MongoDB CPU负载就会骤然飙升,而这仅仅是在测试环境,若投入生产,,这种情况一般我是采取零容忍的,接下来就是一段改造的过程。

首先一起了解下起初的设计结构:

{
    "_id" : ObjectId("58ecdc0b5003d2a379b871df"),
    "profileId" : 1,
    "gameId" : 1,
    "units" : {
        "soldiers" : {
            "Rifle" : 23,
            "Grenadier" : 46
        },
        "vehicles" : {
            "V2" : 15,
            "Light" : 7
        }
    },
    "money" : {
        "earned" : 12345,
        "spent" : 54321
    }
}

以上Json是游戏中记录的部分的战斗数据结构。需求很简单,需要记录下实时的玩家数据,比如士兵中有一种兵种类型Rifle,当前数量为23个;V2远程坦克有15辆等等。

为什么会造成数据库的负载过高呢?

目前发现一个现象,当数据量不是特别大的时候(也就是之前所强调的20分钟这个零界值),服务器的cpu load并没有表现出异常,而一旦过了零界值,在经济远大于生产的情况下,玩家往往会持续输出战斗单位、防御单位、基本建筑等。这个阶段,我们的MongoDB往往是在做高频率的update操作,且是对同一条数据中的不同数值进行操作。

分析

  • 排除NUMA启动。 由于官方有明确表示,因此我也关闭了NUMA,具体NUMA对MongoDB的影响可参照 MongoDB Manual 关于NUMA的解释 这里引用一段:

Running MongoDB on a system with Non-Uniform Access Memory (NUMA) can cause a number of operational problems, including slow performance for periods of time and high system process usage.

  • 排除CPU分配不均。

鉴于MongoDB Manual中有提到对于云服务或者虚机的使用注意事项,因为我们也像服务商确认过了,不存在如下引用 MongoDB on Virtual Environments

When using MongoDB with KVM, ensure that the CPU reservation does not exceed more than 2 virtual CPUs per physical core.

  • 排查slow log

无论计算机发展的如何遵循摩尔定律,冯诺依曼体系结构是不会变的。也就是说我们的cpu是顺序执行的。

因此在排除了前面2种情况后,我们需要确认的是是否存在慢查询了。

也就是在slow log中,我们发现大量的10s以上的update操作。这无疑使我们更接近了真相。因为真相只有一个。

为什么在零界值前cpu load并没有表现出过载的情况?

对于update涉及到的查询条件都已经加上了索引,但并未有明显改善。

但是慢查询是摆在那里的,不离不弃。我们尝试着对profileId进行频繁update,但CPU显然没有任何波动。

至此,我们初步断定,症结点在深层嵌套文档导致的数据多层寻址引发的。

Embedded data models allow applications to store related pieces of information in the same database record. As a result, applications may need to issue fewer queries and updates to complete common operations.

显然我们错误的理解了MANUAL中对于embedded doc 的用法。

通过抓取currentOp,进一步确认,问题就在update的内嵌文档上。

纵观这条战斗数据,细心的你一定发现了,我们的数据嵌套非常深,而对于这条数据中最需要计算的部分是藏在最里面的,3层嵌套的计算对于mongodb来说是非常吃力的,需要耗费巨大的cpu去做这件事情。

经过对业务需求的再整理,达成一个共识,可以暂时抛弃对于兵种的分类,只记录实际存在的数据。

基于以上思路,我们得出了如下的model:

{
    "_id" : ObjectId("58ecdeed5003d2a379b871e0"),
    "profileId" : 1,
    "gameId" : 1,
    "Rifle" : 23,
    "Grenadier" : 46,
    "V2" : 15,
    "Light" : 7,
    "earned" : 12345,
    "spent" : 54321
}

通过改造data model,除去兵种的分类,只对已有的单位进行update、新增的兵种进行初始化即可。

从3层嵌套中解放出来,放在一级目录下,再次测试,cpu毫无压力。

至此,一次关于MongoDB的Schema Design/Data Model改造到此告一段落。

最后附上原子弹的gif,这个动图其实也是对我们mongodb的一次考验,需要瞬时减去相对应数量的单位。

原子弹

最后欢迎大家来一起体验我们的《红色警戒:复兴》!

也欢迎志同道合的小伙伴通过 官方网站-加入我们 来加入我们的团队,为复兴红警努力!

《红色警戒:复兴》

如果觉得这篇文章还不错的话,何不关注一下呢?说不定会有意外惊喜哦~

如果你也是程序员,如果你还是单身,欢迎将你的资料在我后台留言,我相信程序员间的恋爱一定是无障碍的

原文发布于微信公众号 - 猿媛牧场(xpchuiit)

原文发表时间:2018-05-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏13blog.site

Spring+SpringMVC+MyBatis+easyUI整合基础篇(十二)阶段总结

一 不知不觉,已经到了基础篇的收尾阶段了,看着前面的十几篇文章,真的有点不敢相信,自己竟然真的坚持了下来,虽然过程中也有过懒散和焦虑,不过结果还是自己所希望的,...

2485
来自专栏镁客网

朋友们再也不用担心你们的丑照没地方存了!

1534
来自专栏FreeBuf

追踪、定位、监听一个也不能少:最强悍的监控间谍软件FlexiSPY源码泄露

4月22日,黑客FlexiDie公布了大量来自监控软件厂商FlexiSPY的文件,泄露的文件包括源码和一些内部文档。 这家监控公司其实是一家总部位于泰国(...

26410
来自专栏信安之路

【读者投稿】几年安全学习经验杂谈

我属于11年左右才开始入行的小菜鸟,听着前辈们经常讲着在10年之前,注入分分钟拿站,到10年开始慢慢出现waf,作为一个新人,waf当年的确是个不错的ideas...

920
来自专栏大葡萄元元

如何快速让自己的文章被百度收录

网站编辑网站内容的设计师和建设者,通过网络对信息进行收集、分类、编辑、审核,然后通过网络向世界范围的网民进行发布,并且通过网络从网民那里接收反馈信息,产生互动。...

762
来自专栏大数据文摘

【干货】21个数据可视化利器

24911
来自专栏贾老师の博客

【笔记】抽象泄漏

843
来自专栏北京马哥教育

误删了公司数据库,但我还是活下来了

1575
来自专栏程序员互动联盟

为什么C++是最难学的编程语言?

很多已经做了几年的C++程序员已经很自信觉得这门编程语言算是熟悉阶段了,但是当重新对这门语言来个彻底大扫除的时候发现,又有新的语法出现,最糟糕的是之前掌握的很多...

723
来自专栏腾讯移动品质中心TMQ的专栏

【腾讯TMQ】敏捷测试-快速俘虏产品 & 开发

日常见面的相处的产品跟开发,怎么了解他们偷窥他们每天做什么,像少女一样的读懂他们的内心呢?今天,手把手教你读懂读心术,快读提升自己的能力。

4470

扫码关注云+社区