问题分析总结:The troubleshooting of too many open file and cannot allocate memory

最近在开发大数据程序时,开发一个定时任务按规则来删除HBASE是ElasticSearch的任务,这个定时任务时间设置为每天运行几次,程序没什么问题,在做性能测试时,将定时任务设置成1s运行一次,一段时间后在服务器上运行任何命令,出现“-bash: fork: Cannot allocate memory”错误,换句话说,系统奔溃了。

分析步骤如下:

步骤一:通过VisualVM和jstatd来监控远程服务器程序JVM的动态信息

使用《运用VisualVM和jstatd来远程监控JVM虚拟机的信息》文章的配置方法,我们发现通过VisualVM界面右边的监视进程栏目中,其中的线程不断上升,截图如下所示:

步骤二:查看程序的运行日志:

java.io.FileNotFoundException: /XXXX/classes/core-site.xml (Too many open files)

at java.io.FileInputStream.open(Native Method) ~[na:1.7.0_79]

at java.io.FileInputStream.<init>(FileInputStream.java:146) ~[na:1.7.0_79]

at java.io.FileInputStream.<init>(FileInputStream.java:101) ~[na:1.7.0_79]

下面是自己的程序出错的地方(这里略去)

 

步骤三:找到自己程序出错的地方,不断分析问题,发现自己在创建Hbase的Connection连接后,使用完没有关闭。通过日志排查和记得修改和调试,发现是自己在对HDFS上的特殊配置文件映射时,没有使用单列造成的。之后就导致线程急剧上升,之后导致文件句柄数不够而出现上面错误。

步骤四:将修改的程序,打包放到服务器上继续运行,VisualVM界面右边的监视进程栏目中数量达到一个值,不在继续上升,截图如下所示:

问题分析及总结

  • Hadoop使用get(conf)创建FileSystem对象时,用完要关闭。比如FileSystem fs = FileSystem.get(conf);   fs.close();
  • Hbase中的HTable,使用完要关闭连接,例如:HTable table = new HTable(conf, Bytes.toBytes(tableName));  close();
  • Hbase中的HbaseAdmin,使用完之后要释放资源,例如:HBaseAdmin admin=new HBaseAdmin(conf); /admin.close();
  • Hbase中的Table,使用完要关闭连接:例如:Table meta_table = conn.getTable(TableName.META_TABLE_NAME); /meta_table.close();
  • Hbase中的Connection,使用完之后要关连接,例如:Connection conn = ConnectionFactory.createConnection(conf); /conn.close();
  • 配置文件映射用单列模式,例如:
private static Configuration hbaseInitConfiguration = null;

private static Object lock = new Object();

// 方法

public static Configuration initConfiguration(){

if (null == hbaseInitConfiguration){

synchronized (lock) {

if(null == hbaseInitConfiguration){

hbaseInitConfiguration = new Configuration();

// 与hbase/conf/hbase-site.xml中hbase.zookeeper.quorum配置的值相同

String hbase_zookeeper_quorum_value = ...;

hbaseInitConfiguration.set("hbase.zookeeper.quorum", hbase_zookeeper_quorum_value);  // hostname3, hostname 2, hostname 1

String hbase_zookeeper_property_client_port_value = ...;

hbaseInitConfiguration.set("hbase.zookeeper.property.clientPort", hbase_zookeeper_property_client_port_value); // 2181

String hbase_rootdir_value = ...;

hbaseInitConfiguration.set("hbase.rootdir", hbase_rootdir_value); // hdfs://SERVICE-HADOOP-XXXX/hbase

}

}

}

return hbaseInitConfiguration;

}

参考资料:

运用VisualVM和jstatd来远程监控JVM虚拟机的信息

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: