设为首页 收藏本站
查看: 895|回复: 0

[经验分享] 【转】为什么java无法连接搭在一台机器上的mongo复制集

[复制链接]

尚未签到

发表于 2016-12-2 09:47:03 | 显示全部楼层 |阅读模式
这篇文章或许已经不再使用,测试版本为2.7.x,有兴趣可以测试最新版本
  一、问题说明:
       最近测试mongo复制集,由于没有机器,所以选择在一台虚拟机上搭建。然后使用mongo-java-driver连接。
①、复制集初始化函数如下:
       


  • > config = {_id: 'shard1', members: [{_id: 0, host: '127.0.0.1:20011'},{_id: 1, host: '127.0.0.1:20012'},{_id: 2, host:'127.0.0.1:20013'}]}
  • > rs.initiate(config)

          或者你换成localhost,都没有关系。
②、java连接代码如下:



  • static Mongo m = null;
  •     static{
  •         try {
  •             List<ServerAddress> list= new ArrayList<ServerAddress>();
  •             ServerAddress sap0 = new ServerAddress("192.168.132.100",20011);
  •             ServerAddress sas1 = new ServerAddress("192.168.132.100",20012);
  •             ServerAddress sas2 = new ServerAddress("192.168.132.100",20013);
  •             list.add(sap0);
  •             list.add(sas1);
  •             list.add(sas2);
  •             m = new Mongo(list);
  •         } catch (UnknownHostException e) {
  •             // TODO Auto-generated catch block
  •             e.printStackTrace();
  •         }
  •     }

  192.168.132.100是虚拟机的IP,并不是使用本地localhost或者127.0.0.1,因为程序不再虚拟机上么。
报错:



  • Exception in thread "main" com.mongodb.MongoException: can't find a master

  
原因分析:
m = new Mongo(list);
使用此方法:


  • public Mongo( List<ServerAddress> replicaSetSeeds , MongoOptions options )
  •         throws MongoException {
  •         ....
  •         _addrs = replicaSetSeeds;
  •         ....
  •         _connector = new DBTCPConnector( this , _addrs );
  •         _connector.start();
  •         ...
  • }

  数据库连接是DBTCPConnector的实体类。


  • public DBTCPConnector( Mongo m , List<ServerAddress> all )
  •         throws MongoException {
  •         _portHolder = new DBPortPool.Holder( m._options );
  •         _checkAddress( all );
  •  
  •         _allHosts = new ArrayList<ServerAddress>( all ); 
  •         _rsStatus = new ReplicaSetStatus( m, _allHosts );
  •  
  •         _createLogger.info( all " -> " getAddress() );
  •     }

  错误报错是找不到主,我们关注ReplicaSetStatus类,继续往下走:
       这个类是获取replica set 最新状态的,运行时,后台有一个线程ping服务器,所以这个类的状态都是最新的。
他会读取rs的初始化函数,得到host,主从等等状态信息。
初始化函数:


  • ReplicaSetStatus( Mongo mongo, List<ServerAddress> initial ){
  •         _all = Collections.synchronizedList( new ArrayList<Node>() );
  •         for ( ServerAddress addr : initial ){
  •             _all.add( new Node( addr ) );
  •         }
  •         ...
  •  
  •         _updater = new Updater();
  •     }

  可以看到还有一个Node类,这个类是个内部类,保存address的名称,端口等信息。
Updater即是后台进程,同样是个内部类,继承Thead类:


  • class Updater extends Thread {
  •         Updater(){
  •             super( "ReplicaSetStatus:Updater" );
  •             setDaemon( true );
  •         }
  •  
  •         public void run(){
  •             while ( ! _closed ){
  •                 try {
  •                     updateAll();
  •  
  •                     long now = System.currentTimeMillis();
  •                     if (inetAddrCacheMS > 0 && _nextResolveTime < now) {
  •                         _nextResolveTime = now inetAddrCacheMS;
  •                         for (Node node : _all) {
  •                             node.updateAddr();
  •                         }
  •                     }
  •  
  •                     // force check on master
  •                     // otherwise master change may go unnoticed for a while if no write concern
  •                     _mongo.getConnector().checkMaster(true, false);
  •                 }
  •                 catch ( Exception e ){
  •                     _logger.log( Level.WARNING , "couldn't do update pass" , e );
  •                 }
  •  
  •                 try {
  •                     Thread.sleep( updaterIntervalMS );
  •                 }
  •                 catch ( InterruptedException ie ){
  •                 }
  •  
  •             }
  •         }
  •     }

  _connector.start();执行时,就会启动这个线程。关注绿色代码部分,updateAll()函数


  • synchronized void updateAll(){
  •         HashSet<Node> seenNodes = new HashSet<Node>();
  •         for ( int i=0; i<_all.size(); i++ ){
  •             Node n = _all.get(i);
  •             n.update(seenNodes);
  •         }
  •         ...
  •     }

  n.update(seenNodes),继续。。


  • synchronized void update(Set<Node> seenNodes){
  •             try {
  •                 long start = System.currentTimeMillis();
  •                 CommandResult res = _port.runCommand( _mongo.getDB("admin") , _isMasterCmd );
  •                ... 
  • }

  可以看到程序会远程执行isMaster命令,得到res


  • { "serverUsed" : "192.168.72.128:20011" , "setName" : "rstest" , "ismaster" : false , "secondary" : true , "hosts" : [ "localhost:20011" , "localhost:20013" , "localhost:20012"] , "primary" : "localhost:20012" , "me" : "localhost:20011" , "maxBsonObjectSize" : 16777216 , "ok" : 1.0}

  
这样的信息,看到了吧,hosts里面显示的是localhost:20011,就是我们在config函数里配置的IP
然后后面的程序会更新Node,将host变为localhost:20011,这样,我们的程序就无法连接了,毕竟不是在本地配置的。
其实这是个特例了,如果你的程序和mongo在一起的话,这样配置也不会出错,如果程序和mongo不在一起,那么你就需要用外部IP配置复制集了。解决办法如下



  • > config = {_id: 'shard1', members: [{_id: 0, host: '192.168.132.100:20011'},{_id: 1, host: '192.168.132.100:20012'},{_id: 2, host:'192.168.132.100:20013'}]}
  • > rs.initiate(config)

  说实在的,写到这里我写不下去了,因为这个是另外启动的线程,我无法调试出来具体的过程。但是原因却是是这个,大家注意就好了,如果有调试出具体过程的,感谢分享。
 
2012-09-12:今天开发的同事上线遇到问题,新版mongo2.2链接复制集找不到主,其实还是一个问题,因为现在配置复制集都是使用hostname代替IP,所以在程序中连IP的时候他还是找不到,无法解析。新版的driver-2.9.0已经支持,应该是Updater进程已经经过了判断,发现hostname链接不上后又替换了IP,所以大家用新版的driver吧,或者在应用服务器上也配置hosts,让程序能找到机器就好了。
转自 http://blog.iyunv.com/uid-15795819-id-3075083.html

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-308552-1-1.html 上篇帖子: Mongo的ORM框架的学习Morphia(十五)Morphia+spring整合 下篇帖子: Mongo运行错误:Failed to connect 127.0.0.1:27017,reason:errno:10061
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表