从《红色警戒:复兴》论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 条评论
登录 后参与评论

相关文章

来自专栏分布式关系数据库探索

分布式关系数据库探索 - NewSQL 演化过程

回味过去,展望未来,开始分布式数据库探索之旅,首先了解历史,本文大致梳理一下数据库发展过程,从1970年到2018年,数据库的发展过程,仅供参考,交流和学习,感...

56310
来自专栏程序人生

停下来,歇口气,造轮子

上周四至今,我大概有 50-70% 的时间在造一个轮子,一个叫 merlin 的工具。 事情的起源是这样的 —— 我们内部的一个重要服务,要升级到 elixir...

365160
来自专栏IT技术精选文摘

《王者荣耀》2亿用户量的背后:产品定位、技术架构、网络方案等

66370
来自专栏牛客网

成都-阿里Java研发工程师面经

11号去成都参加阿里面试,网上预约的3点,两点半就到了,刚签完到马上就喊去面试。经历了一面二面和HR面。 一面 1.介绍一下你的项目,说一下哪个项目印象最深 ...

44280
来自专栏SDNLAB

网络功能虚拟化系列:NFV的开源软件包

本文系SDNLAB社区译者计划发布文章,SDNLAB将与国外优质媒体和个人进行长期的内容合作,带来更多的优质技术文章,本文是<<网络功能虚拟化:新兴的虚拟化网...

37680
来自专栏葡萄城控件技术团队

超越Web,Javascript在物联网的应用

引子 Patrick Catanzariti 是一名Web开发工程师,最近他在 sitepoint 发表了《JavaScript Beyond the Web ...

40260
来自专栏Java学习网

互联网高手教你如何搜集你想要的信息

  写在前面   几个月前,团队邀我做次内部的分享,主题是如何有效搜索信息。这是因为平时工作中,我经常会分享一些专业学习文档,而这些文档的出现往往很及时,回应一...

38580
来自专栏北京马哥教育

SDN有哪些开源项目?

SDN 之所以能够发展的如此之快,其中开源社区的贡献不容忽视。随着SDN 各类社区的不断发展状大,开源项目也在不断增多,从控制器到交换机再到网络虚拟化,开源...

41380
来自专栏企鹅号快讯

老鸟程序员才知道的40个小技巧

▲ 40条真言,希望对进阶中的程序朋友有所帮助。 1、重构是程序员的主力技能。 2、工作日志能提升脑容量。 3、先用profiler调查,才有脸谈优化。 4、注...

19380
来自专栏数据的力量

职场干货|高效工作的信息搜集及整理术

12620

扫码关注云+社区

领取腾讯云代金券