爱吱声

标题: MongoDB架构概览 [打印本页]

作者: shengnan007    时间: 2012-9-18 12:31
标题: MongoDB架构概览
    关于MongoDB,我们能看到的资料,基本都是在指导大家如何使用MongoDB,但是,MongoDB内部是如何运作的,资料不是很多。
+ Z4 J+ Q' R: k  l: g, |- w' I5 H$ g+ I3 P
    阅读使用手册,会有很多疑惑之处。例如,有人说,MongoDB 等同于分布式的 MySQL。它把一个Table ,按 row,分割成多个Shards,分别存放在不同的 Servers 上。这种说法是否正确?7 Y6 G1 T+ V& J5 d1 s0 R8 S! L
( H: ]! N" }- S
    不深入了解 MongoDB 的内部结构,就无法透彻地回答类似问题。这个系列文章,就来和大家探讨MongoDB的内部的工作方式。
, ~5 f0 k1 X$ \0 M! ~2 Y* {! V" J4 a, i# i  Z0 F1 Q9 w- }# A9 [

8 ], R$ s% \) |; h
6 p+ u# @: b1 n8 B$ l图1-1 MongoDB架构图
& [. g/ D; _& J2 v; m. d" D
# t0 P0 W/ v" R% H4 c5 y6 M" N+ {
    MongoDB 通常运行在一个服务器集群上,而不是一个单机。图1-1,描述了一个MongoDB集群的基本组成部分,包括若干shards,至少一个config server,至少一个routing servers(又称 mongos)。- l9 @0 r* r  D5 g$ E
% B% X6 R! e: R0 n# E% R/ ]' \
Shards8 A4 M! r! v% P

2 X0 a) \5 h  Q; H& a) v0 L    MongoDB的最基本的数据单元,叫document,类似于关系式数据库中的行 row。一系列documents,组成了一个collection,相当于关系式数据库中的table。当一个 collection 数据量太大时,可以把该collection按documents切分,分成多个数据块,每个数据块叫做一个chunk,多个chunks聚集在一起,组成了一个shard。* d6 A. `. X. ?7 j9 ?
, D9 F: b( Y$ J/ Q  K/ ~
    Sharding 的意义,不仅保障了数据库的扩容(scalability),同时也保障了系统的负载均衡(load balance)。) X$ m, G; V  H

7 m$ `* M# f2 i5 Y    每一个shard存储在一个物理服务器(server)上。Server上运行着mongod进程,通过这个进程,对shard中的数据进行操作,主要是增删改查。% A1 v  u. w& `0 n; F4 W
$ r1 E8 t4 c! C8 n
    如果系统中的每个shard,只存储了一份数据,没有备份,那么当这个shard所在的server挂了,数据就丢失了。在生产环境中,为了保证数据不丢失,为了提高系统的可用性(availability),每一个shard被存储多份,每个备份所在的servers,组成了一个replica set。
. n) r/ Z: p  ?/ x4 S
& e+ M. e* {$ M& {# qShard keys
1 ^5 b$ t: W3 l: V5 P        
  L! j1 x" E  s" c( w    为了把collection切分成不同的chunks,从而存放到不同的shards中,我们需要制定一个切分的方式。
7 w, q( x& h! M2 }! w  h" X
8 X/ T8 L/ q3 b9 F    如前所述,在 MongoDB 数据库中,一个表collection由多个行 documents 组成,而每个 document,有多个属性 fields。同一个 collection 中的不同的 documents,可能会有不同的 fields。例如,有个 collection 叫 Media,包含两条 documents,5 }/ e$ ]! W) u% j7 ]- B5 q9 o

, W' v. e; ]3 j! d& N: N- u{' ^' X6 D$ r4 N
  "ISBN": "987-30-3652-5130-82",
* C* V  }5 w8 k+ d' F  "Type": "CD",3 \& k# C3 ^) W* w  M, c
  "Author": "Nirvana",; F$ ^& [) y) ^0 ], _
  "Title": "Nevermind",
5 ?' Y8 V1 x7 K  v. A  "Genre": "Grunge"," a4 x/ N) V, L
   "Releasedate": "1991.09.24",
9 H4 t3 {. a3 |7 I( c1 \1 u2 `   "Tracklist": [
+ u5 ~) S4 [0 g$ c% y8 K     {3 X& d/ u8 U& |3 V/ G: s9 o( k
        "Track" : "1",2 ]0 }; }" g: D  P) Q9 e8 C% S
        "Title" : "Smells like teen spirit",
1 n1 A2 h7 W1 M  @4 \! f        "Length" : "5:02"+ a$ Z1 U  X8 M  l
     },1 b" @" ^) ?7 k# O
     {8 i3 Q2 y" d/ |5 X
        "Track" : "2",8 l: i0 i2 l6 c/ P7 F6 F7 P! q% r
        "Title" : "In Bloom",
3 p' I. @1 Q) {        "Length" : "4:15"
8 K* [  V; U  r1 r, P8 R' ~, n9 |     }2 S  D) `  C$ U8 s
   ]
: B& n" b- o  J% }}
) J5 S% U! k- t" ?. H, w$ j" R- [  w1 H( |7 j& D4 P
{
1 r" ~% L9 t( q  "ISBN": "987-1-4302-3051-9",
& [+ I" s3 c, M: n  "Type": "Book",3 u+ [+ q" _) ?( y6 u8 }/ X; ^3 W* y
  "Title": "Definite Guide to MongoDB: The NoSQL Database",
* v6 L. [5 V) \0 c8 t2 b8 R  "Publisher": "Apress",
$ m$ j5 k" z3 N8 w' G& E" w  "Author": " Eelco Plugge",
8 l1 T0 q4 n4 ~/ w; a9 d  "Releasedate": "2011.06.09"
" Q" E* a& T) s0 |4 H/ N! I}8 R7 w. k: b/ d$ u! U

; @0 m) H% f$ B    假如,在同一个 collection 中的所有 document,都包含某个共同的 field,例如前例中的“ISBN”,那么我们就可以按照这个 field 的值,来分割 collection。这个 field 的值,又称为 shard key。
0 R9 g+ z8 x9 P6 O' S7 }3 B) Q
; `8 q: Z5 S) D    在选择shard key的时候,一定要确保这个key能够把collection均匀地切分成很多chunks。
2 z: F! u% `% J7 D9 M0 n+ y2 \# l4 J$ O, N% c
    例如,如果我们选择“author”作为shard key,如果有大量的作者是重名的,那么就会有大量的数据聚集在同一个chunk中。当然,假设很少有作者同名同姓,那么“author”也可以作为一个shard key。换句话说,shard key 的选择,与使用场景密切相关。
# e+ U* o# E) a0 z) h# b
; k$ S3 \5 ~4 Y    很多情况下,无论选择哪一个单一的 field 作为shard key,都无法均匀分割 collection。在这种情况下,我们可以考虑,用多个 fields,构成一个复合的shard key。
' u; g5 X5 z" i. Q0 \. j2 Y1 _7 p
    延续前例,假如有很多作者同名同姓,他们都叫“王二”。用 author 作为 shard key,显然无法均匀切割 collection。这时我们可以加上release-date,组成name-date的复合 shard key,例如“王二 2011”。
