存储引擎是MongoDB中负责管理数据的的主要组件,负责管理数据在内存和磁盘上的存储方式。MongoDB支持多个存储引擎,因为不同的引擎可以更好地执行特定工作负载,允许用户选择最合适的存储引擎。
journal是一个日志,可以在硬件关机时帮助数据库恢复。 有几个可配置选项允许日志在性能和可靠性之间取得平衡,适用于特定用例。
GridFS是一种多功能存储系统,适用于处理大型文件,例如超过16 MB文档大小限制的文件。
自3.2版本后WiredTiger成为了默认的存储引擎,如果不用 --storageEngine
或者 storage.engine
指定使用那种引擎,则MongoDB会自动选择创建文件时使用的存储引擎。
WiredTiger使用文档级并发控制进行写操作。 因此,多个客户端可以同时修改集合的不同文档。
对于大多数读写操作,WiredTiger使用乐观并发控制。 WiredTiger仅在全局,数据库和集合级别使用锁。 当存储引擎检测到两个操作之间的冲突时,会发生写入冲突,导致MongoDB透明地重试该操作。
一些全局操作(通常是涉及多个数据库的短期操作)仍然需要全局“实例范围”锁定。 其他一些操作(例如删除集合)仍需要独占数据库锁。
WiredTiger使用MultiVersion并发控制(MVCC)。在操作开始时,WiredTiger为事务提供数据的时间点快照。快照显示内存中数据的一致视图。
写入磁盘时,WiredTiger会以相同的方式将快照中的所有数据写入磁盘,并覆盖所有数据文件。当前持久化的数据充当数据文件中的检查点
。检查点确保数据文件一致,而且保留最后一个检查点,即检查点可以作为恢复点
。
版本3.6中更改:MongoDB配置WiredTiger以60秒
的间隔创建检查点(即将快照数据写入磁盘)。
在写入新检查点期间,先前的检查点仍然有效
。因此,即使MongoDB在写入新检查点时终止或遇到错误,在重新启动时,MongoDB也可以从最后一个有效检查点恢复。
当WiredTiger的元数据表以原子方式更新并引用新检查点时,新检查点变为可访问且永久的。一旦可以访问新检查点,WiredTiger就会从旧检查点释放
页面。
使用WiredTiger,即使没有日志记录,MongoDB也可以从最后一个检查点恢复;但是,要恢复在最后一个检查点之后所做的更改,请使用日记功能运行。
从MongoDB 4.0开始,已经不能为使用WiredTiger存储引擎的副本集成员指定
--nojournal
选项或storage.journal.enabled:false
。
WiredTiger将预写事务日志与检查点结合使用以确保数据持久性。
WiredTiger日志会在检查点之间
保留所有数据修改。如果MongoDB在2个检查点之间退出,它将使用日志来重复自上一个检查点以来修改的所有数据
。
使用snappy
压缩库压缩WiredTiger日志。要指定备用压缩算法或不指定压缩,请使用storage.wiredTiger.engineConfig.journalCompressor设置。
注意
WiredTiger的最小日志记录大小为128字节。如果日志记录是128字节或更小,WiredTiger不会压缩该记录。
可以通过将storage.journal.enabled设置为false来禁用独立实例的日记功能,这可以减少维护日志的开销。对于独立实例,不使用日志意味着,当MongoDB意外退出时,将丢失最后一个检查点之前的所有数据修改。
通过WiredTiger,MongoDB支持对所有集合和索引进行压缩。压缩可以最大限度地减少对内存使用,代价时增加了CPU的使用。
默认情况下,WiredTiger对所有集合使用块压缩
和snappy
压缩库,对所有索引使用前缀压缩
。
对于集合,还可以使用zlib
进行块压缩。要指定备用压缩算法或不指定压缩,请使用storage.wiredTiger.collectionConfig.blockCompressor设置。
默认情况下,WiredTiger对所有集合使用Snappy块压缩,对所有索引使用前缀压缩。压缩默认值可在全局级别配置,也可在集合和索引创建期间基于每个集合和每个索引进行设置。
WiredTiger日志也默认进行压缩。
使用WiredTiger,MongoDB同时使用WiredTiger内部缓存和文件系统缓存。
从3.4开始,WiredTiger内部缓存默认使用较大的一个:
例如,在总共4GB RAM的系统上,WiredTiger缓存将使用1.5GB的RAM(0.5 *(4 GB - 1 GB)= 1.5 GB)。相反,一个总共1.25 GB RAM的系统将为WiredTiger缓存分配256 MB,因为这超过总RAM减去1 GB的一半(0.5 *(1.25 GB - 1 GB)= 128 MB <256 MB) 。
WiredTiger内部缓存中的数据与在磁盘中的格式有不同的表示形式:
通过文件系统缓存,MongoDB自动使用WiredTiger缓存或其他进程未使用的所有可用内存。要调整WiredTiger内部缓存的大小,请参阅storage.wiredTiger.engineConfig.cacheSizeGB和–wiredTigerCacheSizeGB。避免将WiredTiger内部缓存大小增加到其默认值以上。
从MongoDB企业版3.2.6开始,内存存储引擎在64位的版本中正式发布。与其它元数据和诊断数据不同内存存储引擎不维护任何磁盘中的数据,包括配置数据,索引,用户认证信息等。
通过避免磁盘I/O,内存存储引擎提供了数据库操作更大的可预测延迟。
为了选择内存存储引擎,指定:
--storageEngine
option, or the storage.engine setting if using a configuration file.例如,从命令行:
mongod --storageEngine inMemory --dbpath
或者,如果使用 YAML configuration file format:
storage:
engine: inMemory
dbPath:
WARNING
在进程结束之后,内存存储引擎并不会持久化数据。
内存存储引擎对写操作使用 document-level 并发控制。因此,多个客户端可以同时修改同一个集合的不同文档。
内存存储引擎要求所有数据(如果 mongod 实例是复制集的一个部分,包括索引,日志等)必须能够容纳于 --inMemorySizeGB 命令行选项 或者 YAML configuration file 中 storage.inMemory.engineConfig.inMemorySizeGB 配置中指定的大小中。
默认地,内存存储引擎使用物理内存减去1GB后的50%内存。
如果一个写操作将会造成数据超出特定的内存大小,MongoDB返回以下错误:"WT_CACHE_FULL: operation would overflow cache"
在 YAML configuration file format 中设置:setting:
storage.inMemory.engineConfig.inMemorySizeGB 来指定一个新的大小:
storage:
engine: inMemory
dbPath:
inMemory:
engineConfig:
inMemorySizeGB:
或者使用命令行选项 --inMemorySizeGB:
mongod --storageEngine inMemory --dbpath --inMemorySizeGB
内存存储引擎是非持久化的,因此不会将数据写到一个持久化的存储中。也就是说,非持久化的数据包括应用数据以及系统数据,例如用户、权限、索引、复制集配置、分片集群配置等。因此, journal 的概念或者是等待数据变成 durable 并不适用于内存存储引擎。
多文档事务不适用于具有使用内存存储引擎的成员的部署
除了单机运行,使用内存存储引擎的 mongod 实例可以作为一个复制集或者分片集群的一个部分运行。
可以将使用内存存储引擎的 mongod 实例作为复制集的一个部分进行部署。例如,作为一个三成员复制集的一个部分,您可以有:
通过使用这种部署模型,只有运行着内存存储引擎
的 mongod 实例可能变成主节点。客户端只会连接到内存存储引擎的 mongod 实例。即使两台运行着内存存储引擎的 mongod 实例同时崩溃重启,它们也可以从运行着WiredTiger的成员中进行同步。运行着WiredTiger的隐藏 mongod 实例将数据持久化
到磁盘,包括用户数据、索引以及复制集配置。
内存存储引擎要求所有数据(如果 mongod 实例是复制集的一个部分,包括索引,日志等)必须能够容纳于 --inMemorySizeGB 命令行选项 或者 YAML configuration file 中 storage.inMemory.engineConfig.inMemorySizeGB 配置中指定的大小中。
可以将使用内存存储引擎的 mongod 实例部署为分片集群的一个部分。例如,在分片集群中,可以配置一个分片,由以下复制集组成:
向该分片中添加 tag inmem 。例如,如果该分片的名字为 shardC ,连接到 mongos ,然后运行 sh.addShardTag() 。
例如,
sh.addShardTag("shardC", "inmem")
对于其他分片,增加一个单独的标签 persisted 。
sh.addShardTag("shardA", "persisted")
sh.addShardTag("shardB", "persisted")
对应该位于 inmem 分片的每个分片集合, assign to the entire chunk range 标签 inmem :
sh.addTagRange("test.analytics", { shardKey: MinKey }, { shardKey: MaxKey }, "inmem")
对应该位于 persisted 分片的每个分片集合, 将标记inmem分配给整个块范围:
sh.addTagRange("salesdb.orders", { shardKey: MinKey }, { shardKey: MaxKey }, "persisted")
对于 inmen 分片,创建一个数据库或将其移动数据库。
为了在发生故障时提供持久性,MongoDB使用写入日志记录到磁盘日志文件。
WiredTiger会使用检查点来恢复数据,如果MongoDB在检查点之间意外退出,则需要使用日记功能来恢复在上一个检查点之后发生的信息。
在4.0版本后,使用WiredTiger引擎后就无法使用 --nojournal 或者storage.journal.enabled: false
使用Journaling进行恢复数据
的过程:
对于日志文件,MongoDB在dbPath目录下创建一个名为journal的子目录。 WiredTiger日志文件的名称格式为WiredTigerLog.
其中sequence是从0000000001开始的零填充数字。
日志文件包含每个写操作
的记录,每条记录都有唯一的标识符。
MongoDB将WiredTiger配置为对日记数据使用snappy压缩。
WiredTiger的最小日志记录大小为128字节。 如果日志记录是128字节或更小,WiredTiger不会压缩该记录。
MongoDB的WiredTiger日志文件的最大大小限制大约为100 MB。 一旦文件超过该限制,WiredTiger就会创建一个新的日志文件。
WiredTiger会自动删除
旧的日志文件,仅维护从上一个检查点恢复所需的文件。
WiredTiger将预先分配
日志文件。
由于其数据保存在内存中,因此没有单独的日志。 写入关注j:true
的写操作立即被确认。
如果副本集的任何投票成员使用内存存储引擎,则必须将writeConcernMajorityJournalDefault设置为false。
将writeConcernMajorityJournalDefault设置为false时,在确认写入之前MongoDB不会等待w: "majority"
被写入磁盘日志。 这样,在给定副本集中的大多数节点的瞬时丢失(例如,崩溃和重启)的情况下,大多数写操作可能会回滚。
GridFS是用于存储和检索超过BSON文档大小限制(16 MB
)的文件,如:图片、音频、视频等的规范。GridFS 也是文件存储的一种方式,但是它是存储在MonoDB的集合中。
GridFS 会将大文件对象分割成多个小的chunk
(文件片段),一般为256k/个,每个chunk将作为MongoDB的一个文档(document)被存储在chunks
集合中。
GridFS 用两个集合来存储一个文件:fs.files
与fs.chunks
。
每个文件的实际内容被存在chunks(二进制数据)中,和文件有关的meta数据(filename,content_type,还有用户自定义的属性)将会被存在files集合中。
chunk集合中的每个文档代表GridFS中表示的文件的不同块。 此集合中的文档具有以下形式:
{
"_id" : ,
"files_id" : ,
"n" : ,
"data" :
}
files集合的每个文档代表GridFS中的一个文件:
{
"_id" : ,
"length" : ,
"chunkSize" : ,
"uploadDate" : ,
"md5" : ,
"filename" : ,
"contentType" : ,
"aliases" : ,
"metadata" : ,
}
files._id
The unique identifier for this document. The _id is of the data type you chose for the original document. The default type for MongoDB documents is BSON ObjectId.
files.length
文件长度,字节
files.chunkSize
指定每个chunk块的大小(字节),除了最后一块,默认255KB
files.uploadDate
The date the document was first stored by GridFS. This value has the Date type.
files.md5
An MD5 hash of the complete file returned by the filemd5 command. This value has the String type.
files.filename
Optional. A human-readable name for the GridFS file.
files.contentType
Optional. A valid MIME type for the GridFS file.
files.aliases
Optional. An array of alias strings.
files.metadata
可选的。 元数据字段可以是任何数据类型,并且可以包含您要存储的任何其他信息。 如果要向文件集合中的文档添加其他任意字段,请将它们添加到元数据字段中的对象。
三个基本命令:put(存储) get(取得) list(列表)
先将文件压缩, 使用-d
指定数据库
ulysses@ulysses:~$ tar -czvf TCP_IP.tar.gz Documents/图解TCP_IP_第5版.pdf
Documents/图解TCP_IP_第5版.pdf
ulysses@ulysses:~$ mongofiles -d first_demo put TCP_IP.tar.gz
2018-12-06T11:05:08.087+0800 connected to: localhost
2018-12-06T11:05:08.532+0800 added file: TCP_IP.tar.gz
使用list和search查看文件
ulysses@ulysses:~$ mongofiles -d first_demo list
2018-12-06T11:40:40.536+0800 connected to: localhost
TCP_IP.tar.gz 32202865
ulysses@ulysses:~$ mongofiles -d first_demo search TCP
2018-12-06T11:40:50.291+0800 connected to: localhost
TCP_IP.tar.gz 32202865
进入数据库后查看集合,多了fs.chunks和fs.files:
> use first_demo;
switched to db first_demo
> show tables
fs.chunks
fs.files
myresult
myresult_1
orders
profile
sites
查看fs.files:
> db.fs.files.find()
{ "_id" : ObjectId("5c0891e46a39c24a825b3d28"), "chunkSize" : 261120, "uploadDate" : ISODate("2018-12-06T03:05:08.536Z"), "length" : 32202865, "md5" : "ebafc54d2da56a5b3745fa96cb4240f3", "filename" : "TCP_IP.tar.gz" }
使用files的 _id 获取区块(chunk)的数据
db.fs.chunks.find({files_id:ObjectId("5c0891e46a39c24a825b3d28")})
尝试从MongoDB中获取文件
ulysses@ulysses:~$ mongofiles -d first_demo get TCP_IP.tar.gz
2018-12-06T11:38:34.518+0800 connected to: localhost
2018-12-06T11:38:34.761+0800 finished writing to TCP_IP.tar.gz
删除大文件
ulysses@ulysses:~$ mongofiles -d first_demo delete TCP_IP.tar.gz
2018-12-06T11:42:38.809+0800 connected to: localhost
2018-12-06T11:42:38.896+0800 successfully deleted all instances of 'TCP_IP.tar.gz' from GridFS
ulysses@ulysses:~$ mongofiles -d first_demo list
2018-12-06T11:42:43.716+0800 connected to: localhost
...
> show tables
fs.chunks
fs.files
myresult
myresult_1
orders
profile
sites
> db.fs.files.find()
> db.fs.chunks.find()
from pymongo import MongoClient
from gridfs import GridFS
import base64
db = MongoClient().first_demo
fs = GridFS(db)
print(fs.list())
if not fs.exists({"filename": 'timg.jpg'}):
with open('/home/ulysses/Pictures/timg.jpg', 'rb') as f:
kw = {'filename': 'timg.jpg'}
fs.put(f, **kw)
else:
cursor = fs.find({"filename": 'timg.jpg'}, no_cursor_timeout=True)
for grid_out in cursor:
data = grid_out.read()
print(data)
执行结果
(venv) ulysses@ulysses:~/PycharmProjects/test_base$ python -m demo.mongo_demo.gridfs
['timg.jpg']
b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x01\x00H\x00H\x00\x00\xff\xdb\x00C\x00\x0c\x08\t\n\t\x07\x0c\n\t\n\r\x0c\x0c\x0e\x11\x1d\x13\x11\x10\x10\x11#\x19\x1b\x15\x1d*%,+)%((.4B8.1?2((:N:?DGJKJ-7QWQHVBIJG\xff\xdb\x00C\x01\x0c\r\r\x11\x0f\x11"\x13\x13"G0(0GGGGG
删除:
else:
cursor = fs.find({"filename": 'timg.jpg'}, no_cursor_timeout=True)
for grid_out in cursor:
data = grid_out.read()
print(data)
fs.delete(grid_out._id)
在Mongodb中我们使用mongodump
命令来备份MongoDB数据。该命令可以导出所有数据到指定目录中。
mongodump命令可以通过参数指定导出的数据量级转存的服务器。
mongodump -h dbhost -d dbname -o dbdirectory
-h:
MongDB所在服务器地址,例如:127.0.0.1,当然也可以指定端口号:127.0.0.1:27017
-d:
需要备份的数据库实例,例如:test
-o:
备份的数据存放位置,例如:c:\data\dump,当然该目录需要提前建立,在备份完成后,系统自动在dump目录下建立一个test目录,这个目录里面存放该数据库实例的备份数据。
实例:
ulysses@ulysses:~$ mongodump -d first_demo -o /home/mongodb/backup
2018-12-05T10:51:31.391+0800 writing first_demo.sites to
2018-12-05T10:51:31.394+0800 writing first_demo.profile to
2018-12-05T10:51:31.394+0800 writing first_demo.orders to
2018-12-05T10:51:31.395+0800 writing first_demo.myresult to
2018-12-05T10:51:31.448+0800 done dumping first_demo.profile (8 documents)
2018-12-05T10:51:31.448+0800 writing first_demo.myresult_1 to
2018-12-05T10:51:31.448+0800 done dumping first_demo.orders (4 documents)
2018-12-05T10:51:31.458+0800 done dumping first_demo.sites (19 documents)
2018-12-05T10:51:31.473+0800 done dumping first_demo.myresult_1 (2 documents)
2018-12-05T10:51:31.473+0800 done dumping first_demo.myresult (2 documents)
若不指定要备份的数据库,则会备份整个服务器数据;也可以使用mongodump --collection COLLECTION --db DB_NAME
命令指定要备份的集合
mongodb使用 mongorestore 命令来恢复备份的数据。语法:
mongorestore -h
–host <:port>, -h <:port>:
MongoDB所在服务器地址,默认为: localhost:27017
–db , -d :
需要恢复的数据库实例,例如:test,当然这个名称也可以和备份时候的不一样,比如test2
–drop:
恢复的时候,先删除当前
数据,然后恢复备份的数据。就是说,恢复后,备份后添加修改的数据都会被删除,慎用哦!
path, --dir::
mongorestore 最后的一个参数,设置备份数据所在位置,
不能同时指定 path和 --dir 选项,–dir也可以设置备份目录。
实例:
ulysses@ulysses:~$ mongorestore -d first_demo /home/mongodb/backup/first_demo
2018-12-05T11:00:45.779+0800 the --db and --collection args should only be used when restoring from a BSON file. Other uses are deprecated and will not exist in the future; use --nsInclude instead
2018-12-05T11:00:45.779+0800 building a list of collections to restore from /home/mongodb/backup/first_demo dir
2018-12-05T11:00:45.780+0800 reading metadata for first_demo.sites from /home/mongodb/backup/first_demo/sites.metadata.json
2018-12-05T11:00:45.780+0800 reading metadata for first_demo.profile from /home/mongodb/backup/first_demo/profile.metadata.json
...