sunshine_1985 发表于 2013-1-30 01:53:10

MongoDB shard相关源码分析

 
MongoDB源码分析
由于应用场景的需要, 我们需要对MongoDB具体实现机制进行进一步的了解,作为开源软件, 直接查看源代码,肯定是最好的选择, 由于我们最关注的是,mongos作为一个转发的代理服务器, 是否可能会成为整个系统中的一个单点和实现瓶颈, 因此,在这次源码阅读过程中,最主要是关注了和mongos相关的几个类,其实也是整个mongoDB实现shard机制的最主要的类,包括"s/config.cpp" ,"s/grid.cpp" , "s/chunk.cpp" , "s/shard.cpp" ,"s/shardkey.cpp", 通过查看这几个主要的类以及它里面使用的一些类, 真正了解mongoDB内部的运作协调机制。
 
1shard
shard机制, 是mongoDB非常重要的一个机制, 实际上, mongoDB就是将database分布到多个shard上, 来实现数据的切分并提高数据的访问效率, 那么shard是如何实现的呢?


1.1shardStatus
为了更好的表示shard当前的状态, mongoDB定义了一个shardStatus的类, 里面主要包含了
http://www.agoit.com/upload/picture/pic/80152/cbb11e81-b4b3-3ebd-988d-15021bda3e27.jpg
一个shard, 一个表示当前时间状态的信息,一个是否有回写的队列信息, 以及一个是否被加上写锁的信息, 通过这几个信息, 来表示。
 
1.2 shard
http://www.agoit.com/upload/picture/pic/80148/bd975069-6b04-32e6-8191-85010795a2be.jpg
shard主要包含了以上几个member, 包括shard的名字, shard的地址, 包括ip 和port, shard的最大值, 如果shard的大小达到最大值, config server 不会继续将数据分配到这个节点, _isDrain表示当前的的shard是否正在被移除。
 
1.3 StaticShardInfo
而实际上, 所有的shard的信息, 是保存在这给staticshardInfo的的静态遍历中。它的成员非常见到,一个互斥锁和一个map<string,Shard>_lookup;, 这个map通过名字,可以很方便查找出所有的shard的信息。方便在整个程序中进行共享。
http://www.agoit.com/upload/picture/pic/80150/51890d2c-2235-32b7-83a9-1d8fc6f607ad.jpg
在shard中, 主要包括了以上几个关键类, reload()方法, 通过连接config server中的primary, 读取configuration server所有有关shard的信息, 并保存到shard中。 _lookup()方法, 主要实现了查询当前的一个shard是否是在我们程序的一个成员shard。
find()方法实现查询, 如果是一个复制集, 那么根据复制集的名字来查询是否在shard中。getAllShard就比较见名知义, 获取当前所有的shard.
shards实际上就是调用了staticshardinfo中的方法, 来实现了大部分的方法。
 
2chunks
shards, 实际上是从比较宏观的角度 去看那些数据的分割,但是实际上, chunks才是mongoDB在不同shards之间交互的最小单位, 只有了解了chunks在整个mongoDB的流通, 才能真正了解整个mongoDB的实现细节。chunks里面, 实际上是包含了一定数量的,根据shard
keys排好序的collection。由于这个类太重要,太复杂, 因此它有很多的辅助类, 且听我一一到来。
 
2.1 chunkRange
http://www.agoit.com/upload/picture/pic/80156/06dc48de-b15d-3a5f-ab65-3b1a3872ce91.jpg
chunkRange的member,很清楚的表明了这个类的意义, 首先是有一个shard, 然后上面 包含了一个collection上的shardkey的最大值和最小值, 同时还包含了一个chunkManager  的指针, 指向所有chunk的所有相关信息
 
 
2.2chunkRangeManager
chunkRanageManger, 这是一个管理chunkRange的辅助类, 它有一个map的成员, 主要保存了所有的chunkRange的指针。
 
  2.3chunk