$ Z9 K  [6 ~3 S  f8 `# H# _& |- Y, m
Chunks
# O6 F/ x: k, M1 E4 J) E        % Q5 H9 Q4 E; ?; x7 Q7 q; L
    MongoDB按 shard key,把 collection切割成若干 chunks。每个 chunk 的数据结构,是一个三元组,{collection,minKey,maxKey},如图1-2 所示。9 z* {8 G0 Z2 a( T! z, _

5 ~- i7 p' H5 n# N: w& u( w" h
' x, N; ~6 a, i" I( `4 X. c
图1-2 chunk的三元组
$ |: G& `1 j. ~( b7 g5 R8 F- ]

8 x8 u- T9 L  r" U1 m4 J    其中,collection 是数据库中某一个表的名称,而 minKey 和 maxKey 是 shard key的范围。每一个 document 的shard key 的值,决定了这条document应该存放在哪个chunk中。. A. c+ r% @" f+ c
/ G3 d+ ?6 x4 j
    如果两条 documents 的 shard keys 的值很接近,这两条 documents 很可能被存放在同一个 chunk 中。
$ E5 {" u9 T5 N8 T( s+ m" ?/ J) {. v9 ^' G2 b, c
    Shard key 的值的顺序,决定了 document 存放的 chunk。在 MongoDB 的文献中,这种切割 collection 的方式,称为order-preserving。
; H! O- ?) T  K$ m; {# Z9 j4 U" X5 v2 o8 C
    一个 chunk最多能够存储64MB的数据。 当某个chunk存储的 documents包含的数据量,接近这个阈值时,一个chunk会被切分成两个新的chunks。7 o7 N$ W0 h3 m9 J: {- A

' W" y* G- g0 \  P# J) k/ m    当一个shard存储了过多的chunks,这个shard中的某些chunks会被迁移到其它 shard中。
) o3 D2 O# A0 |' T1 U1 F
% e: t3 k% d4 {/ B6 q6 {; C# v    这里有个问题,假如某一条 document 包含的数据量很大,超过 64MB,一个 chunk 存放不下,怎么办?在后续章节介绍 GridFS 时,我们会详细讨论。$ \4 C  f& m: x; z$ ?
' ]% b; f' c  u8 _/ \1 }- h
Replica set) t, ^. i5 H1 q; n2 V8 U" ]
        7 u$ R: a- X& j
    在生产环境中,为了保证数据不丢失,为了提高系统的可用性(availability),每一个shard被存储多份,每个备份所在的servers,组成了一个replica set。
* z# T0 K% w" X/ l  P' S$ I/ e2 v, W
    这个replica set包括一个primary DB和多个secondary DBs。为了数据的一致性,所有的修改(insert / update / deletes) 请求都交给primary处理。处理结束之后,再异步地备份到其他secondary中。
6 ?1 Y, k; b7 i; P2 j0 d
& _+ o$ v, x7 `) v+ z8 X  }, t7 K    Primary DB由replica set中的所有servers,共同选举产生。当这个primaryDB server出错的时候,可以从replica set中重新选举一个新的primaryDB,从而避免了单点故障。1 h  R& u! i2 G! O9 B! `2 u0 o4 f

. p6 Z# a4 W" o+ z    Replica set的选举策略和数据同步机制,确保了系统的数据的一致性。后文详述。. R7 W' V( V0 A9 i! a! f( h/ U+ u
) G. T, M' H' H- X' o" b
Config Server
9 N( f1 P* m" j$ _1 ?6 |        + P' F0 p, K. h4 O# ~
    Config servers用于存储MongoDB集群的元数据 metadata,这些元数据包括如下两个部分,每一个shard server包括哪些chunks,每个chunk存储了哪些 collections 的哪些 documents。
. ]" _: f3 ]8 B, K& O* U1 }! Y. @* ^/ z  A3 I7 f0 y7 K
    每一个config server都包括了MongoDB中所有chunk的信息。
# r  v: O3 Z, h9 n1 Q' _7 @* A0 @
$ E  }4 Y3 I. k% {' _6 z* w    Config server也需要 replication。但是有趣的是,config server 采用了自己独特的replication模式,而没有沿用 replica set。$ \: R* t( L: K* z" w

0 I, l! s/ {: [4 v, h    如果任何一台config server挂了,整个 config server 集群中,其它 config server变成只读状态。这样做的原因,是避免在系统不稳定的情况下,冒然对元数据做任何改动,导致在不同的 config servers 中,出现元数据不一致的情况。
2 i0 A7 \: X: C8 a  z$ F! ~; Y/ x! ]# }
    MongoDB的官方文档建议,配置3个config servers比较合适,既提供了足够的安全性,又避免了更多的config servers实例之间的数据同步,引起的元数据不一致的麻烦。
! s) a8 e- n: |! ~( i
0 H) W9 r" f) mMongos
# X2 t0 U0 i* u0 N$ N% N  n/ D7 o4 j% C
    用户使用MongoDB 时,用户的操作请求,全部由mongos来转发。
9 E2 ]. Y5 @  {6 x& \, \( ?/ d  l+ u4 h- L; X) i
    当 mongos 接收到用户请求时,它先查询 config server,找到存放相应数据的shard servers。然后把用户请求,转发到这些 shard servers。当这些 shard servers完成操作后,它们把结果分别返回给 mongos。而当 mongos 汇总了所有的结果后,它把结果返回给用户。1 C: y6 v/ J9 q" \/ {5 d

) Z, r; {# }; D3 g" f. C6 K: S    Mongos每次启动的时候,都要到config servers中读取元数据,并缓存在本地。每当 config server中的元数据有改动,它都会通知所有的mongos。
8 o+ I" C% r/ v, y( X  K& e' k% B, h( }4 Y" O3 A. n8 G+ Y
    Mongos之间,不存在彼此协同工作的问题。因此,MongoDB所需要配置的mongos server的数量,没有限制。
+ a( [" L& K, H4 y4 e
- F% o! X1 }% i# R    通过以上的介绍,我们对每个组成部分都有了基本的了解,但是涉及到工作的细节,我们尚有诸多疑问,例如,一个chunk的数据太大,如何切分?一个shard数据太多,如何迁移?在replica set中,如何选择primary?server挂了,怎么进行故障恢复?接下来的章节,我们逐个回答这些问题。3 D* F& Z) ]! e, |& l
( X, G6 k5 d5 V- A

% x+ \* l! x2 q) ~* L# R8 GReference,
; s! B$ a3 @6 A2 ~7 @! L
+ o% ?! v" y7 k+ U! \" Z+ Q[0] Architectural Overview
% S( h! q2 w* T, ^http://www.mongodb.org/display/DOCS/Sharding+Introduction
( g% }+ I$ V1 d. |' X5 |
作者: PenPen    时间: 2012-9-18 12:40
本帖最后由 PenPen 于 2012-9-18 12:44 编辑 5 [5 c4 z) [6 {$ u2 G8 N+ ^

4 G$ I8 y: H1 q
; w: {' q) u8 v您是和邓侃一起写文章的盛楠么?
作者: shengnan007    时间: 2012-9-18 12:44
呃。。。是我啊。。。
作者: shengnan007    时间: 2012-9-18 12:44
PenPen 发表于 2012-9-18 12:40 , h, D1 p& x7 i9 [2 l
您是和邓侃一起写文章的盛楠么?
- Q* d; r8 u' r0 \
是我啊。。。这都能被认出来。。。
作者: PenPen    时间: 2012-9-18 12:47
shengnan007 发表于 2012-9-18 12:44
! F7 K/ f. }& f2 N' m- q6 y5 q是我啊。。。这都能被认出来。。。

5 @3 \) d/ G5 p9 k; B' T. j4 b( u8 j这篇文章我读过。开始以为是转贴的,后来再一看id就发现真相了~
作者: shengnan007    时间: 2012-9-18 12:49
PenPen 发表于 2012-9-18 12:47
0 B9 X2 @/ S2 c8 y8 ^. Q7 m这篇文章我读过。开始以为是转贴的,后来再一看id就发现真相了~
& \7 R( W# n7 n0 ^6 C# v0 B
多谢支持。还有两篇一会帖过来。后续的还在写。边看源码边写,比较慢,hoho。这里是要推荐才能变成正式会员是么?
作者: 不爱吱声    时间: 2012-9-18 12:51
shengnan007 发表于 2012-9-17 22:49 " M4 y& m/ e) |
多谢支持。还有两篇一会帖过来。后续的还在写。边看源码边写,比较慢,hoho。这里是要推荐才能变成正式会 ...
& j3 V5 V! d( @: Z5 Z! Z3 P
欢迎,欢迎,已经给你变成正式会员了。
作者: shengnan007    时间: 2012-9-18 12:57
不爱吱声 发表于 2012-9-18 12:51
/ {7 n% P: B! f4 f" Q欢迎,欢迎,已经给你变成正式会员了。
; |+ g4 ~* u; P* g
多谢多谢啦~~
作者: 巴山    时间: 2012-9-19 03:38
我们现在的 technology stack 就是 php + mongodb,涉及财务方面的东西用 postgres。
( j5 A4 R/ e1 g" ^
0 R( d+ O3 j( M2 i8 h( i
作者: 梦晓半生    时间: 2012-9-19 04:21
谢谢。
, o; V3 E1 F! _4 x/ d
2 T/ J. ~  S5 X! C) h中文看得真累,大部分还是英文术语。# v: I# Y+ r% T3 P/ _" B* {, T" Q, m

8 }6 ^: _( R' q) b1 [这应该是一个系列吧,后面怎样寻找,执行指令等开始入门,还是说的太简单了。
- ~- \+ l8 p7 @( V* N8 P. k. n( b; D
# [% M4 R9 O8 X+ l现在distributed DB在那些大网站很重要,现在开始有跟已有DB分庭抗礼的苗头,不过不是那里工作的话,其中的奥妙大概难说清楚。
作者: shengnan007    时间: 2012-9-19 08:40
巴山 发表于 2012-9-19 03:38 : U  M2 v" f- y% }2 S
我们现在的 technology stack 就是 php + mongodb,涉及财务方面的东西用 postgres。! a7 D$ A& ]6 b
/ I6 f8 i. V; f3 r. ]+ d
...

( k- i( I! ~  j9 A$ t: _mongoDB作为存储是没有问题的,财务这种核心数据,还是不建议使用mongoDB的
作者: shengnan007    时间: 2012-9-19 08:44
梦晓半生 发表于 2012-9-19 04:21
( F$ |& R6 s  ^+ `, Q谢谢。
, T0 e# O9 q; O0 _4 m8 i( [2 I: H6 O; @. ?& `; ]
中文看得真累,大部分还是英文术语。
$ b! I; o% R/ Q
现在关于mongoDB的文章,大部分都是在告诉大家怎么用,涉及到内部运行机理的文章,数量不多,而且不成体系。这个系列文章的目的,是让大家了解mongoDB的基本的运行机理,这样以后使用的时候,可以知其所以然。但是由于这方面的资料很少,我也是到处找资料,写了这么几篇,再往后,就是边使用,边看源码,边写了。
作者: profer    时间: 2012-9-19 14:16
shengnan007 发表于 2012-9-18 12:44
* P8 Z# o5 K; P# O$ K9 G是我啊。。。这都能被认出来。。。
$ s! ]& L: u. _- C/ R" I' C
是邓嫂么?
作者: shengnan007    时间: 2012-9-19 14:17
profer 发表于 2012-9-19 14:16
0 X0 i! g2 r( X- Y是邓嫂么?
/ }$ L! o0 v- V& x3 {& `# s
是邓的小兵
作者: 恶魔吹笛来    时间: 2012-9-19 18:35
有点惊讶 居然在这里看到这篇文章 呵呵 静待大作
作者: 梦晓半生    时间: 2012-9-20 00:57
shengnan007 发表于 2012-9-19 08:44
3 \& f; W# R: d. f" }" p现在关于mongoDB的文章,大部分都是在告诉大家怎么用,涉及到内部运行机理的文章,数量不多,而且不成体 ...
! ]; G5 t/ B0 i* y5 ^( P1 z
太好了,期待中,希望都带上英文reference。  s4 ?6 u+ B7 }- A* J+ S' |
" N  J" }, A1 G2 x( D" C8 A& j* l
现在这种新技术很多,Mongo是比较流行的一个,我这里附带一下一堆NoSQL的新系统,到最后估计会有几个胜出。5 o9 |/ d, X0 {" m( h0 U$ P; c. v% g6 _
9 C7 i$ ?/ d/ j
http://en.wikipedia.org/wiki/NoSQL
作者: shengnan007    时间: 2012-9-20 08:53
梦晓半生 发表于 2012-9-20 00:57
4 W( z2 ~; J/ ^6 I) w1 Y4 g太好了,期待中,希望都带上英文reference。
' Y  T' s: P5 u0 l/ [3 p; g) I, D  M: U. L2 @& x8 Q5 H- W
现在这种新技术很多,Mongo是比较流行的一个,我这里附带一 ...

3 ]8 T+ H/ i$ b3 I: d5 K; Q现在写的也很纠结,资料太少了,哈哈
作者: 梦晓半生    时间: 2012-9-21 11:52
shengnan007 发表于 2012-9-20 08:53 3 @# d/ @: c2 _. I
现在写的也很纠结,资料太少了,哈哈

8 T6 y- \: z  i' e建议从NoSQL写起,这是推动新数据库设计的需求关系,原始动力。' [9 w, x5 @4 Z: F( h( z# @

5 i1 A% @8 c$ W9 Z# ^http://en.wikipedia.org/wiki/NoSQL+ ^' v& `. N# [, _. i1 n' @

3 X6 H, ?7 i) v$ \2 u& O" G
作者: 定风波    时间: 2012-9-21 17:03
恶魔吹笛来 发表于 2012-9-19 18:35
3 H9 \& F( k$ ^) d! M3 O有点惊讶 居然在这里看到这篇文章 呵呵 静待大作
( L% d2 q9 ?' Y! }0 ]
有什么可惊讶的邓侃在前一个爱坛版本是很早的注册用户呢,从开心网一块迁移的。。。
作者: shengnan007    时间: 2012-9-24 09:11
梦晓半生 发表于 2012-9-21 11:52 % v2 j, Z+ y- x8 ~) Y2 k
建议从NoSQL写起,这是推动新数据库设计的需求关系,原始动力。
6 p4 p/ K% y( j" t" f
, E# [! I' n9 zhttp://en.wikipedia.org/wiki/NoSQL
3 U7 z9 D% b3 R; @3 \# c
好的好的,现在这个写完,然后开始写nosql




欢迎光临 爱吱声 (http://129.226.69.186/bbs/) Powered by Discuz! X3.2