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_names = Collections.synchronizedSet( new HashSet () ); // 节点名称 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(SetseenNodes){ 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(); Node node = _addIfNotHere(host); if (node != null && seenNodes != null) seenNodes.add(node); } } // 获取 passives 信息 if ( res.containsField( "passives" ) ){ for ( Object x : (List)res.get("passives") ){ String host = x.toString(); Node node = _addIfNotHere(host); if (node != null && seenNodes != null) seenNodes.add(node); } } // 获取 maxBsonObjectSize if (_isMaster ) { if (res.containsField("maxBsonObjectSize")) maxBsonObjectSize = ((Integer)res.get( "maxBsonObjectSize" )).intValue(); else maxBsonObjectSize = Bytes.MAX_OBJECT_SIZE; } // 获取 setName if (res.containsField("setName")) { String setName = res.get( "setName" ).toString(); if ( _setName == null ){ _setName = setName; _logger = Logger.getLogger( _rootLogger.getName() + "." + setName ); } else if ( !_setName.equals( setName ) ){ _logger.log( Level.SEVERE , "mis match set name old: " + _setName + " new: " + setName ); return; } } } catch ( ... ){ // ... } } // 更新所有节点状态 synchronized void updateAll(){ HashSet seenNodes = new HashSet (); // 遍历更新所有节点 for ( int i=0; i<_all.size(); i++ ){ Node n = _all.get(i); n.update(seenNodes); } // 移除已经不存在的节点 if (!seenNodes.isEmpty()) { // not empty, means that at least 1 server gave node list // remove unused hosts Iterator it = _all.iterator(); while (it.hasNext()) { if (!seenNodes.contains(it.next())) it.remove(); } } }
定时更新节点状态的内部类 ReplicaSetStatus.Node.Updater
ReplicaSetStatus.Node.Updater 继承了 Thread,可以实例化一个定时更新节点状态的线程。
// 覆写 Thread 类的 run 方法 public void run(){ while ( ! _closed ){ try { // 更新所有节点状态 updateAll(); // 如果当前时间大于 _nextResolveTime // 则更新所有节点并设置 _nextResolveTime long now = System.currentTimeMillis(); if (inetAddrCacheMS > 0 && _nextResolveTime < now) { _nextResolveTime = now + inetAddrCacheMS; for (Node node : _all) { node.updateAddr(); } } // 检查 master ,以避免更新带来的不同步 _mongo.getConnector().checkMaster(true, false); } catch ( Exception e ){ _logger.log( Level.WARNING , "couldn't do update pass" , e ); } // sleep一段时间,等待下次更新 try { Thread.sleep( updaterIntervalMS ); } catch ( InterruptedException ie ){ } } }