hbase问题-java.io.IOException: error or interrupt while splitting logs




【hbase】java.io.IOException: error or interrupt while splitting logs

一.问题描述及初步解决

操作层面报错如下:


[admin@inc-dp-hbase-01 conf]$ hbase shell


HBase Shell; enter 'help<RETURN>' for list of supported commands.


Type "exit<RETURN>" to leave the HBase Shell


Version 0.92.0, r1231986, Mon Jan 16 13:16:35 UTC 2012


 


hbase(main):001:0> list                    //可以查询


TABLE                                                                                                                       


hello                                                                                                                       


jj                                                                                                                           


ssjslkj                                                                                                                     


sunwg                                                                                                                        


test                                                                                                                        


5 row(s) in 0.6560 seconds


 


hbase(main):002:0> create 'yy','uu'      //不可以创建


 


ERROR: org.apache.hadoop.hbase.client.RetriesExhaustedException: Failed after attempts=7, exceptions:


Sat Apr 28 08:31:27 CST 2012, org.apache.hadoop.hbase.client.ScannerCallable@7b6bbeaf, org.apache.hadoop.hbase.NotServingRegionException: org.apache.hadoop.hbase.NotServingRegionException: Region is not online: -ROOT-,,0


        at org.apache.hadoop.hbase.regionserver.HRegionServer.getRegion(HRegionServer.java:2819)


        at org.apache.hadoop.hbase.regionserver.HRegionServer.getClosestRowBefore(HRegionServer.java:1755)


        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)


        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)


        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)


        at java.lang.reflect.Method.invoke(Method.java:597)


        at org.apache.hadoop.hbase.ipc.WritableRpcEngine$Server.call(WritableRpcEngine.java:364)


        at org.apache.hadoop.hbase.ipc.HBaseServer$Handler.run(HBaseServer.java:1326)


 


 


HMaster机器上查看日志:


2012-04-28 09:15:12,256 DEBUG org.apache.hadoop.hbase.client.HConnectionManager$HConnectionImplementation: Lookedup root region location, connection=org.apache.hadoop.hbase.client.HConnectionManager$HConnectionImplementation@55e29b99; serverName=inc-dp-hbase-03,60020,1335429401847


2012-04-28 09:15:12,302 DEBUG org.apache.hadoop.hbase.master.SplitLogManager: total tasks = 5 unassigned = 5


2012-04-28 09:15:13,306 DEBUG org.apache.hadoop.hbase.master.SplitLogManager: total tasks = 5 unassigned = 5


2012-04-28 09:15:14,310 DEBUG org.apache.hadoop.hbase.master.SplitLogManager: total tasks = 5 unassigned = 5


2012-04-28 09:15:15,314 DEBUG org.apache.hadoop.hbase.master.SplitLogManager: total tasks = 5 unassigned = 5


 


2012-04-28 09:25:30,384 WARN org.apache.hadoop.hbase.master.MasterFileSystem: Failed splitting of [inc-dp-hbase-02,60020,1335429401869, inc-dp-hbase-03,60020,1335429401847]


java.io.IOException: error or interrupt while splitting logs in [hdfs://inc-dp-hbase-01.hst.bjc.kfc.alidc.net:9000/hbase/.logs/inc-dp-hbase-02,60020,1335429401869-splitting, hdfs://inc-dp-hbase-01.hst.bjc.kfc.alidc.net:9000/hbase/.logs/inc-dp-hbase-03,60020,1335429401847-splitting] Task = installed = 1 done = 0 error = 0


        at org.apache.hadoop.hbase.master.SplitLogManager.splitLogDistributed(SplitLogManager.java:268)


        at org.apache.hadoop.hbase.master.MasterFileSystem.splitLog(MasterFileSystem.java:276)


        at org.apache.hadoop.hbase.master.MasterFileSystem.splitLogAfterStartup(MasterFileSystem.java:216)


        at org.apache.hadoop.hbase.master.HMaster.finishInitialization(HMaster.java:487)


        at org.apache.hadoop.hbase.master.HMaster.run(HMaster.java:326)


        at java.lang.Thread.run(Thread.java:662)


 


解读:hmaster其实一直在做log的分布式spit,但是都无法成功:


 


HRegionServer机器上查看日志:


2012-04-28 09:13:36,233 DEBUG org.apache.hadoop.hbase.regionserver.HRegionServer: NotServingRegionException; Region is not online: -ROOT-,,0


2012-04-28 09:14:08,242 DEBUG org.apache.hadoop.hbase.regionserver.HRegionServer: NotServingRegionException; Region is not online: -ROOT-,,0


2012-04-28 09:14:40,251 DEBUG org.apache.hadoop.hbase.regionserver.HRegionServer: NotServingRegionException; Region is not online: -ROOT-,,0




解决办法:


$ vi hbase-site.xml        //追加以下内容将分布式splitlog关闭


<property>


<name>hbase.master.distributed.log.splitting</name>


<value>false</value>


</property>



最后重启Hbase集群。有可能停止不了,直接kill进程(我是测试环境~


二.hbase.master.distributed.log.splitting作用及原理

通常有两种情况日志文件需要进行replay:当集群启动时,或者当服务器出错时。当master启动—(备份master转正也包括在内)—它会检查HBase在文件系统上的根目录下的.logs文件是否还有一些文件,目前没有安排相应的region server。日志文件名称不仅包含了服务器名称,而且还包含了该服务器对应的启动码。该数字在region server每次重启后都会被重置,这样master就能用它来验证某个日志是否已经被抛弃。

 

Log被抛弃的原因可能是服务器出错了,也可能是一个正常的集群重启。因为所有的region servers在重启过程中,它们的log文件内容都有可能未被持久化。除非用户使用了graceful stop(参见the section called “Node Decommission”)过程,此时服务器才有机会在停止运行之前,将所有pending的修改操作flush出去。正常的停止脚本,只是简单的令服务器失败,然后在集群重启时再进行log的replay。如果不这样的话,关闭一个集群就可能需要非常长的时间,同时可能会因为memstore的并行flush引起一个非常大的IO高峰。

 

Master也会使用ZooKeeper来监控服务器的状况,当它检测到一个服务器失败时,在将它上面的regions重新分配之前,它会立即启动一个所属它log文件的恢复过程,这发生在ServerShutdowHandler类中。

 

在log中的修改操作可以被replay之前,需要把它们按照region分离出来。这个过程就是log splitting:读取日志然后按照每条记录所属的region分组。这些分好组的修改操作将会保存在目标region附近的一个文件中,用于后续的恢复。

 

Logs splitting的实现在几乎每个HBase版本中都有些不同:早期版本通过master上的单个进程读取文件。后来对它进行了优化改成了多线程的。0.92.0版本中,最终引入了分布式log splitting的概念,将实际的工作从master转移到了所有的region servers中。

 

考虑一个具有很多region servers和log文件的大集群,在以前master不得不自个串行地去恢复每个日志文件—不仅IO超载而且内存使用也会超载。这也意味着那些具有pending的修改操作的regions必须等到log split和恢复完成之后才能被打开。

 

新的分布式模式使用ZooKeeper来将每个被抛弃的log文件分配给一个region server。同时通过ZooKeeper来进行工作分配,如果master指出某个log可以被处理了,这些region servers为接受该任务就会进行竞争性选举。最终一个region server会成功,然后开始通过单个线程(避免导致region server过载)读取和split该log文件。

注:可用通过设置hbase.master.distributed.log.splitting来关闭这种分布式log splitting方式。将它设为false,就是关闭,此时会退回到老的那种直接由master执行的方式。在非分布式模式下,writers是多线程的,线程数由hbase.regionserver.hlog.splitlog.writer.threads控制,默认设为3。如果要增加线程数,需要经过仔细的权衡考虑,因为性能很可能受限于单个log reader的性能限制。

Split过程会首先将修改操作写入到HBase根文件夹下的splitlog目录下。如下:


    0 /hbase/.corrupt
      0 /hbase/splitlog/foo.internal,60020,1309851880898_hdfs%3A%2F%2F \
localhost%2Fhbase%2F.logs%2Ffoo.internal%2C60020%2C1309850971208%2F \
foo.internal%252C60020%252C1309850971208.1309851641956/testtable/ \
d9ffc3a5cd016ae58e23d7a6cb937949/recovered.edits/0000000000000002352


为了与其他日志文件的split输出进行区分,该路径已经包含了日志文件名,因该过程可能是并发执行的。同时路径也包含了table名称,region名称(hash值),以及recovered.edits目录。最后,split文件的名称就是针对相应的region的第一个修改操作的序列号。

 

.corrupt目录包含那些无法被解析的日志文件。它会受hbase.hlog.split.skip.errors属性影响,如果设为true,意味着当无法从日志文件中读出任何修改操作时,会将该文件移入.corrupt目录。如果设为false,那么此时会抛出一个IOExpectation,同时会停止整个的log splitting过程。

 

一旦log被成功的splitting后,那么每个regions对应的文件就会被移入实际的region目录下。对于该region来说它的恢复工作现在才就绪。这也是为什么splitting必须要拦截那些受影响的regions的打开操作的原因,因为它必须要将那些pending的修改操作进行replay。


http://blog.cloudera.com/blog/2012/07/hbase-log-splitting/

http://duanple.blog.163.com/blog/static/709717672011923111743139/

三.问题总结

虽然按照第一种方法表面上解决了问题,但是不确定这样是否会影响性能,但是目前没找到其他方法,暂时先用第一种方法解决。不知道下次重启的时候把配置改回来是否可以正常(下次集群停止后尝试)。而至于hlogsplitting这个开关的影响待日后专门研究hbase的时候再详细研究

相关内容