基本思想

将MongoDB用作内存数据库(in-memory database),也即,根本就不让MongoDB把数据保存到磁盘中的这种用法,引起了越来越多的人的兴趣。这种用法对于以下应用场合来讲,超实用:

  • 置于慢速RDBMS系统之前的写操作密集型高速缓存
  • 嵌入式系统
  • 无需持久化数据的PCI兼容系统
  • 需要轻量级数据库而且库中数据可以很容易清除掉的单元测试(unit testing)

如果这一切可以实现就真是太优雅了:我们就能够巧妙地在不涉及磁盘操作的情况下利用MongoDB的查询/检索功能。可能你也知道,在99%的情况下,磁盘IO(特别是随机IO)是系统的瓶颈,而且,如果你要写入数据的话,磁盘操作是无法避免的。

MongoDB有一个非常酷的设计决策,就是她可以使用内存影射文件(memory-mapped file)来处理对磁盘文件中数据的读写请求。这也就是说,MongoDB并不对RAM和磁盘这两者进行区别对待,只是将文件看作一个巨大的数组,然后按照字节为单位访问其中的数据,剩下的都交由操作系统(OS)去处理!就是这个设计决策,才使得MongoDB可以无需任何修改就能够运行于RAM之中。

fbm

翻译于 2013/05/04 01:16
 顶

3

 
 

实现方法

这一切都是通过使用一种叫做tmpfs的特殊类型文件系统实现的。在Linux中它看上去同常规的文件系统(FS)一样,只是它完全位于RAM中(除非其大小超过了RAM的大小,此时它还可以进行swap,这个非常有用!)。我的服务器中有32GB的RAM,下面让我们创建一个16GB的 tmpfs:

# mkdir /ramdata
# mount -t tmpfs -o size=16000M tmpfs /ramdata/
# df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/xvde1 5905712 4973924 871792 86% /
none 15344936 0 15344936 0% /dev/shm
tmpfs 16384000 0 16384000 0% /ramdata

接下来要用适当的设置启动MongoDB。为了减小浪费的RAM数量,应该把smallfilesnoprealloc设置为true。既然现在是基于RAM的,这么做完全不会降低性能。此时再使用journal就毫无意义了,所以应该把nojournal设置为true。

dbpath=/ramdata
nojournal = true
smallFiles = true
noprealloc = true

MongoDB启动之后,你会发现她运行得非常好,文件系统中的文件也正如期待的那样出现了:

# mongo
MongoDB shell version: 2.3.2
connecting to: test
> db.test.insert({a:1})
> db.test.find()
{ "_id" : ObjectId("51802115eafa5d80b5d2c145"), "a" : 1 } # ls -l /ramdata/
total 65684
-rw-------. 1 root root 16777216 Apr 30 15:52 local.0
-rw-------. 1 root root 16777216 Apr 30 15:52 local.ns
-rwxr-xr-x. 1 root root 5 Apr 30 15:52 mongod.lock
-rw-------. 1 root root 16777216 Apr 30 15:52 test.0
-rw-------. 1 root root 16777216 Apr 30 15:52 test.ns
drwxr-xr-x. 2 root root 40 Apr 30 15:52 _tmp

现在让我们添加一些数据,证实一下其运行完全正常。我们先创建一个1KB的document,然后将它添加到MongoDB中4百万次:

> str = ""

> aaa = "aaaaaaaaaa"
aaaaaaaaaa
> for (var i = 0; i < 100; ++i) { str += aaa; } > for (var i = 0; i < 4000000; ++i) { db.foo.insert({a: Math.random(), s: str});}
> db.foo.stats()
{
"ns" : "test.foo",
"count" : 4000000,
"size" : 4544000160,
"avgObjSize" : 1136.00004,
"storageSize" : 5030768544,
"numExtents" : 26,
"nindexes" : 1,
"lastExtentSize" : 536600560,
"paddingFactor" : 1,
"systemFlags" : 1,
"userFlags" : 0,
"totalIndexSize" : 129794000,
"indexSizes" : {
"_id_" : 129794000
},
"ok" : 1
}
fbm

翻译于 2013/05/04 01:36
 顶

3

 
 
可以看出,其中的document平均大小为1136字节,数据总共占用了5GB的空间。_id之上的索引大小为130MB。现在我们需要验证一件 非常重要的事情:RAM中的数据有没有重复,是不是在MongoDB和文件系统中各保存了一份?还记得MongoDB并不会在她自己的进程内缓存任何数据,她的数据只会缓存到文件系统的缓存之中。那我们来清除一下文件系统的缓存,然后看看RAM中还有有什么数据:

