基于Hbase的实时计算架构

这是淘宝工程师北疯(@内涵帝)关于实时计算的一个分享。

Intro to the Hadoop Stack @ April 2011 JavaMUG

使用C++(通过Thrift)访问/操作/读写Hbase

原文链接:http://www.codelast.com/?p=3303

原文作者Darran zhang,现就职于上海某互联网公司。在这篇文章中作者详细记录了他使用C++通过Trift来访问操作HBase的一个实例,对于使用c++来开发HBase客户端应用有很好的参考价值。

————————————– 毫无理由的分割线 ———————————

无奈,网上关于C++访问Hbase的文章实在太少,所以只好自己折腾一下,然后写出来了。
要使用C++访问Hbase,可以走的途径少之又少,据说当前最好的方法就是通过Thrift来实现:http://thrift.apache.org/

所以本文分成几部分:(1)安装Thrift;(2)用Thrift 生成访问Hbase所需的C++文件;(3)在程序中通过Thrift来访问Hbase。

另外,本文只包含读写Hbase数据的例子,不包含配置Hbase的方法,如需这些内容,请自行搜索。

首先声明一下,本文基于以下环境:
操作系统:RHEL 5.3,64位
Thrift 版本:0.7.0
要访问的 Hbase 版本:0.20.6

我使用0.90.4的 Hbase 安装包来生成C++所需的Hbase.h等文件(用新版的应该能兼容旧版的)

下面开始,一步步来。
Read more of this post

HBase随机写以及随机读性能测试

原文链接:http://blog.bluedavy.com/?p=309

原文作者林昊,花名毕玄,淘宝高级技术专家。在这篇文章中和我们分享了最近他对HBase的一些随机读写的测试结果

————————————– 毫无理由的分割线 ———————————

根据最近生产环境使用的经验,更多的项目的采用,以及采用了更加自动的测试平台,对HBase做了更多的场景的测试,在这篇blog中来分享下纯粹的随机写和随机读的性能数据,同时也分享下我们调整过后的参数。

测试环境说明:
1、Region Server: 5台,12块1T SATA盘(7200 RPM),No Raid,物理内存24G,CPU型号为E5620;
启动参数为:-Xms16g -Xmx16g -Xmn2g -XX:SurvivorRatio=2 -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=85
2、Data Node:35台,和Region Server同样的硬件配置,启动参数上-Xms2g -Xmx2g,未设置-Xmn;

服务端参数:
hbase.replication false
hbase.balancer.period 1200000
hfile.block.cache.size 0.4,随机读20%命中场景使用0.01
hbase.regionserver.global.memstore.upperLimit 0.35
hbase.hregion.memstore.block.multiplier 8
hbase.server.thread.wakefrequency 100
hbase.regionserver.handler.count 300
hbase.master.distributed.log.splitting false
hbase.regionserver.hlog.splitlog.writer.threads 3
hbase.hregion.max.filesize 1073741824
hbase.hstore.blockingStoreFiles 20
hbase.hregion.memstore.flush.size 134217728

客户端参数:
hbase.client.retries.number 11
hbase.client.pause 20
hbase.ipc.client.tcpnodelay true
ipc.ping.interval 3000

最终随机写的测试性能结果如下(点开可看大图):

Read more of this post

多region下的hbase写入问题

原文链接:http://koven2049.iteye.com/blog/1144526

本文作者淘宝竹庄,在这篇文章中研究了单台regionserver中region数量太多导致的写入性能问题。

————————————– 毫无理由的分割线 ———————————

最近在集群上发现hbase写入性能受到较大下降,测试环境下没有该问题产生。而生产环境和测试环境的区别之一是生产环境的region数量远远多于测试环境,单台regionserver服务了约3500个region。

