MongoDB二进制文件
支持的运行平台
推荐的运行平台
- Amazon Linux
- Debian 7.1
- RHEL / CentOS 6.2+
- SLES 11+
- Ubuntu LTS 12.04
- Ubuntu LTS 14.04
- Windows Server 2012 & 2012 R2
推荐mongodb最新的release版本
MongoDB dbpath
并发性(基于不同的数据库引擎的比较)
MMAPv1
3.0之后的改动:3.0之后,MongoDB MMapv1提供文档级别的数据库锁:所有的集合都有一个唯一的读写锁,这意味着不同的集合可以同时执行更新操作
在2.2到2.6之间,每个数据库都有一个读写锁,允许并发读操作,但每个database同一时刻只能有一个写操作。在更早的版本中,在一个mongod进程中,所有的写操作抢占一个写锁
WiredTiger
wt单文档支持并发读写,客户端可在写操作执行期间进行读取操作,不同的线程也可以同时去修改一个集合的某一条数据
Data Consistency(数据一致性)
Journaling(日志)
MongoDB的日志持久化在磁盘,并且使用的是预写式日志。如果遇到意外故障(例如断电),日志信息保证了MongoDB可以迅速恢复记录在日志中的但还没有记录到数据文件中的写操作。
Read Concern(数据读策略)
这里详细说明了数据度策略是什么以及解决的问题,以及readConcern
和readPreference
的比较。这里简单说明下:
readConcern 的初衷在于解决『脏读』的问题,比如用户从 MongoDB 的 primary 上读取了某一条数据,但这条数据并没有同步到大多数节点,然后 primary 就故障了,重新恢复后 这个primary 节点会将未同步到大多数节点的数据回滚掉,导致用户读到了『脏数据』。
当指定 readConcern 级别为 majority 时,能保证用户读到的数据『已经写入到大多数节点』,而这样的数据肯定不会发生回滚,避免了脏读的问题。
需要注意的是,readConcern 能保证读到的数据『不会发生回滚』,但并不能保证读到的数据是最新的,这个官网上也有说明。
Regardless of the read concern level, the most recent data on a node may not reflect the most recent version of the data in the system.
有用户误以为,readConcern 指定为 majority 时,客户端会从大多数的节点读取数据,然后返回最新的数据。
实际上并不是这样,无论何种级别的 readConcern,客户端都只会从『某一个确定的节点』(具体是哪个节点由 readPreference 决定)读取数据,该节点根据自己看到的同步状态视图,只会返回已经同步到大多数节点的数据。
注意,读策略是MongoDB3.2加入的新特性,如果要使用读取『已经写入到大多数节点』的策略,除了要注意MongoDB的版本之外,还应该注意以下两点:
- 启动mongod的时候,添加
--enableMajorityReadConcern
参数 - 副本集必须使用wt存储引擎,而且选举协议为
protocol version 1
Write Concern(数据写策略)
写策略主要讨论的问题是MongoDB写操作的确认等级,写请求确认等级影响了写操作的速度。如果写确认等级比较低,写速度快,随着确认等级的升高,客户端可能要花更多的时间等待MongoDB进行写确认。如果说配置的写确认等级较低,有可能会出现写操作返回成功,但是并没有数据发生改变的情况
所以在生产环境使用MongoDB之前需要先考虑好合适的写操作确认等级
Networking(网络)
Use Trusted Networking Environments(使用可信任的网络环境)
请在可信任的环境下运行MongoDB,通过网络保护策略保护MongoDB被任何非法的机器,系统,或者是网络访问(一般就是指在内网环境中启动运行MongoDB,只有同一内网的机器才有权限访问MongoDB)。如果必须暴露在网络环境中,MongoDB必须要配合相应的权限系统,监控系统等去保证MongDB不被非法访问。
默认情况下,MongoDB的权限认证系统不会开启
关于MongoDB的安全性,还有以下文章参考:
Disable HTTP Interface(禁用http接口)
MongoDB提供了一个http接口,用于检查节点状态,而且也可以用来执行一些脚本。http接口默认关闭,不能在生产环境开启http接口
Manage Connection Pool Sizes(连接池管理)
为了避免连接资源过载(常见的can not get resource from the pool),要预估连接池大小,设定一个比较合理的值。通常的经验是,在一开始的时候设定连接池的大小为当前平均数据库请求数量的110-115%,并且需要根据实际情况的改变而进行调整。参考数据库连接池相关参数说明
connPoolStats
命令可以用来查询当前数据库连接数
Hardware Considerations(硬件注意事项)
MongoDB对硬件的要求和限制相对较低
Allocate Sufficient RAM and CPU(充足的内存和cpu)
MMAPv1
由于MMAPv1
自身的并发模型,它并不需要很多的CPU内核。当然,如果增加了CPU内核数量,可以提高一部分性能,但是并不会减少单次处理的相应时间,至少需要一个双核物理CPU。
增加内存可以帮助MongoDB减少页交换次数,关于如何查看centos系统缺页信息,请参考这里
WiredTiger
WiredTiger是一个多线程的存储引擎,能充分发挥出多核CPU的优势。当前活跃线程数和CPU数量的比例影响着wt的性能
- 增加线程数量至CPU核数能提高吞吐量
- 如果活跃线程数量超出CPU数量到达一定成都的时候,吞吐量会下降
mongostat
可以用来查看当前活跃操作数
WiredTiger存储引擎,既使用了WiredTiger内部缓存,也使用了文件系统缓存
MongoDB3.4开始,WiredTiger将会内部缓存将会占用以下(较大的一个)内存空间:
- 50%的内存减去1GB
- 256MB
由于使用了系统缓存,MongoDB实际上会使用掉所有没有被WiredTiger内部缓存和其他应用程序占用的内存空间。文件系统缓存中的数据是被压缩过的
为了调整WiredTiger内部缓存大小,可以通过设定参数storage.wiredTiger.engineConfig.cacheSizeGB
或者--wiredTigerCacheSizeGB
。避免设置的内部缓存大小大于默认值(个人认为这样处理可能是为了防止内存溢出的问题)
注意:
storage.wiredTiger.engineConfig.cacheSizeGB
限制的是WiredTiger内部缓存占用内存大小。因为使用文件系统缓存的原因,操作系统会使用剩余的全部内存空间(所以跑着大业务量的mongod的机器内存使用总会100%)。
这个设定(WiredTiger内部缓存默认值)的前提是一个机器上只运行一个mongod实例,如果你的机器上运行了多个mongod实例的话,应该把这个配置相对调低。生产环境不推荐一个机器上启动多个mongod进程。
如果是在容器中运行mongod实例(单个容器往往没有权限使用全部内存),这时候需要把storage.wiredTiger.engineConfig.cacheSizeGB
的值设的小于容器可使用的内存空间大小
查看WiredTiger内部缓存到底占用了多少内存的方式是,在mongo shell中之行以下命令:db.runCommand( { serverStatus: 1 } ).wiredTiger.cache["bytes currently in the cache"]
Compression and Encryption(压缩和加密)
当开启加密功能的时候,配备AES-NI指令集扩展的CPU的性能表现最好。如果你使用的是企业级mongodb,而且使用了加密存储引擎,请选择配备AES-NI指令集扩展的CPU
Use Solid State Disks (SSDs)(使用固态硬盘)
推荐在生产环境中使用固态硬盘,这样能带来更高的性价比。固态硬盘的随机读写能力非常适合MMMapv1的更新模型。
MongoDB and NUMA Hardware(非均匀存储器访问)
在一个非均匀内存访问的系统中运行MongoDB可能会带来比较多的问题。包括慢查询和高CPU占用。
关于这部分详细内容,请具体参考MongoDB Production Notes
Disk and Storage Systems(磁盘和存储系统)
swap(交换空间)
生产环境中要为的系统分配交换空间。配置交换空间可以避免内存争用问题,防止Linux中的OOM Killer杀掉mongod进程
当使用MMAPv1存储引擎的时候,mongod使用文件映射到内存的方法确保了操作系统不会将MongoDB数据存储在交换空间。在Windows系统上,因为一些限制,使用MMAPv1需要额外的交换空间在,参考MongoDB on Windows
WiredTiger存储引擎在内存不够用的情况下可能会将部分数据存储在交换空间
RAID(磁盘阵列)
大部分生产环境中MongoDB运行环境中,磁盘阵列组合方式都是raid-10
raid-5和raid-6组合方式性能不如raid-10
不要在生产环境中使用raid-0,虽然raid-0提供了很好的写性能,但是它也存在一些缺点,例如会降低读性能。尤其是使用亚马DBS volumes
关于raid,可以参考这里
Remote Filesystems(远程文件系统)
总的来说,远程文件系统是不推荐在生产环境使用的,主要是因为性能问题
如果使用MMAPv1存储引擎,不推荐网络文件系统(NFS),如果数据文件和日志文件都托管在NFS会导致性能问题。如果将数据文件和日志文件放在本地性能将会提高很多
当使用的是WiredTiger存储引擎的时候,如果远程文件系统符合ISO / IEC 9945 - 1:1996,WiredTiger对象就可以远程存储。因为通常情况下远程文件系统都比本地文件系统慢,所以使用远程文件系统会降低MongoDB的性能
如果决定使用NFS,添加以下的NFS选项到/etc/fstab
文件:bg
, nolock
, 和 noatime
Separate Components onto Different Storage Devices(不同组件使用不同的存储设备)
为了提高性能,可以根据应用程序的数据读写模式将数据库文件,journal文件,log文件等写到不同的存储设备上。将组件挂载为一个独立的文件系统,然后通过符号链接将对应的存储设备映射过去
如果使用WiredTiger存储引擎,也可以将索引单独存储到不同的存储设备上。、
注意,使用不同的存储设备将会影响数据库快照备份,因为文件需要被存储到不同的设备和数据卷上
Scheduling(调度)
Scheduling for Virtual or Cloud Hosted Devices(虚拟设备或云托管设备的调度)
如果使用虚拟机或者是云服务运行MongoDB,操作系统应该使用等待调度方式以获得最佳性能。等待调度方式允许操作系统I/O调度遵从底层虚拟机监控程序。
Scheduling for Physical Servers(物理机调度)
如果使用物理机运行MongoDB,那么操作系统应该使用deadline scheduler
的调度方式。deadline scheduler
记录每个请求的最大延迟时间并且能够为磁盘敏感型数据库应用维持一个最合适的磁盘吞吐率
Architecture(架构)
Replica Sets(副本集)
Sharded Clusters 分片集群
Compression(压缩)
WiredTiger可以使用snappy和zlib两种方式压缩数据。snappy拥有较低的压缩比,但是性能损耗小;zlib能获得更高的压缩比,但是性能损耗多
默认情况下,WiredTiger使用snappy作为默认的压缩库,如果想改变默认的压缩设置,查看storage.wiredTiger.collectionConfig.blockCompressor
Platform Specific Considerations(不同平台注意事项)
MongoDB会使用系统安装的glibc,并且要求glibc的版本至少在glibc-2.12-1.2.el6,否则会出现一些已知的bug,为了避免问题最好让glibc版本高于2.13
MongoDB on Linux(在linux上使用MongoDB)
Kernel and File Systems(内核和文件系统)
如果在Linux上使用MongoDB,那么Linux内核版本必须高于2.6.36,而且要使用XFS或者是EXT4文件系统。如果可能的话,尽量使用XFS,因为总体上MongoDB在XFS文件系统上运行地更好
当使用WiredTiger存储引擎的时候,强烈推荐使用XFS文件系统,因为这样能够避免因为使用EXT4文件系统导致的性能问题
当使用MMapv1存储引擎的时候,MongoDB会预先创建数据库文件占用磁盘空间,虽然这时候还没有真的存储数据,而且通常创建的文件都比较大,基于这点考虑,同样推荐使用XFS和EXT4文件系统。如果可能的话,尽量使用XFS
注意:
- 通常情况下,如果使用XFS文件系统,Linux内核版本至低是2.6.25
- 如果使用EXT4文件系统,Linux内核版本最低是2.6.28
- 如果使用Red Hat Enterprise或者是CentOS,内核版本最低为2.6.18-194
fsync() on Directories
MongoDB要求文件系统支持fsync()方法,HGFS和Virtual Box’s shared folders都不支持改方法
Recommended Configuration(推荐配置)
对于所有的MongoDB部署环境:
- 主机必须使用Network Time Protocol (NTP)来同步时钟,这对于分片集群来说非常重要
关于WiredTiger和MMAPv1存储引擎,有以下推荐配置:
- 关掉存储数据文件的volumn的atime
- 设定文件描述符限制
-n
和用户进程可占用文件描述符数量限制(ulimit)-u
高于20000,相关内容参考这里。ulimit过低将可能会导致MongoDB在业务繁忙的时候产生错误,进而甚至导致数据库连接失败,服务不可用等严重情况 - 关闭透明大页,MongoDB使用普通虚拟内存页性能表现更好
- 在BIOS中关闭NUMA
- 禁用SELinux,如果可能的话。如果已经在Red Hat操作系统中使用了SELinux,必须做好相应配置,参考Configure SELinux for MongoDB和Configure SELinux for MongoDB Enterprise
如果使用SELinux,任何需要使用server-side javascript的MongoDB操作语句将会导致segfault errors。Disable Server-Side Execution of JavaScript介绍了如何禁止执行server-side javascript
补充说明:
- atime
参考这篇文章,因为数据库文件可能频繁被修改,如果关闭atime,这样避免文件改动带来的atime的修改影响部分性能 - ulimit
参考这篇文章,一般最大打开文件数会是系统内存的10%(以KB来计算)(称之为系统级限制),查看系统级别的最大打开文件数可以使用sysctl -a | grep fs.file-max
命令查看。与此同时,内核为了不让某一个进程消耗掉所有的文件资源,其也会对单个进程最大打开文件数做默认值处理(称之为用户级限制),默认值一般是1024,使用ulimit -n
命令可以查看。在Web服务器中,通过更改系统默认值文件描述符的最大值来优化服务器是最常见的方式之一,具体优化方式请查看http://blog.csdn.net/kumu_linux/article/details/7877770。 - 关于Transparent Huge Pages(透明大页)
- numa
针对使用WiredTiger存储引擎的建议:
- 不管使用什么类型的存储介质(机械硬盘,ssd),都要将linux系统readahead(文件预读)设置为0。设定更高等级的文件预读参数有利于连续的io操作,但是MongoDB的磁盘操作通常情况下都是随机的,调高文件预读等级只能带来有限的好处,而且会影响MongoDB本身的性能。因此,将readahead设置为0在大部分的工作场景中能让MonoDB获得最佳性能。
针对使用MMAPv1存储引擎的建议:
- 保证存储数据库文件的块设备的readahead是合适的。针对硬盘的随机读写操作类型,可以设定较低的readahead为32(16KB)。对于标准块设备,
sudo blockdev --report
可以获取当前readahead值,sudo blockdev --setra <value> <device>
可以用于制定设备的值
补充说明:
readahead(文件预读): Linux的文件预读readahead,指Linux系统内核将指定文件的某区域预读进页缓存起来,便于接下来对该区域进行读取时,不会因缺页(page fault)而阻塞。因为从内存读取比从磁盘读取要快很多。预读可以有效的减少磁盘的寻道次数和应用程序的I/O等待时间,是改进磁盘读I/O性能的重要优化手段之一。
MongoDB and TLS/SSL libraries
在Linux系统中可能会看到以下错误1
2<path to SSL libs>/libssl.so.<version>: no version information available (required by /usr/bin/mongod)
<path to SSL libs>/libcrypto.so.<version>: no version information available (required by /usr/bin/mongod)
这个警告说明了系统的TLS/SSL库和编译MongoDB使用的不一致,通常情况下并不需要关注这个,但仍然可以使用以下命令来查看MongoDB需要的TLS/SSL库版本1
2objdump -T <path to mongod>/mongod | grep " SSL_"
objdump -T <path to mongod>/mongod | grep " CRYPTO_"
上述命令将返回以下结果:1
20000000000000000 DF *UND* 0000000000000000 libssl.so.10 SSL_write
0000000000000000 DF *UND* 0000000000000000 OPENSSL_1.0.0 SSL_write
接下来检测下系统中的TLS/SSL库的版本:1
2objdump -T <path to TLS/SSL libs>/libssl.so.1*
objdump -T <path to TLS/SSL libs>/libcrypto.so.1*
上述方法,既不准确,也不完善,仅供参考
MongoDB on Windows
感兴趣的可以参考这里
MongoDB on Virtual Environments
EC2
MongoDB兼容EC2,MongoDB Cloud Manager可以部署在AWS上,然后可以使用MongoDB Cloud Manager在EC2上部署mongod实例,详情参考Configure AWS Integration
Azure
VMWare
MongoDB兼容VMWare
VMWare支持内存过载,所以可以给虚拟机分配超出物理机实际内存大小的内存值。当内存过载时,管理程序会给虚拟机重新分配内存。VMWare balloon driver (vmmemctl)会自动回收它认为最没有价值的内存,balloon driver运行在虚拟机中,当balloon driver扩大时,会导致虚拟机回收应用的内存,这个会影响MongoDB的内存管理,影响MongoDB的内存
可以通过关闭balloon driver和VMWare的内存过载功能来避免上述问题。但是,关闭balloon driver会导致管理程序使用交换分区,因为没有其他的能够用来执行内存回收的机制。从swap读写数据要比从内存慢得多,这也会影响性能。因此关闭balloon driver和VMWare的内存过载功能不是最佳方案,最佳方案是给运行MongoDB的虚拟机分配全部内存,这样就能保证MongoDB不会被影响
使用VMWare的时候,确保每个物理CPU虚拟出来的CPU数量不超过2
使用vMotion关闭VMWare的(动态迁移)。虚拟机的动态迁移会导致性能问题,而且会影响MongoDB副本集和分片集群机制
可以克隆一个正在运行着MongoDB的虚拟机,也就是说可以使用这种方式快速的把一个MongoDB单点做成一个副本集。如果克隆一个开启了journaling的MongoDB的VM,直接克隆就能MongoDB就能启动。如果MongoDB没有开启,先关闭MongoDB,然后克隆VM,然后重启MongoDB
KVM
MongoDB兼容KVM
KVM支持内存过载,所以可以给虚拟机分配超出物理机实际内存大小的内存值。当内存过载时,管理程序会给虚拟机重新分配内存。KVM balloon driver (vmmemctl)会自动回收它认为最没有价值的内存,balloon driver运行在虚拟机中,当balloon driver扩大时,会导致虚拟机回收应用的内存,这个会影响MongoDB的内存管理,影响MongoDB的内存
可以通过关闭balloon driver和KVM的内存过载功能来避免上述问题。但是,关闭balloon driver会导致管理程序使用交换分区,因为没有其他的能够用来执行内存回收的机制。从swap读写数据要比从内存慢得多,这也会影响性能。因此关闭balloon driver和KVM的内存过载功能不是最佳方案,最佳方案是给运行MongoDB的虚拟机分配全部内存,这样就能保证MongoDB不会被影响
使用KVM的时候,确保每个物理CPU虚拟出来的CPU数量不超过2
性能监控
iostat
在Linux系统中,可以使用iostat去检查数据库是否存在磁盘io瓶颈
1 | iostat -xmt 1 |
iostat关键字段:
- %util: 这个字段价值最大,它代表了当前指定时间磁盘使用百分比
- avgrq-sz: 平均请求大小,这个数值越小表示有越多的random IO
bwm-ng
这是个监控网络状态的命令行工具,可以用来确认是否存在网络瓶颈
Backups
数据备份请参考这里
其他参考链接
- Blog Post: Capacity Planning and Hardware Provisioning for MongoDB In Ten Minutes
- Whitepaper: MongoDB Multi-Data Center Deployments
- Whitepaper: Security Architecture
- Whitepaper: MongoDB Architecture Guide
- Presentation: MongoDB Administration 101
- MongoDB Production Readiness Consulting Package