4 _- O5 y7 D* P6 j( v3 L* g Replica Sets中的节点从距离它“最近”的节点同步数据,这个“最近”是通过ping的时间来判断的。在节点之间的心跳检测中,会记录ping某个节点和收到响应的时间,通过这个时间的长短,来确定距离的远近,时间越长视为距离越远。知道了和节点之间的距离,再通过如下的算法,来确定可以同步数据的源节点: 0 k3 U9 c$ L+ O( s0 |" I7 o/ e( x, k1 f
for each member that is healthy:5 F- R* l) i+ r7 w
if member[state] == PRIMARY , ~5 F9 l6 X8 G$ |8 K8 s add to set of possible sync targets" T. U. [8 B5 p! Y; T9 r1 M) G
9 I: V$ T- q/ B
if member[lastOpTimeWritten] > our[lastOpTimeWritten] 3 |% h& O- S7 R- _# c& \, X' A5 m add to set of possible sync targets : H( V, D0 ?! w$ @. E! k2 o4 _8 d
sync target = member with the min ping time from the possible sync targets3 e C7 I! f P# P: G3 L4 y" w; _
1 @' }! e2 R4 V9 } 对于节点是否健康,MongoDB各个版本的判断依据有所不同,但都是为了找到能够正常运行的节点。+ f* L6 N, e4 h" v7 r/ F
9 X y! H) r p# \9 ^4 ? 我们可以通过运行db.adminCommand({replSetGetStatus:1})命令来查看当前的节点状况,在secondary上运行这个命令的时候,能够看到syncingTo这个字段,这个字段的值就表示secondary节点同步数据的源节点。 ! t8 m" k) H8 ]# M2 u2 f0 h& @2 Q8 V , E6 a9 ?9 x- t. m! d: F1 [( S H链式同步 / |* \6 f# W) B$ r, }0 K 0 p& I3 {4 i+ W! C 前边所说的内容,都是假设有一个primary和一个secondary,这种情况下的同步过程比较简单,但是如果有2个secondary或者更多,那么这个过程就要复杂的多。 ' d/ F% S3 p% v9 r% ^* E/ l4 E6 j s& B1 M
我们用w:3来说明这个问题。比如S1和S2节点是secondary节点, P节点是primary节点,S1节点从P节点同步数据,S2节点从S1节点同步数据。这样P -> S1 -> S2 之间就形成了一个链。如果我们设定w为3,那么除了primary写入数据,还需要有两个secondaris完成同步,才可以返回成功。那么P节点如何能知道S2节点已经从S1节点同步成功了呢?% X. A l# [" C. c
+ H2 z. y B# E9 [3 z4 G: ?/ v
MongoDB通过oplog同步协议来解决上述的多个节点同步的问题。- z) Z0 H8 b8 U% z9 q7 s
- f. [: ~4 J3 T7 {! P5 i( {! X0 C 当S2从S1同步数据时,S2会给S1发送一个特殊的握手消息,“Hi,我是S2,我要从你这同步数据了,把我也算到w参数里边吧。” # F. V9 I W2 w. H, B1 B( H" c9 d% k1 m* M k
当S1收到这个消息的时候,会说,“我不是primary节点,我可以把你这个计数转到我的同步源中去。”然后S1打开一个到P的新的连接,然后对P说,“这个连接你就当是S2的吧,把S2也算到w的计数中。”这个时候,S1和P之间有两个连接,一个是S1自己的,一个是为S2建立的。, @1 z& l% t: \% j