mongodb持久化

先上一张图(根据此处重画),看完下面的内容应该可以理解。
mongodb使用内存映射的方式来访问和修改数据库文件,内存由操作系统来管理。开启journal的情况,数据文件映射到内存2个view:private view和write view。对write view的更新会刷新到磁盘,而对private view的更新不刷新到磁盘。写操作先修改private view,然后批量提交(groupCommit),修改write view。
WriteIntent
发生写操作时,会记录修改的内存地址和大小,由结构WriteIntent表示。
/** Declaration of an intent to write to a region of a memory mapped view
* We store the end rather than the start pointer to make operator< faster
* since that is heavily used in set lookup.
*/
struct WriteIntent { /* copyable */
void *p; // intent to write up to p
unsigned len; // up to this len void* end() const { return p; }
bool operator < (const WriteIntent& rhs) const { return end() < rhs.end(); } // 用于排序
};
WriteIntent
查看代码会发现大量的类似调用,这就是保存WriteIntent。
getDur().writing(..)
getDur().writingPtr(...)
CommitJob
CommitJob保存未批量提交的WriteIntent和DurOp,目前只使用一个全局对象commitJob。对于不修改数据库文件的操作,如创建文件(FileCreatedOp)、删除库(DropDbOp),不记录WriteIntent,而是记录DurOp。
ThreadLocalIntents
由于mongodb是多线程程序,同时操作CommitJob需要加锁(groupCommitMutex)。为了避免频繁加锁,使用了线程局部变量
/** so we don't have to lock the groupCommitMutex too often */
class ThreadLocalIntents {
enum { N = };
std::vector<dur::WriteIntent> intents;
};
ThreadLocalIntents
WriteIntent先存放到intents里,当intents的大小达到N时,就添加到CommitJob里,这时候要才需要加锁。添加intents到CommitJob时,会对重叠的内存地址段进行合并,减少WriteIntent的数量。当然,CommitJob也会对添加的WriteIntent进行检查是否重复添加。这里有一个问题,如果intents的大小没有达到N,是不是永远都不添加到CommitJob里呢?不会。因为每次写操作,必须先获得'w'锁(库的写锁)或者'W'锁(全局写锁),当释放锁的时候,也会把intents添加到全局的数组里。
何时groupCommit
写操作会先修改private view,并保存WriteIntent到CommitJob。但是private view是不持久化的,CommitJob保存的WriteIntent何时groupCommit?
const unsigned UncommittedBytesLimit = (sizeof(void*)==) ? * * : * * ;
UncommittedBytesLimit
- durThread线程定期groupCommit,间隔时间可以由journalCommitInterval选项指定。默认是100毫秒(journal文件所在硬盘分区和数据文件所在硬盘相同)或者30毫秒。另外,如果有线程在等待groupCommit完成,或者未commit的字节数大于UncommittedBytesLimit / 2,会提前commit。
- 调用commitIfNeeded。如果未commit的字节数不小于UncommittedBytesLimit,或者是强制groupCommit,则执行groupCommit。
groupCommit的过程
1.PREPLOGBUFFER
首先是生成写操作日志(redo log)。对WriteIntent从小到大排序,这样可以对前后的WriteIntent进行重叠、重复的合并。对每个WriteIntent的地址,和每个数据文件的private view的基地址进行比较(private view的基地址已经排序,查找很快),找出其隶属的数据文件的标号。WriteIntent的地址减掉private view的基地址得到偏移,再从private view把修改的数据复制下来。这样数据文件标号、偏移、数据,形成一个JEntry。
2.WRITETOJOURNAL
把写操作日志压缩并写入journal文件。这一步完成之后,即使mongodb异常退出,数据也不会丢失了,因为可以根据journal文件中的写操作日志重建数据。关于journal文件可以参见这里。
3.WRITETODATAFILES
把所有写操作更新到write view中。后台线程DataFileSync会定期把write view刷新到磁盘中,默认是60秒,由syncdelay选项指定。
4.REMAPPRIVATEVIEW
private view是copy on write的,即在发生写时开辟新的内存,否则是和write view共用一块内存的。如果写操作很频繁,则private view会申请很多的内存,所以private view会remap,防止占用内存过多。并不是每次groupCommit都会remap,只有持有'W'锁的情况下才会remap。
durThread线程的定期groupCommit有三种情况会remap
- privateMapBytes >= UncommittedBytesLimit
- 前面9次groupCommit都没有ramap
- durOptions选项指定了DurAlwaysRemap
调用commitIfNeeded发生的groupCommit,如果持有持有'W'锁则remap。
remap的一个问题
在_REMAPPRIVATEVIEW()函数中,有这样一段代码
#if defined(_WIN32) || defined(__sunos__)
// Note that this negatively affects performance.
// We must grab the exclusive lock here because remapPrivateView() on Windows and
// Solaris need to grab it as well, due to the lack of an atomic way to remap a
// memory mapped file.
// See SERVER-5723 for performance improvement.
// See SERVER-5680 to see why this code is necessary on Windows.
// See SERVER-8795 to see why this code is necessary on Solaris.
LockMongoFilesExclusive lk;
#else
LockMongoFilesShared lk;
#endif
执行remap时,需要LockMongoFiles锁。win32下,这把锁是排他锁;而其他平台下(linux等)是共享锁。write view刷新到磁盘的时候,也需要LockMongoFiles共享锁。这样,在win32下,如果在执行磁盘刷新操作,则remap操作会被阻塞;而在执行remap之前,已经获得了'W'锁,这样会阻塞所有的读写操作。因此,在win32平台下,太多的写操作(写操作越多,remap越频繁)会导致整个数据库读写阻塞。
在win32和linux下做了一个测试,不停的插入大小为10k的记录。结果显示如下:上图win32平台,下图为linux平台;横坐标为时间轴,从0开始;纵坐标为每秒的插入次数。很明显的,linux平台的性能比win32好很多。


