有点标题党的意思,不过下面三招确实比较实用,内容来自Conversocial公司的VP Colin Howe在London MongoDB用户组的一个分享。
申请:下面几点并非放四海皆准的法则,具体是否能够使用,还需要根据自己的应用场景和数据特点来决定。
1.使用组合式的大文档
我们知道MongoDB是一个文档数据库,其每一条记录都是一个JSON格式的文档。比如像下面的例子,每一天会生成一条这样的统计数据:
{ metric: "content_count", client: 5, value: 51, date: ISODate("2012-04-01 13:00") } { metric: "content_count", client: 5, value: 49, date: ISODate("2012-04-02 13:00") }
而如果采用组合式大文档的话,就可以这样将一个月的数据全部存到一条记录里:
{ metric: "content_count", client: 5, month: "2012-04", 1: 51, 2: 49, ... }
通过上面两种方式存储,预先一共存储大约7GB的数据(机器只有1.7GB的内存),测试读取一年信息,这二者的读性能差别很明显:
- 第一种: 1.6秒
- 第二种: 0.3秒
那么问题在哪里呢?
实际上原因是组合式的存储在读取数据的时候,可以读取更少的文档数量。而读取文档如果不能完全在内存中的话,其代价主要是被花在磁盘seek上,第一种存储方式在获取一年数据时,需要读取的文档数更多,所以磁盘seek的数量也越多。所以更慢。
实际上MongoDB的知名使用者foursquare就大量采用这种方式来提升读性能。见此
2.采用特殊的索引结构
我们知道,MongoDB和传统数据库一样,都是采用B树作为索引的数据结构。对于树形的索引来说,保存热数据使用到的索引在存储上越集中,索引浪费掉的内存也越小。所以我们对比下面两种索引结构:
db.metrics.ensureIndex({ metric: 1, client: 1, date: 1})
与
db.metrics.ensureIndex({ date: 1, metric: 1, client: 1 })
采用这两种不同的结构,在插入性能上的差别也很明显。
当采用第一种结构时,数据量在2千万以下时,能够基本保持10k/s 的插入速度,而当数据量再增大,其插入速度就会慢慢降低到2.5k/s,当数据量再增大时,其性能可能会更低。
而采用第二种结构时,插入速度能够基本稳定在10k/s。
其原因是第二种结构将date字段放在了索引的第一位,这样在构建索引时,新数据更新索引时,不是在中间去更新的,只是在索引的尾巴处进行修改。那 些插入时间过早的索引在后续的插入操作中几乎不需要进行修改。而第一种情况下,由于date字段不在最前面,所以其索引更新经常是发生在树结构的中间,导 致索引结构会经常进行大规模的变化。
3.预留空间
与第1点相同,这一点同样是考虑到传统机械硬盘的主要操作时间是花在磁盘seek操作上。
比如还是拿第1点中的例子来说,我们在插入数据的时候,预先将这一年的数据需要的空间都一次性插入。这能保证我们这一年12个月的数据是在一条记录 中,是顺序存储在磁盘上的,那么在读取的时候,我们可能只需要一次对磁盘的顺序读操作就能够读到一年的数据,相比前面的12次读取来说,磁盘seek也只 有一次。
db.metrics.insert([ { metric: 'content_count', client: 3, date: '2012-01', 0: 0, 1: 0, 2: 0, ... } { .................................., date: '2012-02', ... }) { .................................., date: '2012-03', ... }) { .................................., date: '2012-04', ... }) { .................................., date: '2012-05', ... }) { .................................., date: '2012-06', ... }) { .................................., date: '2012-07', ... }) { .................................., date: '2012-08', ... }) { .................................., date: '2012-09', ... }) { .................................., date: '2012-10', ... }) { .................................., date: '2012-11', ... }) { .................................., date: '2012-12', ... }) ])
结果:
- 如果不采用预留空间的方式,读取一年的记录需要62ms
- 如果采用预留空间的方式,读取一年的记录只需要6.6ms
相关推荐
综上所述,解决MongoDB的磁盘IO问题需要综合考虑数据库设计、索引策略、硬件配置、系统参数调整以及查询优化等多个方面。通过对这些方面的深入理解和实践,可以有效地提高MongoDB的性能,满足高并发读写场景的需求。
- **问题分析**:这种方式虽然方便管理,但由于每个文档都非常大,导致内存利用率低下,同时也增加了磁盘I/O的压力。 - **优化措施**: - 将多语言版本的信息拆分成独立的文档,例如`{_id: "375-en_US", name: ...
MongoDB性能测试报告详细分析了在大数据量环境下,包括GridFS和组合索引在内的性能表现。...报告最后总结了插入和查询的性能表现,并提出了一些未解决的问题,这些问题可能需要在后续的工作中继续探索。
MongoDB使用预分配策略以减少磁盘碎片,但过度的IO操作可能会影响整体性能。在这种情况下,检查系统IO负载和MongoDB的日志以识别问题根源是必要的。 文中提到的预分片策略是为了加速数据加载和导入,但这通常用于分...
MongoDB 是一个流行的开源文档型数据库,特别适合处理大规模数据。在这个亿级数据量的性能测试中,我们关注了MongoDB在不同操作下的表现,包括插入、查询和分片(Sharding)等。 1) **普通插入性能**: 插入性能在...
例如,MongoDB的磁盘IO高问题,可能是由于数据写入量过大或者索引设计不合理导致的,手册会提供相应的排查和优化步骤。此外,对于MongoDB的空间使用问题,手册会讲解如何分析存储空间的占用情况,以及如何进行有效...
可以使用`mongostat`命令实时监控MongoDB的运行状态,包括磁盘使用情况、锁等待时间、网络IO等。同时,定期检查日志文件,以便及时发现和解决问题。 7. **故障切换**: 如果主节点发生故障,从节点可以在确认主...
在挂载文件系统时,可以使用`-o directio`选项开启Direct I/O支持。 3. **打开文件标志**:在使用Direct I/O时,需要在open()函数中设置O_DIRECT标志,告诉内核采用直接I/O方式。例如: ``` int fd = open("/dev/...
9. **OS IO设备预读值**:设置预读值为32,以提高磁盘I/O效率。使用`blockdev --getra`命令检查预读值。 10. **OS NUMA配置**:禁用NUMA(非统一内存访问),以避免内存访问延迟。在内核启动参数中应包含`numa=off`...
在描述中提到,安装数据库时可能需要用到libaio,这是因为许多现代数据库系统,如Oracle、MongoDB、PostgreSQL等,为了提高性能,都支持异步I/O。通过使用libaio,数据库可以在后台处理磁盘读写,而不阻塞主线程,...
MongoDB 是一个流行的开源文档型数据库,以其灵活性、高性能和易于使用而闻名。在使用 MongoDB 时,管理和启动数据库服务是关键步骤之一。MongoDB 的启动命令 `mongod` 是用于启动数据库服务的命令行工具,它接受多...
- **IO**:Bi和Bo表示磁盘读写,较大的值和较高的wa(等待I/O的CPU时间)可能表示磁盘IO问题。 - **system**:in和cs表示中断和上下文切换,过高可能影响性能。 - **CPU**:us表示用户进程占用的CPU时间,持续...
1. **硬件限制**:包括CPU、内存、磁盘IO等。 2. **配置不当**:如不合理的索引策略、内存设置等。 3. **网络延迟**:高延迟或不稳定网络环境会导致数据传输效率低下。 4. **软件问题**:数据库版本过旧、驱动程序不...
3. 分析、定位和解决问题:结合日志信息和应用环境,对问题进行综合分析,以确定故障原因并采取相应措施。 4. 网络故障排除:涉及网络问题时,应检查硬件传输、网卡状态、DNS配置、服务运行状况、访问权限以及...
网络或磁盘IO全部异步化,以前都是只有mongodb是异步客户端,而redis和oss都是同步请求 对url.py做了重大改变,以前是只有多了一个api,就往url.py里写,弄得后面上百个api很难找到某个 功能高度封装,降低代码耦合...