# echo 3 > /proc/sys/vm/drop_caches
# free
total used free shared buffers cached
Mem: 30689876 6292780 24397096 0 1044 5817368
-/+ buffers/cache: 474368 30215508
Swap: 0 0 0

可以看到,在已使用的6.3GB的RAM中,有5.8GB用于了文件系统的缓存(缓冲区,buffer)。为什么即使在清除所有缓存之后,系统中仍然还有5.8GB的文件系统缓存??其原因是,Linux非常聪明,她不会在tmpfs和缓存中保存重复的数据。太棒了!这就意味着,你在RAM只有一份数据。下面我们访问一下所有的document,并验证一下,RAM的使用情况不会发生变化:

> db.foo.find().itcount()
4000000 # free
total used free shared buffers cached
Mem: 30689876 6327988 24361888 0 1324 5818012
-/+ buffers/cache: 508652 30181224
Swap: 0 0 0
# ls -l /ramdata/
total 5808780
-rw-------. 1 root root 16777216 Apr 30 15:52 local.0
-rw-------. 1 root root 16777216 Apr 30 15:52 local.ns
-rwxr-xr-x. 1 root root 5 Apr 30 15:52 mongod.lock
-rw-------. 1 root root 16777216 Apr 30 16:00 test.0
-rw-------. 1 root root 33554432 Apr 30 16:00 test.1
-rw-------. 1 root root 536608768 Apr 30 16:02 test.10
-rw-------. 1 root root 536608768 Apr 30 16:03 test.11
-rw-------. 1 root root 536608768 Apr 30 16:03 test.12
-rw-------. 1 root root 536608768 Apr 30 16:04 test.13
-rw-------. 1 root root 536608768 Apr 30 16:04 test.14
-rw-------. 1 root root 67108864 Apr 30 16:00 test.2
-rw-------. 1 root root 134217728 Apr 30 16:00 test.3
-rw-------. 1 root root 268435456 Apr 30 16:00 test.4
-rw-------. 1 root root 536608768 Apr 30 16:01 test.5
-rw-------. 1 root root 536608768 Apr 30 16:01 test.6
-rw-------. 1 root root 536608768 Apr 30 16:04 test.7
-rw-------. 1 root root 536608768 Apr 30 16:03 test.8
-rw-------. 1 root root 536608768 Apr 30 16:02 test.9
-rw-------. 1 root root 16777216 Apr 30 15:52 test.ns
drwxr-xr-x. 2 root root 40 Apr 30 16:04 _tmp
# df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/xvde1 5905712 4973960 871756 86% /
none 15344936 0 15344936 0% /dev/shm
tmpfs 16384000 5808780 10575220 36% /ramdata

果不其然! :)

fbm

翻译于 2013/05/04 01:57
 顶

3

 
 

复制(replication)呢?

既然服务器在重启时RAM中的数据都会丢失,所以你可能会想使用复制。采用标准的副本集(replica set)就能够获得自动故障转移(failover),还能够提高数据读取能力(read capacity)。如果有服务器重启了,它就可以从同一个副本集中另外一个服务器中读取数据从而重建自己的数据(重新同步,resync)。即使在大量数据和索引的情况下,这个过程也会足够快,因为索引操作都是在RAM中进行的 :)

有一点很重要,就是写操作会写入一个特殊的叫做oplog的collection,它位于local数据库之中。缺省情况下,它的大小是总数据量的5%。在我这种情况下,oplog会占有16GB的5%,也就是800MB的空间。在拿不准的情况下,比较安全的做法是,可以使用oplogSize这个选项为oplog选择一个固定的大小。如果备选服务器宕机时间超过了oplog的容量,它就必须要进行重新同步了。要把它的大小设置为1GB,可以这样:

oplogSize = 1000
fbm

翻译于 2013/05/04 02:22
 顶

2

 
 

分片(sharding)呢?

既然拥有了MongoDB所有的查询功能,那么用它来实现一个大型的服务要怎么弄?你可以随心所欲地使用分片来实现一个大型可扩展的内存数据库。配置服务器(保存着数据块分配情况)还还是用过采用基于磁盘的方案,因为这些服务器的活动数量不大,老从头重建集群可不好玩。

注意事项

RAM属稀缺资源,而且在这种情况下你一定想让整个数据集都能放到RAM中。尽管tmpfs具有借助于磁盘交换(swapping)的能力,但其性能下降将非常显著。为了充分利用RAM,你应该考虑:

  • 使用usePowerOf2Sizes选项对存储bucket进行规范化
  • 定期运行compact命令或者对节点进行重新同步(resync)
  • schema的设计要相当规范化(以避免出现大量比较大的document)

结论

宝贝,你现在就能够将MongoDB用作内存数据库了,而且还能使用她的所有功能!性能嘛,应该会相当惊人:我在单线程/核的情况下进行测试,可以达到每秒20K个写入的速度,而且增加多少个核就会再增加多少倍的写入速度。

