最近在看一本书:《MongoDB: The Definitive Guide》,对此书有兴趣的朋友可以留下您的邮箱.
下面是MongoDB Internals部分章节的翻译,想看原文,请留下邮箱,哈哈
在很多场合下,数据库被当成黑盒来使用,MongoDB也不例外.但是作为DBA,或者是想要更加深入的了解它的人来说,了解MongoDB的一些内部知识是有帮助的.
1. BSON (Binary JSON)
Documents在MongoDB中属于抽象概念(无形概念),Document有形的表述取决于使用的驱动或语言.目前MongoDB服务端使用BSON存储Documents.
BSON是一个轻量级的二进制存储格式,可以存储任意MongoDB document as a string of bytes.Document以BSON的格式存储于磁盘.
When a driver is given a document to insert, use as a query, and so on, it will encode
that document to BSON before sending it to the server. Likewise, documents being
returned to the client from the server are sent as BSON strings. This BSON data is
decoded by the driver to its native document representation before being returned to
the client.
驱动的作用类似Server和Client通信的翻译.
BSON的三个特点:
效率:
不需要占用过多额外空间,与JSON比较,BSON效率非常高(如,存储binary data或large numerics数据类型时),最恶劣的情况下BSON比JSON效率略低.
性能 :
BSON使用C-style表述类型,在大多数编程语言中使用encode,decode操作都比较迅速.
Traversability :
In some cases, BSON does sacrifice space efficiency to make the format easier to
traverse. For example, string values are prefixed with a length rather than relying
on a terminator to signify the end of a string. This traversability is useful when the
MongoDB server needs to introspect documents.
2. Wire Protocol
当Driver连接到MongoDB Server时使用轻量级的TCP/IP wire protocol.
The Mongo Wire Protocol is a simple socket-based, request-response style protocol. Clients communicate with the database server through a regular TCP/IP socket.
详细文档参考:
http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-TableOfContents
3. Data Files
在MongoDB中,每个库都有自己的数据文件,如下:
[mongo@db6 ~]$ cd mongodb/data1/
[mongo@db6 data1]$ ll
total 24
drwxr-xr-x 2 root root 4096 Dec 2 16:42 admin
drwxr-xr-x 2 root root 4096 Dec 3 16:47 digoal
-rwxrwxr-x 1 mongo mongo 5 Dec 3 16:11 mongod.lock
drwxr-xr-x 2 root root 4096 Dec 3 16:29 test
drwxr-xr-x 2 root root 4096 Dec 4 13:55 _tmp
drwxr-xr-x 2 root root 4096 Dec 2 16:47 wapprepaid
[mongo@db6 data1]$ cd test
[mongo@db6 test]$ ll -h
total 38G
-rw------- 1 root root 64M Dec 3 09:18 test.0
-rw------- 1 root root 128M Dec 3 09:18 test.1
-rw------- 1 root root 2.0G Dec 3 10:03 test.10
-rw------- 1 root root 2.0G Dec 3 10:12 test.11
-rw------- 1 root root 2.0G Dec 3 10:14 test.12
-rw------- 1 root root 2.0G Dec 3 10:23 test.13
-rw------- 1 root root 2.0G Dec 3 10:25 test.14
-rw------- 1 root root 2.0G Dec 3 10:37 test.15
-rw------- 1 root root 2.0G Dec 3 10:41 test.16
-rw------- 1 root root 2.0G Dec 3 12:29 test.17
-rw------- 1 root root 2.0G Dec 3 12:46 test.18
-rw------- 1 root root 2.0G Dec 3 12:57 test.19
-rw------- 1 root root 256M Dec 3 09:19 test.2
-rw------- 1 root root 2.0G Dec 3 16:17 test.20
-rw------- 1 root root 2.0G Dec 3 16:23 test.21
-rw------- 1 root root 2.0G Dec 3 16:29 test.22
-rw------- 1 root root 512M Dec 3 09:20 test.3
-rw------- 1 root root 1.0G Dec 3 09:22 test.4
-rw------- 1 root root 2.0G Dec 3 09:24 test.5
-rw------- 1 root root 2.0G Dec 3 09:28 test.6
-rw------- 1 root root 2.0G Dec 3 09:35 test.7
-rw------- 1 root root 2.0G Dec 3 09:44 test.8
-rw------- 1 root root 2.0G Dec 3 09:55 test.9
-rw------- 1 root root 16M Dec 3 09:18 test.ns
该数据库的启动参数如下:
-r-------- 1 mongo mongo 168 Dec 3 09:02 mongodb.cfg
[mongo@db6 conf]$ cat mongodb.cfg
port=5281
fork=true
logpath=/var/log/mongo/mongodb.log
logappend=true
dbpath=/home/mongo/mongodb/data1
directoryperdb=true
auth=true
maxConns=1000
nohttpinterface=true
# 查看库,
[mongo@db6 conf]$ /opt/mongodb-linux-x86_64-1.6.4/bin/mongo 127.0.0.1:5281/admin
MongoDB shell version: 1.6.4
connecting to: 127.0.0.1:5281/admin
> db.auth("digoal","DIGOAL")
1
> show dbs
admin
digoal
local
test
wapprepaid
可以看出每个库有自己的目录.
由于默认情况下是开启prealloc,所以文件是预先指派的,指派大小从最初的test.0 64MB开始成倍递增.
test.1 128MB
test.2 256MB
test.3 512MB
test.4 1024MB
test.5 2G
到2G后面数据文件单个大小就不再变化.这么搞的好处是小库不会浪费太多空间,大库的话又可以做到数据文件尽量保持在磁盘上的连续存储。
预指派的好处:保持数据文件在磁盘存储连续,避免当需要是才做文件指派时的性能下降。
4. Namespaces and extents
Namespace在MongoDB中代表一个完整的对象描述,如
> use test
switched to db test
> db.auth("digoal","DIGOAL")
1
> show collections
blog.posts
system.indexes
system.users
tbl
tbl1
tbl2
tbl3
tbl4
tbl_test
test.blog.posts
test.blog
test.system
test.system.indexes 等等 这些都属于namespaces.
extents是在数据文件中的概念,namespaces以extents的形式存储在数据文件中.如图
从这个图上来看,foo.0,foo.1文件被指派了extents,foo.2是预指派产生的数据文件,目前还没有使用.
foo.$freelist是一个特殊的namespace,用作跟踪空余的EXTENTS,(如drop collection或index后,extent被释放),当某个NAMESPACE需要新的extents时,首先查找FREELIST是否有合适大小的extents。
5. Memory-Mapped Storage Engine
目前MongoDB默认的存储引擎,Memory-Mapped Storage Engine.当数据库启动的时候,Memory map所有数据文件.之后的话 flushing data to disk and paging out and in 就交给操作系统来管理了.
Memory-Mapped 存储引擎有以下重要属性:
5.1 由于大多数内存管理的工作推到了OS端,MongoDB关于内存管理这一方面的代码比较精简.
5.2 MongoDB数据库的虚拟大小可能会超过数据库物理SIZE,That's OK,不用担心,这些操作已经交给OS处理了。
5.3 MongoDB不能控制数据写入磁盘的顺序,所以就不可能通过记录WriteAhead Log 来确保单台服务器情况下数据库的持久化。从MongoDB http://www.mongodb.org/display/DOCS/Durability+and+Repair 上面了解到,
The v1.8 release of MongoDB will have single server durability. You can follow the Jira here : http://jira.mongodb.org/browse/SERVER-980. Specifically, in v1.8, journaling will be added to the storage engine.
We recommend using replication to keep copies of data for now – and likely forever – as a single server could fail catastrophically regardless.
V1.8版本在存储引擎中增加了JOURNAL的记录,可以提供单服务器数据库持久化。
不过MongoDB推荐使用多台服务器的数据多份拷贝来做数据库持久化.
5.4 在32位的操作系统中,由于寻址的关系,每个mongod,MongoDB 只能存储2GB的数据。所以建议使用64位操作系统.