每日学习笔记(24)

 1,一开始都是调用HttpMethod的getResponseBody()和getResponseBodyAsString,但这样总会出现下图中的警告信息

 

这是由于没有使用缓存的缘故,如果字符串数据过多,会出警告,应该改用流和缓存来读取数据:

 

  
  
  
  
  1. InputStream resStream = null
  2.        String response = null
  3.        BufferedReader resBufferReader = null
  4.         
  5.        try { 
  6.            httpClient.executeMethod(httpMethod); 
  7.            resStream = httpMethod.getResponseBodyAsStream(); 
  8.            resBufferReader = new BufferedReader(new InputStreamReader(resStream));  
  9.            StringBuffer resBuffer = new StringBuffer();    
  10.            String resTemp = "";    
  11.            while((resTemp = resBufferReader.readLine()) != null){    
  12.                resBuffer.append(resTemp);    
  13.            }    
  14.            response = resBuffer.toString();    
  15.  
  16.        } catch (Exception e) { 
  17.        } 

 2,   连接Zookeeper的方法如下:

 

  
  
  
  
  1. public static HBaseAdmin hBaseAdmin = null
  2.  
  3.     public static void init() { 
  4.         hBaseConfiguration = HBaseConfiguration.create(); 
  5.         try { 
  6.             hBaseAdmin = new HBaseAdmin(hBaseConfiguration); 
  7.         } catch (Exception e) { 
  8.             throw new HbaseRuntimeException(e); 
  9.         } 
  10.     } 

这里其实是将两个默认的配置文件加进来了,对于相同的配置项,后者会覆盖前者

 

  
  
  
  
  1. conf.addResource("hbase-default.xml"); 
  2.     conf.addResource("hbase-site.xml"); 

可是总是报下面的错:

 

  
  
  
  
  1. An error is preventing HBase from connecting to ZooKeeper 
  2.  
  3. Caused by: java.io.IOException: Unable to determine ZooKeeper ensemble 

断点跟踪到Zookeeper的源码发现是ZKUtil类的connect方法抛出的异常,

 

  
  
  
  
  1. public static ZooKeeper connect(Configuration conf, String ensemble, 
  2.       Watcher watcher, final String descriptor) 
  3.   throws IOException { 
  4.     if(ensemble == null) { 
  5.       throw new IOException("Unable to determine ZooKeeper ensemble"); 
  6.     } 
  7.     int timeout = conf.getInt("zookeeper.session.timeout", 180 * 1000); 
  8.     LOG.debug(descriptor + " opening connection to ZooKeeper with ensemble (" + 
  9.         ensemble + ")"); 
  10.     return new ZooKeeper(ensemble, timeout, watcher); 
  11.   } 

上述代码表明是没有读取到Zookeeper集群的地址,这个地址是在ZooKeeperWatcher的构造函数中读取的:

 

  
  
  
  
  1. this.quorum = ZKConfig.getZKQuorumServersString(conf); 

继续跟下去,发现配置信息是makeZKProps方法读取出来的,

  
  
  
  
  1.     // First check if there is a zoo.cfg in the CLASSPATH. If so, simply read 
  2.     // it and grab its configuration properties. 
  3.     ClassLoader cl = HQuorumPeer.class.getClassLoader(); 
  4.     final InputStream inputStream = 
  5.       cl.getResourceAsStream(HConstants.ZOOKEEPER_CONFIG_NAME); 
  6.     if (inputStream != null) { 
  7.       try { 
  8.         return parseZooCfg(conf, inputStream); 
  9.       } catch (IOException e) { 
  10.         LOG.warn("Cannot read " + HConstants.ZOOKEEPER_CONFIG_NAME + 
  11.                  ", loading from XML files", e); 
  12.       } 

 

看到这里才恍然大悟,它会首先去检查CLASSPATH下是否有zoo.cfg文件,如果有,则将其中的配置项读取出来作为Zookeeper的配置项,而此时就会完全不顾 hbase-default.xml和hbase-site.xml这两个配置文件了!

3,   Zookeeper有两个异常需要特别认真地去考虑,

1)第一种情况是连接丢失,在丢失的这段时间,你的操作是不生效的,也就意味着你所做的delete,setData,makePath这些操作都是无效的,这就是第一个要特别去处理的异常信息

