HBase coredump问题和修复
- UI展示RPC call参数时,引用了被释放的内存。UI造成coredump的原因有两个:
- RPC monitor的生命周期没有控制在call的生命周期之内;
- RPC monitor返回给http call克隆对象时,状态变量的克隆与数据变量的克隆不匹配。状态变量类似常量拷贝,而数据变量是浅拷贝。
- 提交到社区的issue:
https://issues.apache.org/jira/browse/HBASE-25981
https://issues.apache.org/jira/browse/HBASE-26087 - 这个bug的触发与运维脚本频繁抓取JMX的内容有关,特别是抓取RPC的处理状态信息。修复前全部集群特别是访问压力大的集群,会间隔几天因这个问题RS coredump重启。
-
checkAndMutate在check阶段获取的数据被过早释放。
问题的原因是checkAndMutate在check阶段会scan一部分数据。这部分数据用来做检查。但是scan出数据后,检查之前,scanner就被close,从而数据所在的堆外内存就被释放和复用。
在读数据内容做check的时候,会因为读取数据内存地址的数据不符合预期而产生错误的判断或是coredump,而错误的判断会导致用户本应写入的数据写入失败。
这个问题可以用UT稳定复现。解决方案也比较明确,即数据在使用之后释放。
提到社区的issue:https://issues.apache.org/jira/browse/HBASE-26036
这个bug主要影响的业务,他们存储的数据有正排属性,比如价格,库存等,所以几乎所有相关的表都会采用CAS写入的方式。 -
RPC结束close scanner时,发现资源已被释放。
问题的原因:
table block进入bucket cache缓存后,block中记录的next block size如果发生变化,会由新的block替换原先缓存的block。
而这个过程为了避免原先的block发生内存泄漏,替换前会将原block的内存直接释放,释放时并未考虑原block是否有rpc引用。
提到社区的issue:https://issues.apache.org/jira/browse/HBASE-26155 -
文件损坏引起的coredump问题。
经过日志分析发现多台RS因coredump重启,线程崩溃在解压包的位置。并且最终定位到崩溃与具体的2个region有关,这2个region只要开始做compaction,就会引起RS崩溃。
整个集群300多台机器,2个region分别坏了1个文件,然后只要compaction选中损坏文件,就会引起region在的RS coredump重启,然后region移动到其他RS,短时间内又回coredump。也就是2个文件损坏,引起了全部RS的轮番重启!
于是先更新代码将疑似有问题的region全部隔离,禁用疑似问题region的compact,保证服务的可用性。再经过PR检查,代码检查,文件检查。。。最终定位是与2个文件有关,这2个文件有数据损坏/异常,只要调用lzo native lib解压就必定会引起进程崩溃。
使用HBase提供的shell工具读对应hfile的stat信息时,就会崩溃,确认了这个问题。 -
与too big request同时出现的coredump问题。
但是coredump时调用栈的位置每次都指在WrongRowIOException message的kv.toString()的位置,
public Put add(Cell kv) throws IOException{
byte [] family = CellUtil.cloneFamily(kv);
List list = getCellList(family);
//Checking that the row of the kv is the same as the put
if (!CellUtil.matchingRow(kv, this.row)) {
throw new WrongRowIOException("The row in " + kv.toString() +
" doesn’t match the original one " + Bytes.toStringBinary(this.row));
}
list.add(kv);
familyMap.put(family, list);
return this;
}
改为如下代码,coredump就不复现了
if (!CellUtil.matchingRow(kv, this.row)) {
String errMsg = "The row in the put kv doesn’t match the original one " +
Bytes.toStringBinary(this.row);
LOG.error(errMsg);
throw new WrongRowIOException(errMsg);
}
这个问题目前没找到根因,还在跟进中。