日期:2014-05-16  浏览次数:20544 次

MongoDB Java Driver 源码分析(8):com.mongodb.RelicaSetStatus
  RelicaSetStatus 用于读取集群中的服务器节点的信息。

  getMaster 方法和 getASecondary 方法分别可用于以获取 master 节点和 secondary 节点。
  内部类 ReplicaSetStatus.Node 包含了节点的状态信息,内部类 ReplicaSetStatus.Node.Updater 用于实例化一个定时更新节点状态的线程。

  getMaster 方法和 getASecondary 方法分析如下:
    // 获取 master 服务器地址
    ServerAddress getMaster(){
        // 获取 master 服务器节点
        Node n = getMasterNode();
        if ( n == null )
            return null;

        // 返回节点地址
        return n._addr;
    }

    // 获取 mater 服务器节点
    Node getMasterNode(){
        // 检查数据连是否已经关闭接
        _checkClosed();

        // 遍历所有节点,找到 master 服务器节点
        for ( int i=0; i<_all.size(); i++ ){
            Node n = _all.get(i);
            if ( n.master() )
                return n;
        }
        return null;
    }

    // 获取一个最佳的 secondary 服务器地址
    ServerAddress getASecondary(){
        // 检查数据连是否已经关闭接
        _checkClosed();

        Node best = null;
        double badBeforeBest = 0;

        // 随机选取起点
        int start = _random.nextInt( _all.size() );

        double mybad = 0;

        for ( int i=0; i<_all.size(); i++ ){
            Node n = _all.get( ( start + i ) % _all.size() );

            // 不是 secondary 节点,跳过
            if ( ! n.secondary() ){
                mybad++;
                continue;
            }

            // 找到第一个  secondary 节点
            // 设置 best,继续查找
            if ( best == null )
                best = n;
                badBeforeBest = mybad;
                mybad = 0;
                continue;
            }

            // 第 n 个 secondary 节点
            // 与之前找到的节点比较,选用最好的
            // 比较 ping 值
            long diff = best._pingTime - n._pingTime;
            if ( diff > slaveAcceptableLatencyMS ||
                 // 一种保证随机分布的算法
                 ( ( badBeforeBest - mybad ) / ( _all.size() - 1 ) ) > _random.nextDouble() )
                {
                best = n;
                badBeforeBest = mybad;
                mybad = 0;
            }

        }

        if ( best == null )
            return null;

        // 返回 best 的地址
        return best._addr;
    }

包含节点状态信息的内部类 ReplicaSetStatus.Node

  ReplicaSetStatus.Node 包含了节点的信息:
final ServerAddress _addr; // 地址
final Set<String> _names = Collections.synchronizedSet( new HashSet<String>() ); // 节点名称
DBPort _port; // 数据库端口

boolean _ok = false;  // 状态是否正常
long _lastCheck = 0;  // 上次检查时间
long _pingTime = 0;  // ping 延时

boolean _isMaster = false;  // 是否为 master 节点
boolean _isSecondary = false;  // 是否为 secondary 节点

double _priority = 0; // 优先级


  另外,它也提供了更新节点的方法 upadate 和 updateAll:
        // 更新节点状态
        synchronized void update(Set<Node> seenNodes){
            try {

                // 发送 admin 请求,检查状态 
                long start = System.currentTimeMillis();
                CommandResult res = _port.runCommand( _mongo.getDB("admin") , _isMasterCmd );
                _lastCheck = System.currentTimeMillis();
                _pingTime = _lastCheck - start;

                // 状态异常
                if ( res == null ){
                    _ok = false;
                    return;
                }

                // 状态正常
                _ok = true;
 
               // 是 mater 节点
                _isMaster = res.getBoolean( "ismaster" , false );

                // 是 secondary 节点 
                _isSecondary = res.getBoolean( "secondary" , false );

                // 是 primary 节点
                _lastPrimarySignal = res.getString( "primary" );

                // 获取 hosts 信息
                if ( res.containsField( "hosts" ) ){
                    for ( Object x : (List)res.get("hosts") ){
                        String host = x.toString();