今天在线上环境的监控页面中点击http://hbasemaster:60010/table.jsp?name=table1,界面中没有显示出应用的region情况,通过修改table.jsp可以观察到jsp程序在执行regions = table.getRegionsInfo()时,会抛出以下异常。
一时定位不到原因,而集群中抛出以上异常的表共有两张:table1/table2,另外几张表都是正常的。
跟踪程序代码,可以知道抛出异常的原因是读取region的info:regioninfo信息为空。于是去.META.表中扫描以上几张表,知道table1所有region的regioninfo都是存在的,但table2有部分region的regioninfo为空。询问客户后知道table2之前是从其它集群拷过来时,可能有异常操作导致部分数据丢失。而空regioninfo的那些region在hdfs上都不存在,因此可以删除之。
但这无法解释为何table1也会抛出这个异常。于是再次祭出btrace大法。
定位到在执行table1的查询时,scan meta表时,processRow会执行65次,在第65次时会抛出NullPointerException异常,而奇怪的是table1总共只有64个region,为什么会这样呢?
原来代码中有以下段落:
这下清楚了,原来扫描meta表中某张表的信息时并未设定stopRow,而是当检查到没有返回结果,或者返回结果的表名不是当前指定表时才退出循环。因此总会多扫一次,一般情况下没有问题,但当某张表有异常时,与它相邻的上一张表也会跟着杯具...
java.lang.NullPointerException
at org.apache.hadoop.hbase.util.Writables.getWritable(Writables.java:75)
at org.apache.hadoop.hbase.util.Writables.getHRegionInfo(Writables.java:119)
at org.apache.hadoop.hbase.client.HTable$2.processRow(HTable.java:398)
at org.apache.hadoop.hbase.client.MetaScanner.metaScan(MetaScanner.java:190)
at org.apache.hadoop.hbase.client.MetaScanner.metaScan(MetaScanner.java:95)
at org.apache.hadoop.hbase.client.MetaScanner.metaScan(MetaScanner.java:73)
at org.apache.hadoop.hbase.client.HTable.getRegionsInfo(HTable.java:421)
at org.apache.jsp.table_jsp._jspService(table_jsp.java:233)
...
一时定位不到原因,而集群中抛出以上异常的表共有两张:table1/table2,另外几张表都是正常的。
跟踪程序代码,可以知道抛出异常的原因是读取region的info:regioninfo信息为空。于是去.META.表中扫描以上几张表,知道table1所有region的regioninfo都是存在的,但table2有部分region的regioninfo为空。询问客户后知道table2之前是从其它集群拷过来时,可能有异常操作导致部分数据丢失。而空regioninfo的那些region在hdfs上都不存在,因此可以删除之。
但这无法解释为何table1也会抛出这个异常。于是再次祭出btrace大法。
@OnMethod(
clazz="org.apache.hadoop.hbase.util.Writables",
method="getHRegionInfo"
)
public static void traceWritables(final byte [] bytes){
println("writables");
println(bytes);
}
定位到在执行table1的查询时,scan meta表时,processRow会执行65次,在第65次时会抛出NullPointerException异常,而奇怪的是table1总共只有64个region,为什么会这样呢?
原来代码中有以下段落:
public boolean processRow(Result rowResult) throws IOException {
HRegionInfo info = Writables.getHRegionInfo(
rowResult.getValue(HConstants.CATALOG_FAMILY,
HConstants.REGIONINFO_QUALIFIER));
if (!(Bytes.equals(info.getTableDesc().getName(), getTableName()))) {
return false;
}
这下清楚了,原来扫描meta表中某张表的信息时并未设定stopRow,而是当检查到没有返回结果,或者返回结果的表名不是当前指定表时才退出循环。因此总会多扫一次,一般情况下没有问题,但当某张表有异常时,与它相邻的上一张表也会跟着杯具...