多region下的hbase写入问题

本文分析了HBase在高region数量环境下写入性能下降的原因,指出在0.90.x版本中,由于每次写入前需计算全局memstore大小导致性能瓶颈。升级到0.92.0版本后,通过改进数据结构提升了写性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在集群上发现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较多的场景下写性能得到较大提升。
参照[url]https://issues.apache.org/jira/browse/HBASE-3694[/url],可以以此patch为参考生成相应的0.90.x版本的patch
HBase写入机制是一个复杂但高效的过程,它涉及个组件的协同工作以确保数据的可靠性和一致性。以下是 HBase 写入数据的工作原理及流程: 当客户端发起一个写入请求时,首先需要确定目标 RegionServer。这一步骤通过查询 `hbase:meta` 表来完成,该表记录了所有 RegionRegionServer 之间的映射关系。客户端使用 `HConnection` 接口中的 `locateRegion` 方法来定位负责特定 rowkey 的 RegionServer [^4]。 一旦找到了正确的 RegionServer,客户端就会将数据发送给它。在 RegionServer 接收到数据后,并不会立即将其写入 HDFS,而是先缓存到内存中的 MemStore 中。MemStore 是每个列族(Column Family)都有一个的结构,用于临时存储新到达的数据 [^5]。 与此同时,为了保证数据的安全性,在向 MemStore 添加数据之前,HBase 还会执行写前日志(Write-Ahead Log, WAL)。这意味着所有的更改都会被记录在一个称为 HLog 文件中,这个文件位于 HDFS 上。如果发生故障导致 MemStore 数据丢失,则可以通过重放 WAL 来恢复这些数据 [^1]。 随着 MemStore 中的数据量增长,当达到一定阈值时,系统会触发 flush 操作,把 MemStore 中的内容持久化为一个新的 StoreFile 并保存至 HDFS。随着时间推移和更数据的写入,会有更的 StoreFiles 被创建出来 。 此外,HBase 还实现了 Compaction 机制,用来合并个小的 StoreFiles 成较大的文件,以此减少磁盘 I/O 并提高读取性能。Compaction 分为 Minor 和 Major 两种类型:Minor Compaction 只合并少量相邻的小文件;而 Major Compaction 则会对整个 Region 内的所有 StoreFiles 进行彻底整合 [^1]。 综上所述,HBase写入流程包括以下几个关键步骤: - 定位合适的 RegionServer。 - 将数据写入 WAL 以确保持久性。 - 把数据插入到对应的 MemStore。 - 当 MemStore 达到设定大小时执行 Flush 操作生成新的 StoreFile。 - 定期进行 Compaction 来优化存储效率和查询速度。 ```java // 示例代码 - 使用 Java API 向 HBase 表中插入数据 import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Connection; import org.apache.hadoop.hbase.client.ConnectionFactory; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.Table; import org.apache.hadoop.hbase.util.Bytes; public class HBaseWriteExample { public static void main(String[] args) throws Exception { // 创建配置对象并设置ZooKeeper相关信息 Configuration config = HBaseConfiguration.create(); config.set("hbase.zookeeper.quorum", "localhost:2181"); // 建立连接 try (Connection connection = ConnectionFactory.createConnection(config); Table table = connection.getTable(TableName.valueOf("my_table"))) { // 准备要插入的数据 Put put = new Put(Bytes.toBytes("row1")); put.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("qualifier"), Bytes.toBytes("value")); // 执行插入操作 table.put(put); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值