mongodb持久化的更多相关文章
- redis mongodb持久化的方式
目录 redis持久化方式(两种) RDB持久化 AOF持久化 两种持续化方式需要明确的问题 对比 MongoDB持久化方式 redis持久化方式(两种) RDB持久化 redis提供了RDB持久化的 ...
- scrapy框架的另一种分页处理以及mongodb的持久化储存以及from_crawler类方法的使用
一.scrapy框架处理 1.分页处理 以爬取亚马逊为例 爬虫文件.py # -*- coding: utf-8 -*- import scrapy from Amazon.items import ...
- MongoDB丢数据问题的分析
坊间有很多传说MongoDB会丢数据.特别是最近有一个InfoQ翻译的Sven的一篇水文(为什么叫做水文?因为里面并没有他自己的原创,只是搜罗了一些网上的博客,炒了些冷饭吃),其中又提到了丢数据的事情 ...
- HBase、Redis、MongoDB、Couchbase、LevelDB主流 NoSQL 数据库的对比
最近小组准备启动一个 node 开源项目,从前端亲和力.大数据下的IO性能.可扩展性几点入手挑选了 NoSql 数据库,但具体使用哪一款产品还需要做一次选型. 我们最终把选项范围缩窄在 HBase.R ...
- Redis、Memcache和MongoDB的区别
>>Memcached Memcached的优点:Memcached可以利用多核优势,单实例吞吐量极高,可以达到几十万QPS(取决于key.value的字节大小以及服务器硬件性能,日常环境 ...
- Redis、Memcache与MongoDB的区别
>>Memcached Memcached的优点:Memcached可以利用多核优势,单实例吞吐量极高,可以达到几十万QPS(取决于key.value的字节大小以及服务器硬件性能,日常环境 ...
- redis和mongodb的比较
>>RedisRedis的优点:支持多种数据结构,如 string(字符串). list(双向链表).dict(hash表).set(集合).zset(排序set).hyperloglog ...
- 三个缓存数据库Redis、Memcache、MongoDB
>>Memcached Memcached的优点:Memcached可以利用多核优势,单实例吞吐量极高,可以达到几十万QPS(取决于key.value的字节大小以及服务器硬件性能,日常环境 ...
- Redis、Memcache和MongoDB
一.Memcached Memcached的优点:Memcached可以利用多核优势,单实例吞吐量极高,可以达到几十万QPS(取决于key.value的字节大小以及服务器硬件性能,日常环境中QPS高峰 ...
随机推荐
- 日本电商Rakuten:最凶猛的国际扩张者
这是普及社(puji-she)第五篇关于电商开放平台的文章,今天关注日本的Rakuten,它是一家综合性的企业,核心业务包括电子商务.旅游.信用 及支付.金融证券.新闻门户等.本文关注Rakuten的 ...
- 通过GCD、NSOperationQueue队列、NSThread三种方法来创建多线程
#import "ViewController.h" @interface ViewController () @property (weak, nonatomic) IBOutl ...
- 6. Android框架和工具之 JSON解析
Android进阶笔记17:3种JSON解析工具(org.json.fastjson.gson)
- leetcode 题解:Binary Tree Preorder Traversal (二叉树的先序遍历)
题目: Given a binary tree, return the preorder traversal of its nodes' values. For example:Given binar ...
- 【网络编程】之十二、wsaeventselect+线程池 服务器实现
#include<WinSock2.h> #include<iostream> using namespace std; #pragma comment(lib, " ...
- 重构5-Pull Up Field(字段上移)
我们来看看一个和上移方法十分类似的重构.我们处理的不是方法,而是字段. public abstract class Account{} public class CheckingAccount ext ...
- find 忽略文件夹选项-prune的说明
注意:因为习惯在当前路径查找时候,常忽略./ 的指定,但读者不要因此而完全忘记find的格式. 查找时忽略指定目录,是要使用-prune选项,但实际上最重要的还是要和path配合.-prune的意义是 ...
- hdu 4714 Tree2cycle 树形经典问题
发现今天没怎么做题,于是随便写了今天杭电热身赛的一题. 题目:给出一棵树,删边和添边的费用都是1,问如何删掉一些树边添加一些树边,使得树变成一个环. 分析:统计树的分支数.大概有两种做法: 1.直接d ...
- js解析xml,获取XMl标签属性值
<script type="text/javascript"> var xml="<?xml version=\"1.0\" enc ...
- MongoDB - The mongo Shell, Data Types in the mongo Shell
MongoDB BSON provides support for additional data types than JSON. Drivers provide native support fo ...