一,建立最少的列簇
1,用户表
将用户基本信息放入一个列簇中(如nickname,gender等),将好友,标签等有大量列的单独存放,这样用户表成为5个列簇
2,信息表、用户关系等基本表都改为一个列簇
调整依据:更少的列簇,更少的io
分析:一个HRegion中所有HStore中MemStore的大小总和到达阀值时就会进行flush操作(解释:可大概理解为同一个表中的所有列簇会同时flush),若是多个列簇,就会同时对多个hstore下的文件进行写入,同时牵扯到该hregion下的所有hstore文件是否需要进行合并及拆分的验证加查,及进行相应的合并及拆分操作等一连串反映。
代码如下:
long flushSize = regionInfo.getTableDesc().getMemStoreFlushSize();
if (flushSize == HTableDescriptor.DEFAULT_MEMSTORE_FLUSH_SIZE) {
flushSize = conf.getLong(“hbase.hregion.memstore.flush.size”,
HTableDescriptor.DEFAULT_MEMSTORE_FLUSH_SIZE);
this.memstoreFlushSize = flushSize;
二,建立比较合理的hregion个数,及修改hbase0.90错误
代码分析:
hbase在每次put以前,需要检查当前regionserver上的memstore是否超过总memstore阀值,如果超过,需要block住当前的写入,防止OOM,代码片段见下:
Java代码
- /**
- * Check if the regionserver's memstore memory usage is greater than the
- * limit. If so, flush regions with the biggest memstores until we're down
- * to the lower limit. This method blocks callers until we're down to a safe
- * amount of memstore consumption.
- */
- public synchronized void reclaimMemStoreMemory() {
- if (isAboveHighWaterMark()) {
- lock.lock();
- try {
- while (isAboveHighWaterMark() && !server.isStopped()) {
- wakeupFlushThread();
- try {
- // we should be able to wait forever, but we've seen a bug where
- // we miss a notify, so put a 5 second bound on it at least.
- flushOccurred.await(5, TimeUnit.SECONDS);
- } catch (InterruptedException ie) {
- Thread.currentThread().interrupt();
- }
- }
- } finally {
- lock.unlock();
- }
- } else if (isAboveLowWaterMark()) {
- wakeupFlushThread();
- }
- }
这是一个同步操作,其中isAboveHighWaterMark()的代码如下:
Java代码
- private boolean isAboveHighWaterMark() {
- return server.getGlobalMemStoreSize() >= globalMemStoreLimit;
- }
getGlobalMemStoreSize()里面的操作是遍历所有region,拿到每个region的memstore大小:
Java代码
- public long getGlobalMemStoreSize() {
- long total = 0;
- for (HRegion region : onlineRegions.values()) {
- total += region.memstoreSize.get();
- }
- return total;
- }
如果region数量很多就比较杯具了,在单台服务器3500个region的环境下通过btrace跟踪到这一步需要耗时0.4ms,也就是每一个put会block所有线程0.4ms,这样无法发挥出server端并行处理能力,同时可以计算出无论如何配置,写tps无法超过1000/0.4=2500!
产生这个问题的根本原因是在0.90.x版本中,region无法拿到regionserver的信息,因此只能通过实时计算来得到rs上总的memstore大小。在0.92.0或trunk版本中修改了HRegion的数据结构,让HRegion在初始化时得到regionserver的信息,因此可以实时记录memstore的总大小,并让每个region对象能拿到该值,于是这个isAboveHighWaterMark()就不再block住所有线程了,在region较多的场景下写性能得到较大提升。
建议 :治标手动操作将hregion大小合并到一个合理的范围
根本解决:翻看0.92的patch包,将jar包中的class文件做好备份进行替换测试。
参考于: http://koven2049.iteye.com/blog/1144526
减少hregion性能会有成倍提升,可以先进行手动合并hregion的测试