http://www.agoit.com/upload/picture/pic/80156/06dc48de-b15d-3a5f-ab65-3b1a3872ce91.jpg
chunk主要保存了以下数据成员, 主要就是一个最大值,一个最小值, 还有一个shard,指向他保存的shard的地址, 还有一个chunkMange的指针,用于对chunk进行操作,最主要的操作类都是在chunk 和chunkManage中。还有个shardchunkversion,用于进行版本控制,确保在多个写之后,服务器知道哪个是最新的更新数据, 从而保证了最终一致性。
在chunk中, 主要包括了以下的方法
1.contains, 判断一个key值是否在shards中
2.  pickMedianKey向mongod发出一个关于chuks 分隔点的查询,返回中位的key值
3.singleSplit对当前的shards进行分割,  获取适合的的分割点
4.multiSplit根据多个key值,将shard里面的chunk, 分割成多个chunk分割成多个chunk
5.   moveAndCommit将chunk, 从当前的shard ,移动到指定的shards如果移动成功,就需要reload,获取当前chunk的元数
6. moveIfShould如果当前shard的chunk数小于1???这个countObjects的不是非常理解 从shard中选一个最适合的shard将chunk移动到新的位置
7. splitIfShould当需要的时候切分, 切分的门槛的数字, 根据当前chunk的数字, 得出需要切分的一个限制,如果是需要分割, 那么用singleSplit进行分割得到需要移动到的新shard,调用moveIfShould,进行移动
 
  2.4 chunkManager
http://www.agoit.com/upload/picture/pic/80158/5323775c-1675-3dea-a2a8-dfb239287e75.jpg
首先是chunkManager的几个member, 首先在一个chunManager中, 包含了命名空间, 关键字,是否唯一等基本信息, 同时包括了一个管理的所有chunk的一个map,一个包含所有shard的一个set , 同时还有一个chunkRanagegManager ,,管理所有的chunkRange,一个sequenceNumber,进行版本管理。
主要的方法包括
1._load() 连接primary 的confige server 查询"config.chunks"
获取所有的chunk信息和shards信息并保存到_chukMap 和shards中
2. _isValid 确保chunkMap中的所有chunks没有间隔和交
3._reload_inlock() 最少尝试3次_load() 直到_isvald()
_chunkRangs.reloadAll(_chunkMap);序列号+1 通过版本控制的机制, 来跟踪chunkManager重新load的次数 通过触发checkShardVersion 来达到连接级的版本达到最新的状态
4.ceateFirstChunk在指定的shard上面,增加一个chunk,指定min max 获取一个version号,并增加1 获取一个连接, 修改chunk 的collection的信息  config.chunks 序列数的号码增加1 每一个chunkmanager 有个唯一的数字 通过检查chunkmange 的序列号, 来确定 chunk的配置信息是否更改 将chunk 存到chunkMap中
将chunkRange 进行reloadAll 将chunk所在的shard存到shard中
修改chunk当前的版本号 确保shardKey中需要index的建index
5.findChunk  获取key值, 查询_chunkMap,如果存在,并且chunk中包含了对应的obj那么返回。如果要求retry, 可以进行第二次尝试 每次尝试, 都会进行_reload_inlock()
6.findChunkOnServer( ) 通过遍历_chunkMap ,找到在指定shard上的chunk
7.getShardsForRange 变量所有从min到max的所有的shard并保存到shards里面 ensureIndex_inlock变量shards中所有的shard, 对key建立索引 每次都需要啊?所有key都需要
8. getVersioin,  通过遍历chunkMap上面的所有chunk, 获取当前最大的版本号 并返回。
 
3小结
小结, 代码看到这里, 也就大概知道了整个mongoDB内部如何对根据chunk进行合理的管理的 。这一切的最高管理者,当然是chunkManager, 它掌控着所有的生杀大权。从load开始, 读取config server,所有chuk的信息, 并建立所有相关的chunk,chunkRange,shards等相关的信息, 并根据chunk的需要比如负载不均衡,或者有新的shard加入的适合,将一些chunk移到适当的shard上面, 从而保证shard上面既不会爆满, 又能够达到负载均衡。而chunk中的方法, 有保证了可以将chunk按照较为平均的比例切分到不同的shards上面。同时, chunk上面包含了版本控制的信息, 保证了W+R>N的原理, 来保证整个写入的最终一致性。
 
页: [1]
查看完整版本: MongoDB shard相关源码分析