我们有一个运行CDH5.0.2的四数据节点集群,通过Cloudera Manager parcel安装。 为了将13M用户的行导入HBase,我们编写了一个简单的Python脚本并使用了hadoop-streaming jar。它的工作效果可达100k行。然后......然后,一个接一个地,所有数据节点都崩溃了同样的消息:
The health test result for REGION_SERVER_GC_DURATION has become bad:
Average time spent in garbage collection was 44.8 second(s) (74.60%)
per minute over the previous 5 minute(s).
Critical threshold: 60.00%.
根据网络上发现的建议(例如 [1], [2], [3])之后解决问题的任何尝试都不会导致任何接近解决方案的问题。使用java堆大小“玩”是没用的。 “解决”这种情况的唯一方法是将区域服务器的垃圾收集持续时间监控周期从5'增加到50'。可以说是一种肮脏的解决方法。
我们现在没有工作人员为我们的GC使用创建监视器。我们最终会这样做,但我想知道如何将13M行导入HBase可能会导致所有区域服务器崩溃。有干净的解决方案吗?
编辑:
Datanode上的JVM选项是:
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:-CMSConcurrentMTEnabled -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled
Datanodes是运行CentOS 6.5的物理机,每台运行32Gb Ram,1Quadcore,2GHz,30Mb缓存。
以下是我们运行的Python脚本的摘录。我们填写两个表:一个用作唯一用户ID作为rowkey,一个用于用户信息的列家庭,另一个用作我们可能想要作为rowkey访问的所有信息。
#!/usr/bin/env python2.7
import sys
import happybase
import json
connection = happybase.Connection(host=master_ip)
hbase_main_table = connection.table('users_table')
hbase_index_table = connection.table('users_index_table')
header = ['ID', 'COL1', 'COL2', 'COL3', 'COL4']
for line in sys.stdin:
l = line.replace('"','').strip("\n").split("\t")
if l[header.index("ID")] == "ID":
#you are reading the header
continue
for h in header[1:]:
try:
id = str(l[header.index("ID")])
col = 'info:' + h.lower()
val = l[header.index(h)].strip()
hbase_table.put(id_au_bytes, {
col: val
})
indexed = ['COL3', 'COL4']
for typ in indexed:
idx = l[header.index(typ)].strip()
if len(idx) == 0:
continue
row = hbase_index_table.row(idx)
old_ids = row.get('d:s')
if old_ids is not None:
ids = json.dumps(list(set(json.loads(old_ids)).union([id_au])))
else:
ids = json.dumps([id_au])
hbase_index.put(idx, {
'd:s': ids,
'd:t': typ,
'd:b': 'ame'
})
except:
msg = 'ERROR '+str(l[header.index("ID")])
logging.info(msg, exc_info=True)
答案 0 :(得分:3)
目前很多人遇到的一个主要问题是java应用程序可用的RAM量已经爆炸,但是有关调优Java GC的大部分信息都是基于32位时代的经验。
我最近花了大量时间研究GC的大堆情况,以避免可怕的长时间停顿"。我好几次看了excellent presentation,最后GC以及我遇到的问题开始变得更有意义了。
我对Hadoop了解不多,但我认为您可能遇到年轻一代太小的情况。不幸的是,大多数关于JVM GC调整的信息都没有强调,你的对象成为GC的最佳位置是在年轻一代。此时几乎没有时间收集垃圾。我不打算详细说明(如果你想知道,请观看演示文稿)但是如果你的年轻(新一代)没有足够的空间,它会过早地填满。这会强制收集,一些对象将被移动到终身(旧)代。最终,终身一代填满了,也需要收集。如果您的终生代中有大量垃圾,这可能会非常缓慢,因为终身收集算法通常是标记扫描,其收集垃圾的时间非零。
我认为您正在使用Hotspot。这里是热点的各种GC参数的一个很好的参考。 JVM GC options
我首先要大大增加年轻一代的规模。我的假设是,正在创建许多短到中等生命的对象。你想要避免的是将这些提升到终身一代。你这样做的方式是延长他们在年轻一代中度过的时间。要实现这一点,您可以增加它的大小(因此需要更长的时间来填充)或增加时效阈值(基本上是对象将保留的年轻集合的数量)。暂停阈值的问题在于在年轻一代中移动对象需要时间。增加年轻一代的规模在记忆方面是低效的,但我的猜测是你有很多余地。
我已将此解决方案与缓存服务器一起使用,并且我在>中使用了少量集合。 100毫秒范围和不常见(少于一天)主要收藏品通常低于0.5秒,堆积约4GB。我们的目标是5分钟,15分钟或29天。
您可能想要考虑的另一件事是G1(垃圾优先)收集器,它最近被添加(相对而言)到HotSpot。
我对这条建议对你有多好感兴趣。祝你好运。