通过jstack工具检查到大半写入线程BLOCKED状态在”public synchronized void reclaimMemStoreMemory() {“这一行,这是在put之前的一个检查过程。

hbase在每次put以前,需要检查当前regionserver上的memstore是否超过总memstore阀值,如果超过,需要block住当前的写入,防止OOM,代码片段见下:

/**
   * 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()的代码如下:

private boolean isAboveHighWaterMark() {
  return server.getGlobalMemStoreSize() >= globalMemStoreLimit;
}

getGlobalMemStoreSize()里面的操作是遍历所有region,拿到每个region的memstore大小:

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较多的场景下写性能得到较大提升。

参照https://issues.apache.org/jira/browse/HBASE-3694,可以以此patch为参考生成相应的0.90.x版本的patch

HBase上应用lucene创建索引及检索

原文链接:http://koven2049.iteye.com/blog/1129994

本文作者淘宝竹庄,在这篇文章中试验了采用lucene创建索引的方案,究竟是否靠谱,先一窥究竟,再等待时间的检验吧。

————————————– 毫无理由的分割线 ———————————

HBasene(https://github.com/akkumar/hbasene)是开源项目,在hbase存储上封装使用Lucene来创建索引,代码API非常简单,熟悉lucene的朋友可以很方便地创建。

以下为测试代码,完成读取一张hbase上记录url和用户id的表,对其创建索引并进行简单的基于url的索引的代码。当取到search的结果后,就可以拿到想要的数据了。由于分词后将原始内容进行了反向索引,所以匹配就转化为了查询,速度相当快。

其中getDocumentFromHTable为读取一张hbase上己有的表,将url字段提取出来创建content索引。

创建索引的实质是用了HBaseIndexWriter和HBaseIndexReader两个分别继承自IndexWriter和IndexReader的类来做索引的读取和写入。同时使用了HBaseIndexStore来做存储。

而创建索引使用的分词等仍然是使用标准的lucene API。

注意hbasene使用的是hbase-0.20.5,需要修改少量源代码才能运行在0.90.x以上的版本中。

这里对创建索引表使用到的结构做下简单的说明,因为是lucene入门级水平,所以各位请尽管拍砖讨论。

索引表由以下几个CF构成:

  • fm.sequence: 记录sequenceId,在执行createLuceneIndexTable时需要写死该CF的row为sequenceId,qulifier为qual.sequence,值为-1。可以不用理会
  • fm.doc2int: DocumentId,每个document都会有一个这样的id,如果Field.Store设置为YES,则能在索引表中查询到该id并得到完整的内容。
  • fm.termVector: 向量偏移,用于模糊查找,记录偏移量等信息
  • fm.termFrequency:分词后的关键词在每个document中出现的频率,qulifier为documentId,value为出现次数
  • fm.fields:记录了content内容,row为documentId,value为document的全文内容,它和fm.docint是相反的,后者是反向索引。
  • fm.payloads:扩展CF,目前还没有用到

Read more of this post

关于HFile的思考

原文链接:http://blog.data-works.org/2011/07/关于HFile的思考/

原文作者郭鹏,国内Cassandra领域的先驱者和实践者。资深软件开发工程师,擅长分布式应用程序的开发和使用,实践经验极其丰富。新浪微博:@逖靖寒

————————————– 毫无理由的分割线 ———————————

0.90.x版本的HBase中的文件是存储在HFile中的。

关于HFile文件的详细介绍,可以查看这篇文章:http://www.data-works.org/download/hfile.pdf

这篇文章中介绍了以下五点内容:

HFile的作用。
HFile的格式。
HFile的性能。
HFile的使用注意事项。
HFile的编程接口。
HFile中有一个很重要的参数,那就是block size。如果我们写入hfile中的某一个value的值大于block size会怎么样?

Read more of this post

HBase中的时间维度

原文链接:http://outerthought.org/blog/417-ot.html

原文是Bruno Dumon在一年前写的,现在看了还是有很多启发,因此简单的翻译一下,可能有理解不准确的地方,强烈推荐看原文。

————————————– 毫无理由的分割线 ———————————

HBase是一个类Bigtable系统,按照Google的论文对Bigtable的定义是“一种稀疏的,分布式的,持久的多为维度的有序Map。这个Map由row key,column key和timestamp做为索引,Map中的值是连续的byte数组”。HBase的多维度,包括table和column family等。

不是所有维度都是等同的,不同的维度有其特殊的意义。例如,row这个维度用于region切分,所以可以增长到海量。而column则不用于分片,和row不同的是,一个row中的多个columns的put或者delete操作是一个原子事务(当然,同一个原子事务中不可能同事put和delete)。而这篇文章将重点关注时间维度。

1. 基本概念

在Bigtable论文中,一个{row key,column key}对应的是一个cell。每个cell可能包含多个版本的数据,以timestamp索引,这就是本文要讲述的时间索引。

1.1 时间/版本维度中的key

Row key)和column key(在HBase中也称为qualifier)是bytes类型,而时间维度的key则是long integer类型,比较典型的是使用 java.util.Date.getTime()或者System.currentTimeMillis()来做为时间维度的key。

时间维度的各个版本是倒序排列后存储的,所以从storefile中读取的时候,最先读到的就是最新的时间,这个特性在系统设计的时候如果能有效利用,会非常有用。

下面我们从几个核心操作get,put和delete来看看时间维度的具体细节。

Read more of this post

HBase-0.90.4的主要更新

原文链接:http://koven2049.iteye.com/blog/1125557

本文作者淘宝竹庄,为我们带来了HBase即将release的0.90.4版本的主要更新信息。0.90.4版本主要是解决一些bug,对于性能并没有做太多显著的改进。

————————————– 毫无理由的分割线 ———————————

apache邮件列表中提到0.90.4己经准备release了,看了一下所有的patch,这个版本在性能改进上基本没有改进,主要是对很多异常下bug的修复,其中比较重要的bug有以下几个:

1 https://issues.apache.org/jira/browse/HBASE-3820 —-Splitlog() executed while the namenode was in safemode may cause data-loss
在执行splitlog的时候,如果namenode因为未知原因进入safemode,可能导致数据丢失,需要先检查并等待safemode结束

2 https://issues.apache.org/jira/browse/HBASE-3914 —-ROOT region appeared in two regionserver’s onlineRegions at the same time
root region有可能被分配给两台region server(条件:当root 所在的rs挂掉,master在assign的时候也正好挂掉)

3 https://issues.apache.org/jira/browse/HBASE-3892 —-Table can’t disable
在split期间执行disable table有可能会导致无限期挂起,实际应用中这会比较危险。比如管理员在做ddl操作时可能会因为这个bug引起table不可用时间变得很长

4 https://issues.apache.org/jira/browse/HBASE-3988 —-Infinite loop for secondary master
seconde master无法自动接管primary master的bug

5 https://issues.apache.org/jira/browse/HBASE-3969 —-Outdated data can not be cleaned in time
当compaction队列过长时,有可能因为队列优先级问题导致一些major compaction任务长期无法执行。patch的提供者遇到过好几次超过2天还没有执行一个major compaction任务。因此做了优先级的调整

6 https://issues.apache.org/jira/browse/HBASE-4028 —-Hmaster crashes caused by splitting log.
Hmaster在splitlog时对内存的计算在多线程下统计不准确,从而最终导致无法控制内存而oom

7 https://issues.apache.org/jira/browse/HBASE-3906 —-When HMaster is running,there are a lot of RegionLoad instances(far greater than the regions),it has risk of OOME.
减少hmaster启动时候的无谓的内存消耗,patch提供者在实际应用中减少了3GB的内存。(值得注意的是这个patch的提供者是华为的兄弟)

其它还有很多修复的bug都是在比较特殊情况下产生的,通常是没有检查对象为空而引起的npe,比如4088等。由这点看出来分布式系统设计的难度还是很高的,一个完整的程序需要不断地fix bug…

HBase: The Definitive Guide 官方预览

感谢@陈晟-Sean的微博消息。

Lars George的《HBase: The Definitive Guide》应该是本年度HBase最引人注目的重头技术书,据说八月份将正式发售。现在已经放出了官方预览章节,有兴趣的赶紧点这里一睹为快

不知道国内有哪家出版社计划引进了么?