KeeperException.ConnectionLossException,处理的方法很简单,就是引入重试机制,指定好最大重试次数,重试间隔时间即可。

 

  
  
  
  
  1. public <T> T retryOperation(ZkOperation operation) throws KeeperException, InterruptedException { 
  2.    KeeperException exception = null
  3.    for (int i = 0; i < retryCount; i++) { 
  4.      try { 
  5.        return (T) operation.execute(); 
  6.      } catch (KeeperException.ConnectionLossException e) { 
  7.        if (exception == null) { 
  8.          exception = e; 
  9.        } 
  10.        if (Thread.currentThread().isInterrupted()) { 
  11.          Thread.currentThread().interrupt(); 
  12.          throw new InterruptedException(); 
  13.        } 
  14.        retryDelay(i); 
  15.      } 
  16.    } 
  17.    throw exception; 
  18.  } 

 

 

2)第二种情况是Session的超时。当你第一次连接Zookeeper时,是可以注册一个Watcher的,这个Watcher的作用就是应对Zookeeper连接成功和会话超时的,

当后者发生时,你必须进行尝试重新连接Zookeeper服务器的动作,一旦重新连接成功,你就可以做一些应用层的初始化动作,这里是通过onReconnect.command()来实现的,OnReconnect接口是一个钩子,用于重连完成时,回调进行一些初始化动作的。

 

  
  
  
  
  1. public synchronized void process(WatchedEvent event) { 
  2.     if (log.isInfoEnabled()) { 
  3.       log.info("Watcher " + this + " name:" + name + " got event " + event + " path:" + event.getPath() + " type:" + event.getType()); 
  4.     } 
  5.  
  6.     state = event.getState(); 
  7.     if (state == KeeperState.SyncConnected) { 
  8.       connected = true
  9.       clientConnected.countDown(); 
  10.     } else if (state == KeeperState.Expired) { 
  11.       connected = false
  12.       log.info("Attempting to reconnect to recover relationship with ZooKeeper..."); 
  13.       //尝试重新连接zk服务器 
  14.       try { 
  15.         connectionStrategy.reconnect(zkServerAddress, zkClientTimeout, this, 
  16.             new ZkClientConnectionStrategy.ZkUpdate() { 
  17.               @Override 
  18.               public void update(SolrZooKeeper keeper) throws InterruptedException, TimeoutException, IOException { 
  19.                 synchronized (connectionStrategy) { 
  20.                   waitForConnected(SolrZkClient.DEFAULT_CLIENT_CONNECT_TIMEOUT); 
  21.                   client.updateKeeper(keeper); 
  22.                   if (onReconnect != null) { 
  23.                     onReconnect.command(); 
  24.                   } 
  25.                   synchronized (ConnectionManager.this) { 
  26.                     ConnectionManager.this.connected = true
  27.                   } 
  28.                 } 
  29.                  
  30.               } 
  31.             }); 
  32.       } catch (Exception e) { 
  33.         SolrException.log(log, "", e); 
  34.       } 
  35.       log.info("Connected:" + connected); 
  36.     } else if (state == KeeperState.Disconnected) { 
  37.       connected = false
  38.     } else { 
  39.       connected = false
  40.     } 
  41.     notifyAll(); 
  42.   } 

 

 

4,今天在做solr的master/slave切换时遇到一个让人困扰的问题

场景描述:

         3个solr节点的集群,1个master节点,名为m1,2个slave节点,分别为s1,s2,每个solr节点都在Zookeeper集群中同一个Znode下注册为EPHEMERAL_SEQUENTIAL节点,分别可以得到一个序号,采取“序号最小者为master”的策略来进行master选举。若m1节点挂掉,则下一个序号最小的slave节点自动接替成为新的master,假定此slave是s1,则此时有3件事要完成:

         1) s1节点上的solr核的solrConfig.xml配置文件中有关replication的片段,必须从slave的配置改成master的配置,并且reload其对应的solr核

         2)其他slave节点(这里是s2)必须修改其配置文件中有关replication的片段,将原先指向m1的masterUrl改为指向s1,并且reload其对应的solr核

         3)若原先挂掉的m1节点重新回到集群中来,则它会在上面提到的那个Znode下重新一个EPHEMERAL_SEQUENTIAL节点,并且序号肯定会比s1,s2的大,则m1会发现已经有新的master节点s1存在,自动识别出自己的身份是slave,其上的solr核也会采用有关slave的配置片段,并且指向s1所在的新的masterUrl

问题:

         我现在碰到的情况是,s1将其配置文件从slave改为master,然后reload的结果是,索引目录文件由index变成了index.时间戳,导致s2这个slave节点在从s1复制索引时却是默认从index这个目录去复制的,从而无法找到索引文件,s1上的indexversion返回是0.

         目前卡在这个地方,明天来好好研究下真实原因。。。

 

你可能感兴趣的:(java,职场,随笔,java语言,休闲)