把 MongoDB 当成是纯内存数据库来使用(Redis 风格)的更多相关文章

  1. mongoDB 学习笔记纯干货(mongoose、增删改查、聚合、索引、连接、备份与恢复、监控等等)

    最后更新时间:2017-07-13 11:10:49 原始文章链接:http://www.lovebxm.com/2017/07/13/mongodb_primer/ MongoDB - 简介 官网: ...

  2. 【转】mongoDB 学习笔记纯干货(mongoose、增删改查、聚合、索引、连接、备份与恢复、监控等等)

    mongoDB 学习笔记纯干货(mongoose.增删改查.聚合.索引.连接.备份与恢复.监控等等) http://www.cnblogs.com/bxm0927/p/7159556.html

  3. 纯CSS3实现自定义涂鸦风格的边框

    今天我们要来分享一款基于纯CSS3的自定义边框应用,看上去它像一个Tooltip控件,因为下边框有一个小三角,就像很多地方的引用文本框一样.另外这款CSS3边框是涂鸦风格的,看起来很有个性.用CSS3 ...

  4. 纯CSS实现扁平化风格开关按钮

    开关样式预览图 前言 最近在基于bootstrap框架开发一个网站,在填写表单一项需要用户填写是否选择某一选项,本来想引用bootstrap框架自带的一个按钮插件,结果在引用js的时候总是出错,就找了 ...

  5. mongodb研究(mongodb 内存数据库)

    本日志大部分都不是原创的转载复制的会带链接保持版权 工作中使用mongodb已经好久了,讽刺的是到了最后快离职的时候才有时间好好研究下源码.   印象:mongodb是一个内存数据库,数据都是放到内存 ...

  6. Redis和Memcache和MongoDB简介及区别分析(整理)

    Redis和Memcache 一.Redis简介 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.从2010年 ...

  7. mongodb vs redis(Tokyo Tyrant转)

    * MongoDB vs Redis vs Tokyo Tyrant(原文链接:http://www.cnblogs.com/riceball/archive/2010/03/05/MongoDB_V ...

  8. Spring Boot 2 快速教程:WebFlux 集成 Mongodb(四)

    摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 这是泥瓦匠的第104篇原创 文章工程:* JDK 1.8* M ...

  9. [转帖]SSD和内存数据库技术

    SSD和内存数据库技术 自己的理解还是不是很对 SSD 提升的是 随机读 并没有对顺序写有多大的提升, 因为数据库采用的是redo的模式. 理论上写入 时是顺序写 所以 写并发的提升不会很大 但是会很 ...

随机推荐

  1. TCGA癌症缩写、癌症中英文对照

    Cohort 英文名称 中文名称 ACC Adrenocortical carcinoma 肾上腺皮质癌 BLCA Bladder Urothelial Carcinoma 膀胱尿路上皮癌 BRCA ...

  2. Codeforces - 1191B - Tokitsukaze and Mahjong - 模拟

    https://codeforces.com/contest/1191/problem/B 小心坎张听的情况. #include<bits/stdc++.h> using namespac ...

  3. L The Digits String(没有写完,有空补)

    链接:https://ac.nowcoder.com/acm/contest/338/L来源:牛客网 Consider digits strings with length n, how many d ...

  4. ELK + Filebeat日志分析系统安装

    之前搭建过elk,用于分析日志,无奈服务器资源不足,开了多个Logstash之后发现占用内存过高,于是现在改为Filebeat做日志收集,记录一下搭建过程和遇到问题的解决方案. 第一步 , 安装jdk ...

  5. linux典型应用对系统资源使用的特点

  6. java插件提示安全设定高,不能加载解决方法

    当不可信小应用程序或应用程序在 Web 浏览器中运行时,我应当如何控制? 本文适用于: Java 版本: 7.0, 8.0 通过 Java 控制面板设置安全级别 在 Java 控制面板中,单击 Sec ...

  7. Polish orthography

    Computer encoding[edit] There are several different systems for encoding the Polish alphabet for com ...

  8. List接口和Set接口及其常用实现类概述

    一.List接口 List:有序的 collection(也称为序列).此接口的用户可以对列表中每个元素的插入位置进行精确地控制.用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元 ...

  9. 9.Markdown语法(自用)——2019年12月12日

    title: markdown语法说明 date: "2018-12-26 20:17:16" tags: 技术指令 categories: 技术驿站 markdown语法说明 2 ...

  10. jquery对象中 “冒号” 详解

      冒号  可以理解为 “匹配” 或 “选取”的意思.   $(":button") 表示匹配所有的按钮.$("input:checked")表示匹配所有选中的 ...