theoforce 发表于 2015-7-6 05:14:04

Mongodb源码分析--Mongos之分布式锁

  在之前的一篇文章中,介绍了balancer会声明使用分布式锁来协调分布式环境下的信息沟通并确保事务一致性,有关分布式锁的一些原理性信息可以参见这几篇文章:
   http://wenku.baidu.com/view/19ce3085b9d528ea81c77982.html
   http://wenku.baidu.com/view/d94ac11ffc4ffe473368ab27.html
  
   http://zh.wikipedia.org/wiki/Paxos%E7%AE%97%E6%B3%95
  
   http://en.wikipedia.org/wiki/Paxos_%28computer_science%29
  
  下图是mongod使用sharding机制时的一个系统架构图(有关如果配置sharding并进行数据存储参见我的这篇文章):
http://daizhj.iyunv.com/images/cnblogs_com/daizhj/mongodb_sharding.png
  这里Mongod实现的比较简单,它主要是通过在config服务器结点上创建并维护两个lock集合(lockpings和lock),并mongos启动时会在这两个集合中各创建一条数据记录,然后通过维护该记录的状态(包括时间戳,state)来标识当前mongos结点的锁使用情况。如果多台机器之间想使用一个锁,只要确保锁的名称一致就行,这里就会在configsvr结点的相应集合中共享这一条记录以确保只有一个mongos结点获得了该锁。

      首先mongod会在配置为configsvr结点上创建并维护两个集合,如下图:
http://daizhj.iyunv.com/images/cnblogs_com/daizhj/distlock_lockpings.png
http://daizhj.iyunv.com/images/cnblogs_com/daizhj/distlock_locks.png
  config.lockpings:
      _id:存储mongos发送来的balancer的标识信息(格式=> "机器名称:时间戳:随机数")
      ping: 以及发送ping指令时的时间(日期时间格式)

config.lock:      _id: 存储锁的名称(如balancer)
      process: 关联config.lockpings中_id的字段(并与其保持一致)
      state: 锁状态(是否有操作使用该锁)。0为未锁定,1为锁定。
      ts: 锁转为使用状态时的时间戳
      when :锁转为使用状态时的时间(日期时间格式)
      who: 谁使用了该锁(格式为process + 线程名称 + 随时数)
      why: 使用锁的原因(如:doing balancer round)
  
  了解上面内容之后,我们看一下mongos分布式锁的类关系图:
http://daizhj.iyunv.com/images/cnblogs_com/daizhj/dist_lock_classdraw.png
  其中DistributedLock类就是分布式锁的结构,它包括如下信息:
    _name:锁名称,与config.lock中的_id相绑定
    _conn:要链接到的mongod服务器地址
    _ns:使用的锁集合名称,构造函数将其初始化为"config.locks"
    _takeoverMinutes: 强制接管的时间(当某个lock长时间不被解锁或无响应信息时),这时系统会回收该lock(通过将state置1)
    lock_entry() : 当系统开始获取lock时所执行的操作
    unlock():解除锁定
  dist_lock_try类主要用于对上面的DistributedLock类操作进行封装,以便于使用.
   其构造函数和析构函数与DistributedLock类的lock_entry()和unlock()方法对应。
  
   下面我们就通过源码来进一步分析其底层的实现原理, 首先我们看一下DistributedLock的构造函数:


//distlock.cpp
DistributedLock::DistributedLock( const ConnectionString& conn , const string& name , unsigned takeoverMinutes )
      : _conn(conn),_name(name),_takeoverMinutes(takeoverMinutes) {
      _id = BSON( "_id"0 )
                return;
   //线程方式执行distLockPingThread()方法
            boost::thread t( boost::bind( &distLockPingThread , conn ) );
            _seen.insert( s );
      }
      set _seen;
      mongo::mutex _mutex;
    } distLockPinger;  
      它使用线程方式来执行distLockPingThread()方法来发送ping指令,并最终执行下面方法:


//distlock.cpp
void _distLockPingThread( ConnectionString addr ) {
   //设置当前线程名称
      setThreadName( "LockPinger" );
      
      log()
页: [1]
查看完整版本: Mongodb源码分析--Mongos之分布式锁