[转帖]HBase的两个异常排查_Hadoop,ERP及大数据讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  Hadoop,ERP及大数据讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3263 | 回复: 0   主题: [转帖]HBase的两个异常排查        上一篇   下一篇 
    本主题由 koei123 于 2015-6-1 15:14:44 移动
fozhyn
注册用户
等级:上士
经验:317
发帖:101
精华:0
注册:2011-10-18
状态:离线
发送短消息息给fozhyn 加好友    发送短消息息给fozhyn 发消息
发表于: IP:您无权察看 2015-3-18 18:02:47 | [全部帖] [楼主帖] 楼主

1,写HBase莫名卡住



之前有个多线程数据同步程序在写HBase时偶尔会卡住,从jstack分析,有一个线程block在

北京联动北方科技有限公司
而其他要写同一个regionserver的线程block在上面这把锁。
在HBase client的代码中发现在构造out对象的时候,timeout设成了0.具体代码如下:
北京联动北方科技有限公司
北京联动北方科技有限公司

北京联动北方科技有限公司
接着看write这个调用
北京联动北方科技有限公司北京联动北方科技有限公司北京联动北方科技有限公司北京联动北方科技有限公司
当调用write时,先写channel的buffer,写满以后,将数据发送出去。
北京联动北方科技有限公司
好了,从代码路径上看到,正是卡在selector.select这个地方,因为在构造的时候设置了timeout为0,0意味着无限等待。
select是当注册的channel就绪时就返回,对于读的,通道缓存满意味着就绪,对于写,将通道的数据清空意味着就绪。而写只是用户空间的缓存数据移到内核空间,理论上是不会失败的,除非网络有问题,Send-Q里的数据一直没发送出去。
而通过netstat看到情况证实了这一点,regionserver所在的机器在18:15时已经当机,当机原因不详,但client所在的机器在19:30依然有这样的tcp连接

tcp 0 65160 ::ffff:{client ip}:57589 ::ffff:{server ip}:30020 ESTABLISHED


连接状态还是ESTABLISHED,对于client来说,还是一个正常的链接,但是写又写不进去,咨询了内核专家,得知这是内核的一个bug。那
现在看上去可行的解决方法只能是在hbase client的代码里

北京联动北方科技有限公司加超时了
相关同事提交了issue到社区 https://issues.apache.org/jira/browse/HBASE-8558,在0.94.16已经被修复。

2,多线程读写HBase的一个注意点



还是这个程序,某天报了个错

java.util.concurrent.ExecutionException: java.lang.RuntimeException: java.lang.OutOfMemoryError: unable to create new native thread
at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)
at java.util.concurrent.FutureTask.get(FutureTask.java:83)
at org.apache.hadoop.hbase.client.HConnectionManager$HConnectionImplementation.processBatchCallback(HConnectionManager.java:1604)
at org.apache.hadoop.hbase.client.HConnectionManager$HConnectionImplementation.processBatch(HConnectionManager.java:1456)
at org.apache.hadoop.hbase.client.HTable.flushCommits(HTable.java:1011)
at org.apache.hadoop.hbase.client.HTable.put(HTable.java:834)
at com.taobao.dump.sapclient.client.HbaseClient.set(HbaseClient.java:224)

看错误信息,不能建立新的线程,和之前集群升级时遇到的一个问题类似,分析是某个程序建了大量的线程,达到了系统的上限。看机器上跑的进程的,最大可能是这个程序自己。从出错信息分析,结合hbase源码,在每个htable建立的时候,会初始化一个线程池。

int maxThreads = conf.getInt("hbase.htable.threads.max", Integer.MAX_VALUE);
if (maxThreads == 0) {
        maxThreads = 1; // is there a better default?
}
long keepAliveTime = conf.getLong("hbase.htable.threads.keepalivetime", 60);

// Using the "direct handoff" approach, new threads will only be created
// if it is necessary and will grow unbounded. This could be bad but in HCM
// we only create as many Runnables as there are region servers. It means
// it also scales when new region servers are added.
this.pool = new ThreadPoolExecutor(1, maxThreads,
keepAliveTime, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
Threads.newDaemonThreadFactory("hbase-table"));
((ThreadPoolExecutor)this.pool).allowCoreThreadTimeOut(true);

这个pool的作用是client在提交一个操作时,会建立一个callable线程提交到pool里,每个线程专门处理各自regionserver上的请求,最终聚合在一起,返回给client。所以当一个批量操作的请求过来的时候,极端情况下会在每个regionserver都会有一个线程,而每个htable都独自维护这个pool。所以当进程里htable实例多,并且集群规模较大的时候,该进程的线程数极端情况下是很多的。
具体到这个程序,确实有大量的batch操作,并且开了29个处理线程,并且hbase集群加了一批机器后,达到了近400台的规模,那极端情况下,将有1万多个线程,还不包括其他处理线程。而当时又有多个进程被同时调度到这台机器上,这时就就会出现上述异常了。
解决思路应用层面主要是降低极端情况下的并发,有以下几个方面:
1,container数和单个container中的线程数,在并发处理能力保持不变的情况下,选择合理的container数和线程数。
2,使用HTablePool来统一管理HTable实例,最好是单例,并且设定一个合理的maxSize,如并发时htable实例不够,调用方就先等待,直到有可用的实例。
3,建立htable对象时,指定自己的线程池,这个线程池全局共用,并且维护一个有界队列,当队列满时,请求就等待。

public HTable(Configuration conf,final byte[] tableName,
final ExecutorService pool)

这个case最后的解决方式是,调低了HTablePool的maxSize。

另一个解决思路,加大系统可创建的最大线程数,关于一个JVM进程最多可以创建多少个线程,请参考 http://jzhihui.iteye.com/blog/1271122 ,但在我们的环境实际测试,只有调整参数/proc/sys/vm/max_map_count才能加大可创建的线程数。如不做调整,则可创建30000+个线程。具体系统层面的因果还待进一步分析。

--转自 北京联动北方科技有限公司

该贴由koei123转至本版2015-6-1 15:14:43



赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论