`
fantaxy025025
  • 浏览: 1279238 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类

MongoDB的真正性能-实战百万用户一-一亿的道具

 
阅读更多

=

=

=

MongoDB的真正性能-实战百万用户一-一亿的道具 

http://www.cnblogs.com/crazylights/archive/2013/05/08/3068098.html

上一篇为求振聋发聩的效果,有些口号主义,现在开始实战,归于实用主义。

使用情景

开始之前,我们先设定这样一个情景:

1.一百万注册用户的页游或者手游,这是不温不火的一个状态,刚好是数据量不上不下的一个情况。也刚好是传统MySql数据库性能开始吃紧的时候。

2.数据库就用一台很普通的服务器,只有一台。读写分离、水平扩展、内存缓存都不谈。一百万注册用户如果贡献度和活跃度都不高,恐怕公司的日子还不是那么宽裕,能够在数据库上的投资也有限。

以此情景为例,设每个用户都拥有100个道具,用户随时会获得或失去道具。

我们就来看看这一亿的道具怎么搞。

道具一般要使用原型、实例的设计方法,这个不属于数据库的范畴。

道具类型001 是屠龙刀,屠龙刀价格1500,基础攻击150,这些,我们把它们称为道具原型,保存在原型数据文件中。

这个原型数据文件,无论是存在何种数据库或者本地文件中,对服务器来说都不是问题,也不干扰数据库设计,所以我们不去讨论他。

关系数据库设计方法

典型的关系数据库设计方法:

用户表:字段 xxx userid xxx   ,记录数量100万

xxx是其他字段,userid标示用户

用户道具表:字段 xxx userid itemtype xxx ,记录数量一亿

xxx是其他字段,userid 标示

一个亿的记录数是不是看起来有点头疼,mysql这个时候就要想各种办法了。

MongoDB设计方法

但我们用mongoDB来实现这个需求,直接就没有问题

首先第一个集合:users集合,用UserName 作为_id ,记录数100万

然后道具的组织,我们有两种选择

1.在users集合的值中建立Items对象,用Bson数组保存道具(Mongo官方称为Bson,和Json一模一样的存储方法)

方法一,没有额外的记录数

2.新建userItems集合,同样用UserName作为_id 每个UserItems集合的值中建立一个Item对象,使用一个Bson数组来保存道具

方法二,多了一个集合和100万记录数

 

我们的道具数据看起来像下面这样:

{_id:xxx,Items:[

{Itemtype:xxx,ItemPower:xxx},

...

...

...

 

]}

测试方法

测试方法如下:测试客户端随机检查一个用户的道具数量,小于100加一个道具,大于100 删除一个道具。

连续100万次,采用10个线程并发。

如果用关系数据库设计方法+mysql来实现,这是一个很压力很大的数据处理需求。

可是用文档数据库设计方法+MongoDB来实现,这个测试根本算不上有压力。

注意事项

即使我们用了一个如此胜之不武的设计方式,你依然有可能还是能把他写的很慢。

因为MongoDB在接口设计上并没有很好的引导和约束,如果你不注意,你还是能把他用的非常慢。

第一个问题:Key-Value数据库可以有好多的Key,没错,但对MongoDB来说,大错特错

MongoDB的索引代价很大,大到什么程度:

1.巨大的内存占用,100万条索引约占50M内存,如果这个设计中,你一个道具一条记录,5G内存将用于索引。

我们的屌丝情景不可能给你这样的服务器,

2.巨大的性能损失,作为一个数据库,所有的东西终将被写入硬盘,没有关系数据库那样的表结构,MongoDB的索引写入性能看起来很差,如果记录数据较小的时候,你可以观测到这样震撼的景象,加一个索引,性能变成了1/2,加两个索引,性能变成了1/3。

只有当第二个索引的查询不可避免,才值得增加额外索引。因为没索引的数据,查询性能是加几个零的慢,比加索引更惨。

我们既然选择了Key-Value数据库,应尽量避免需要多个索引的情况。

所有的索引只能存在于内存中,而读取记录时,也需要将Bson在内存中处理,内存还承担着更重要的作用:读取缓存。

本来就不充裕的内存,应该严格控制我们的记录条数,能够用Bson存储的,尽量用之。

那么我们之前在MongoDB的设计中怎么还考虑第二种设计方法呢?独立一个userItems 集合,不是又多出100万条记录了吗?

这基于另两个考虑:a.Bson的处理是要反复硬盘和内存交换的,如果每条记录更小,则IO压力更小。内存和硬盘对服务器来说都是稀缺资源,至于多大的数据拆分到另一个集合中更划算,这需要根据业务情况,服务器内存、硬盘情况来测试出一个合适大小,我们暂时使用1024这个数值,单用户的道具表肯定是会突破1024字节的,所以我们要考虑将他独立到一个集合中

b.可以不部署分片集群,将另一个集合挪到另一个服务器上去。只要服务器可以轻松承载100万用户,200万还会远么?在有钱部署分片集群以前,考虑第二组服务器更现实一些。

第二个问题:FindOne({_id:xxx})就快么?

毋庸置疑,FindOne({_id:xxx})就是最直接的用Key取Value。

也的确,用Key取Value 就是我们能用的唯一访问Value的方式,其他就不叫Key-Value数据库了。

但是,由于我们要控制Key的数量,单个Value就会比较大。

不要被FindOne({_id:xxx}).Items[3].ItemType这优雅的代码欺骗,这是非常慢的,他几乎谋杀你所有的流量。

无论后面是什么 FindOne({_id:xxx})总是返回给你完整的Value,我们的100条道具,少说也有6~8K.

这样的查询流量已经很大了,如果你采用MongoDB方案一设计,你的单个Value是包含一个用户的所有数据的,他会更大。

如果查询客户端和数据库服务器不在同一个机房,流量将成为一个很大的瓶颈。

我们应该使用的查询函数是FindOne({_id:xxx},filter),filter里面就是设置返回的过滤条件,这会在发送给你以前就过滤掉

比如FindOne({_id:xxx},{Items:{"$slice":[3,1]}}),这和上面那条优雅的代码是完成同样功能,但是他消耗很少的流量

第三个问题:精细的使用Update

这和问题二相对的,不要暴力的FindOne,也尽量不要暴力的Update一整个节点。虽然MangoDB的性能挺暴力的,IO性能极限约等于MongoDB性能,暴力的Update就会在占用流量的同时迎接IO的性能极限。

除了创建节点时的Insert或者Save之外,所有的Update都应该使用修改器精细修改.

比如Update({_id:xxx},{$set:{"Items.3.Item.Health":38}});//修改第三把武器的健康值

至于一次修改和批量修改,MongoDB默认100ms flush一次(2.x),只要两次修改比较贴近,被一起保存的可能性很高。

但是合并了肯定比不合并强,合并的修改肯定是一起保存,这个也要依赖于是用的开发方式,如果使用php做数据客户端,缓存起来多次操作合并了一起提交,实现起来就比较复杂。

 

注意以上三点,一百万注册用户并不算很多,4G内存,200G硬盘空间的MongoDB服务器即可轻松应对。性能瓶颈是硬盘IO,可以很容易的使用Raid和固态硬盘提升几倍的吞吐量。不使用大量的Js计算,CPU不会成为问题,不要让索引膨胀,内存不会成为问题。你根本用不着志强的一堆核心和海量的内存,更多的内存可以让缓存的效果更好一些,可是比读写分离还是差远了。如果是高并发时查询性能不足,就要采用读写分离的部署方式。当IO再次成为瓶颈时,就只能采用集群部署MongoDB启用分片功能,或者自行进行分集合与key散列的工作。

 

=

=

=

分享到:
评论

相关推荐

    mongodb-driver-sync-4.2.3-API文档-中英对照版.zip

    赠送jar包:mongodb-driver-sync-4.2.3.jar; 赠送原API文档:mongodb-driver-sync-4.2.3-javadoc.jar; 赠送源代码:mongodb-driver-sync-4.2.3-sources.jar; 赠送Maven依赖信息文件:mongodb-driver-sync-4.2.3....

    mongodb-driver-core-4.2.3-API文档-中文版.zip

    赠送jar包:mongodb-driver-core-4.2.3.jar; 赠送原API文档:mongodb-driver-core-4.2.3-javadoc.jar; 赠送源代码:mongodb-driver-core-4.2.3-sources.jar; 赠送Maven依赖信息文件:mongodb-driver-core-4.2.3....

    mongodb-driver-sync-4.2.3-API文档-中文版.zip

    赠送jar包:mongodb-driver-sync-4.2.3.jar; 赠送原API文档:mongodb-driver-sync-4.2.3-javadoc.jar; 赠送源代码:mongodb-driver-sync-4.2.3-sources.jar; 赠送Maven依赖信息文件:mongodb-driver-sync-4.2.3....

    mongodb-driver-core-3.5.0.jar

    在本篇文章中,我们将深入探讨`mongodb-driver-core-3.5.0.jar`这一核心驱动包及其相关组件。 `mongodb-driver-core-3.5.0.jar`是MongoDB Java驱动程序的核心部分,包含了与MongoDB服务器通信的基本功能。这个版本...

    MongoDB(mongodb-org-server_5.0.4_amd64.deb)

    MongoDB Community Server(mongodb-org-server_5.0.4_amd64.deb)适用于适用于Debian10 MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。 MongoDB是...

    mongodb-async-driver-2.0.1 jar包

    MongoDB异步驱动程序(mongodb-async-driver)是为Java开发者设计的一个库,它允许应用程序以非阻塞的方式与MongoDB服务器进行通信,提高了处理大量并发请求的能力。 在"mongodb-async-driver-2.0.1.jar"这个特定...

    MongoDB(mongodb-org-server-5.0.4-1.el7.x86_64.rpm)

    MongoDB Community Server(mongodb-org-server-5.0.4-1.el7.x86_64.rpm)适用于RedHat / CentOS 7.0 MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。...

    mongodb-linux-x86_64-rhel70-4.2.5.tgz

    `mongodb-linux-x86_64-rhel70-4.2.5.tgz`是一个专为RHEL 7.0系统设计的MongoDB二进制包,版本为4.2.5。 首先,安装MongoDB需要确保系统满足最低要求,例如兼容的Linux内核版本、足够的内存以及适当的硬件配置。...

    mongodb-windows-x86-64-7.0.5-signed.msi

    mongodb-windows-x86_64-7.0.5-signed.msi 数据库构建工具

    MongoDB Community(mongodb-org-server-5.0.8-1.el7.x86_64.rpm)

    MongoDB Community Server(mongodb-org-server-5.0.8-1.el7.x86_64.rpm)适用于RedHat / CentOS 7.0 MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。...

    mongodb-linux-x86_64-4.0.8.tgz

    首先,"mongodb-linux-x86_64-4.0.8.tgz"是一个专为Linux 64位系统设计的MongoDB发行版,版本号为4.0.8。MongoDB的每个版本都有其特定的改进和新特性,4.0.8作为稳定版本,提供了许多重要的功能和性能优化,例如引入...

    mongodb-driver-core-4.3.3.jar

    mongodb-driver-core 4.3.3版本

    MongoDB(mongodb-src-r5.0.4.tar.gz)

    MongoDB Community Server(mongodb-src-r5.0.4.tar.gz)源代码 MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。 MongoDB是一个介于关系数据库和非...

    mongodb-linux-x86_64-rhel62-4.0.0.tgz

    这个“mongodb-linux-x86_64-rhel62-4.0.0.tgz”文件是专门为基于Red Hat Enterprise Linux 6.2 (RHEL62)的64位Linux系统设计的MongoDB 4.0.0版本的安装包。MongoDB 4.0是一个重要的版本,因为它引入了许多新特性和...

    mongodb-windows-x86_64-4.4.0-signed.msi

    MongoDB window 安装包,mongodb-windows-x86_64-4.4.0-signed.msi,免除下载速度慢的烦恼!

    MongoDB Community Server(mongodb-windows-x86_64-5.0.8-signed.msi

    MongoDB Community Server(mongodb-windows-x86_64-5.0.8-signed.msi)适用于RedHat / CentOS 7.0 MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。 ...

    mongodb-linux-x86_64-ubuntu1404-3.6.4

    这个压缩包“mongodb-linux-x86_64-ubuntu1404-3.6.4”是专为Ubuntu 14.04设计的MongoDB 3.6.4版本,包含了在Linux环境下运行MongoDB所需的所有组件。 MongoDB 3.6是MongoDB的一个重要版本,引入了许多新特性和改进...

    mongodb-database-tools-windows-x86_64-100.3.1.zip

    在提供的压缩包"mongodb-database-tools-windows-x86_64-100.3.1.zip"中,包含了以下关键文件: 1. mongodump.exe:这是用于创建MongoDB数据库的逻辑备份的工具。它将数据库的数据和元数据转换为JSON或BSON格式的...

    MongoDB Community(mongodb-linux-aarch64-ubuntu1804-5.0.8.tgz)

    MongoDB Community Server(mongodb-linux-aarch64-ubuntu1804-5.0.8.tgz)适用于Ubuntu 18.04 Arm芯片, MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决...

    mongodb-linux-x86_64-3.4.10.tgz

    这将创建一个名为`mongodb-linux-x86_64-3.4.10`的目录,包含所有MongoDB的可执行文件。 二、配置环境变量 为了能在任意目录下运行MongoDB,你需要将其可执行文件路径添加到系统的PATH环境变量中。在`.bashrc`或`....

Global site tag (gtag.js) - Google Analytics