1.背景

由于种种原因,最近将核心业务生产使用的HBase迁移到了云上的弹性MapReduce(EMR)集群上,并使用了EMR的HBase组件默认参数配置。

结果在流量高峰期出现了宿主机故障,挂掉了两个core节点(部署了region server和datanode),大量region rit,花了15分钟才自动恢复,硬生生吃了一个P0故障。

复盘的时候发现,由于云上EMR对hdfs的socket超时参数默认设置了900000(15min),导致了region重新上线读取故障节点WAL日志的时候足足等待了15分钟才去重试下个节点。这样的自愈时间显然是不满足「在线业务」的需求的,需要将这个超时时间调整到60000(1min),实现快速自愈的目的。

因此,结合HBase自身组件特性与 「在线业务」高可用、低抖动 诉求,全面整理了HBase参数调优的最佳实践。

2.先回顾下HBase基础架构

这里只是简单回顾下整体架构,方便对照各个组件聊一聊需要优化的参数。更详细内容可以参考我过去整理的《全面认识HBase架构(建议收藏)

2.1 整体架构

从物理结构上,HBase包含了三种类型的server,zookeeper、HMaster、RegionServer,从而形成了一种主从模式的结构。

  • RegionServer主要用来服务读和写操作。当用户通过client访问数据时,client会和HBase RegionServer 进行直接通信。
  • HMaster主要进行RegionServer的管理、DDL(创建、删除表)操作等。
  • Zookeeper是HDFS(Hadoop Distributed File System)的一部分,主要用来维持整个集群的存活,保障了HA,故障自动转移。
  • 底层的存储,还是依赖于HDFS的。Hadoop的DataNode存储了RegionServer所管理的数据,所有HBase的数据都是存在HDFS中的。Hadoop的NameNode维护了所有物理数据块的metadata。

2.2 RegionServer组成

一个RegionServer运行在一个HDFS的DataNode上,并且拥有以下组件:

  • WAL:全称Write Ahead Log, 属于分布式系统上的文件。主要用来存储还未被持久化到磁盘上的新数据。如果新数据还未持久化,节点发生宕机,那么就可以用WAL来恢复这些数据。
  • BlockCache:是一个读缓存。它存储了被高频访问的数据。当这个缓存满了后,会清除最近最少访问的数据。
  • MenStore: 是一个写缓存。它存储了还未被写入磁盘的数据。它会在写入磁盘前,对自身数据进行排序,从而保证数据的顺序写入。每个region的每个colum family会有一份对应的memstore。
  • HFiles:按照字典序存储各个row的键值。

3.读优化

3.1 优化读/写内存比例

一个RegionServer上有一个BlockCache和N个Memstore,它们的大小之和必须小于HeapSize* 0.8,否则HBase不能启动,因为仍然要留有一些内存保证其它任务的执行。

BlockCache作为读缓存,对于读的性能比较重要,如果读比较多,建议内存使用1:4的机器,比如:8cpu32g或者16pu64g的机器。

读多写少的场景下,可以调高BlockCache的数值,降低Memstore的数值来提高读场景性能。

核心调整参数如下:

- hfile.block.cache.size = 0.5 ;
- hbase.regionserver.global.memstore.size = 0.3。

3.2 减少HFile数量

因为HBase读取时没有命中缓存,就需要打开HFile。如果HFile文件越多,IO次数就越多,读取的延迟就越高。

因此,HBase通过compaction机制来合并HFile。

但是,对于「在线业务」来说,白天流量高峰做compact会严重影响磁盘IO,造成读写毛刺,因此需要对compact限速。

3.3 开启「短路读」特性

HBase数据是存储在HDFS,从HDFS读取数据需要经过DataNode,开启Short-Circuit Local Read后,客户端可以直接读取本地数据。

假设现有两个用户User1和User2,User1拥有访问HDFS目录上/appdata/hbase1文件的权限,而User2用户没有该权限,但是User2用户又需要访问这个文件,那么可以借助UNIX中「文件描述符传递」的机制,可以让User1用户打开文件得到一个文件描述符,然后把文件描述符传递给User2用户,那么User2用户就可以读取文件里面的内容了,即使User2用户没有权限。

这种关系映射到HDFS中,可以把DataNode看作User1用户,客户端DFSClient看作User2用户,需要读取的文件就是DataNode目录中的/appdata/hbase1文件。实现如下图所示:

核心参数如下:

dfs.client.read.shortcircuit = true

3.4 开启「对冲读」特性(需要评估磁盘IO)

当我们开启「短路读」特性后,优先会通过Short-Circuit Local Read功能尝试本地读。但是在某些特殊情况下,有可能会出现因为磁盘问题或者网络问题引起的短时间本地读取失败。

为了应对这类问题,HBase实现了「对冲读」特性Hedged Read。

该机制基本工作原理为:
客户端发起一个本地读,一旦一段时间之后还没有返回,客户端将会向其他DataNode发送相同数据的请求。哪一个请求先返回,另一个就会被丢弃。

当然,这个特性显然会放大磁盘IO的压力,需要谨慎评估使用。

核心参数如下:(根据实际环境对参数进行调整)

- dfs.client.hedged.read.threadpool.size = 10 //指定有多少线程用于服务hedged reads。如果此值设置为0(默认),则hedged reads为disabled状态
- dfs.client.hedged.read.threshold.millis:默认为500(0.5秒):在spawning 第二个线程前,等待的时间。

4.写优化

4.1 增大MemStore的内存

面对「写多读少」的场景, 可以考虑调高MemStore 的内存占比,降低BlockCache的内存占比,跟读优化3.1的思路正好相反。

具体可以根据读写比例来评估。

4.2 适当增加HFile产生

本条与3.2并不冲突,需要权衡

数据写入过程中,MemStore在满足一定条件时会flush刷写到磁盘,生成一个HFile文件。当一个Store下的HFile文件数量大于某个阈值时,就会引起写入或更新阻塞。

RS日志中会有类似 “has too many store files...” 的信息。当出现这种情况时,需要等待Compaction合并以减少HFile数量,这里主要是Minor Compaction即小合并。

所以我们尽量调大这个阈值,减少compaction。

核心参数:

hbase.hstore.blockingStoreFiles = 100

如果写很快,很容易带来大量的HFile,因为此时HFile合并的速度还没有写入的速度快。

需要在业务低峰期做major compaction,充分利用系统资源。如果HFile降低不下来,则需要添加节点。

4.3 适当增大Memstore阻塞倍数

当MemStore大小达到刷写阈值(
hbase.hregion.memstore.flush.size,默认128M)时,就会flush刷写到磁盘,这个操作基本没有阻塞。但当一个Region的所有MemStore大小达到一个阻塞倍数(hbase.hregion.memstore.block.multiplier,默认值为4,即4倍的刷写阈值 默认4*128=512M)时,就会阻塞该Region所有的更新请求,并强制flush。客户端可能会抛出RegionTooBusyException异常。

为了尽量避免写入阻塞,可以适当调整这两个参数

核心参数包括:

hbase.hregion.memstore.flush.size = 128
hbase.hregion.memstore.block.multiplier = 4

5.IO优化

HBase利用compaction机制,通过大量的读延迟毛刺和一定的写阻塞,来换取整体上的读取延迟的平稳。

为了综合权衡 性能 与 稳定性,需要对compation做限速处理。

核心调整参数如下:

- hbase.offpeak.end.hour = 6 //允许不限速compact的结束时间
- hbase.offpeak.start.hour = 22 //允许不限速compact的开始时间
- hbase.hstore.compaction.throughput.higher.bound = 15728640 //限速compact最大为15M
- hbase.hstore.compaction.throughput.lower.bound = 10485760 //限速compact最小为10M
- hbase.hregion.majorcompactio = 0 //关闭定时major compaction
- hbase.regionserver.thread.compaction.large = 1 //compation线程
hbase.regionserver.thread.compaction.small = 1//compaction线程
hbase.hstore.compaction.max = 3 //一次Minor Compaction最多合并的HFile文件数

需要注意的是,白天compaction限速,并且关闭了定时major compaction后,可能会导致HFile合并不足,因此,可以考虑外部控制(如java api)定时在夜间做major compaction来减少HFile数量。

6.故障恢复优化

引起RegionServer宕机的原因各种各样,有因为Full GC导致、网络异常导致、官方Bug导致(close wait端口未关闭)以及DataNode异常导致等等。

这些场景下一旦RegionServer发生宕机,HBase都会马上检测到这种宕机,并且在检测到宕机之后会将宕机RegionServer上的所有Region重新分配到集群中其他正常RegionServer上去,再根据HLog进行丢失数据恢复,恢复完成之后就可以对外提供服务,整个过程都是自动完成的,并不需要人工介入。基本原理如下图所示:

当datanode异常时,如果读取超时设置过大(dfs.client.socket-timeout和dfs.socket.timeout),region无法正常读取WAL日志,就会导致恢复耗时增加。

核心参数如下:

dfs.client.socket-timeout = 60000
dfs.datanode.socket.write.timeout = 480000
dfs.socket.timeout = 60000

7.其他优化

7.1 split策略

HBase 2.0.0 以上版本采用的 split 策略是 SteppingSplitPolicy。

SteppingSplitPolicy 在初期 region 数量较少的时候,split 的阈值较低,会比较频繁地触发 split。

我们已经给表做了预分区,所以可以将split策略设置为固定大小(大小由参数
hbase.hregion.max.filesize 决定)

hbase.regionserver.region.split.policy = org.apache.hadoop.hbase.regionserver.ConstantSizeRegionSplitPolicy

7.2 开启rsgroup

rsgroup对于扩缩容等运维操作有很大的帮助,可以很好的控制region移动造成的影响。move_servers_rsgroup 命令的 for 循环里会将 region 逐个移动。

hbase.coprocessor.master.classes = org.apache.hadoop.hbase.rsgroup.RSGroupAdminEndpointhbase.master.loadbalancer.class = org.apache.hadoop.hbase.rsgroup.RSGroupBasedLoadBalancer

另外,为了避免rs故障导致的meta表的「重试风暴」,region漂移失败(异常opening状态),可以给meta表设置独立的rsgroup,与业务rsgroup进行隔离。同时,增大meta表的handler数量。

hbase.regionserver.metahandler.count = 400 //建议根据客户端数量进行评估设置

8、小结

本文从HBase「基础架构」出发,梳理各个组件、读写流程的参数调优,期望能满足「在线业务」的 高可用、低抖动 的需求。

如果你有其他优化经验,欢迎留言评论。

都看到最后了,原创不易,点个关注,点个赞吧~

文章持续更新,可以微信搜索「阿丸笔记 」第一时间阅读,回复【笔记】获取Canal、MySQL、HBase、JAVA实战笔记,回复【资料】获取一线大厂面试资料。

知识碎片重新梳理,构建Java知识图谱:github.com/saigu/JavaK…(历史文章查阅非常方便)

硬吃一个P0故障,「在线业务」应该如何调优HBase参数?的更多相关文章

  1. 一个简单web系统的接口性能分析及调优过程

    在测试一个简单系统接口性能压力时,压到一定数量,程序总是崩溃,查看相关机器相关数据时,CPU.内存.IO占用均不高,问题自然出现在其它地方先介绍下系统部件架构 Resin版本为:[root@local ...

  2. Windows 10 如何使用「系统还原」功能备份系统状态和配置

    https://www.sysgeek.cn/windows-10-system-restore/ 在 Windows 10 系统中,「系统还原」功能旨在创建配置快照,并在检测到系统更改时将其工作状态 ...

  3. [redis]复制机制,调优,故障排查

    在redis的安装目录下首先启动一个redis服务,使用默认的配置文件,作为主服务 ubuntu@slave1:~/redis2$ ./redis-server ./redis.conf & ...

  4. 如何将离线计算业务的成本降低65%——弹性容器服务EKS「竞价实例」上线

    在容器化的应用场景中,大数据计算是其中很大并且业务应用在逐渐增加的一个热门领域,包括越来越多的人工智能企业,都在使用容器技术来支持业务中的大量计算任务.降低成本.提升资源利用率也是当前这部分用户非常期 ...

  5. 作业帮上万个 CronJob 和在线业务混部,如何解决弱隔离问题并进一步提升资源利用率?

    作者 吕亚霖,作业帮基础架构 - 架构研发团队负责人.负责技术中台和基础架构工作.在作业帮期间主导了云原生架构演进.推动实施容器化改造.服务治理.GO 微服务框架.DevOps 的落地实践. 别路,作 ...

  6. STORM在线业务实践-集群空闲CPU飙高问题排查

    源:http://daiwa.ninja/index.php/2015/07/18/storm-cpu-overload/ 2015-07-18AUTHORDAIWA STORM在线业务实践-集群空闲 ...

  7. STORM在线业务实践-集群空闲CPU飙高问题排查(转)

    最近将公司的在线业务迁移到Storm集群上,上线后遇到低峰期CPU耗费严重的情况.在解决问题的过程中深入了解了storm的内部实现原理,并且解决了一个storm0.9-0.10版本一直存在的严重bug ...

  8. Struts2SpringHibernate整合示例,一个HelloWorld版的在线书店(项目源码+详尽注释+单元测试)

    Struts2,Spring,Hibernate是Java Web开发中最为常见的3种框架,掌握这3种框架是每个Java Web开发人员的基本功. 然而,很多初学者在集成这3个框架的时候,总是会遇到各 ...

  9. 【前端新手也能做大项目】:跟我一起,从零打造一个属于自己的在线Visio项目实战【ReactJS + UmiJS + DvaJS】(二)

    本系列教程是教大家如何根据开源js绘图库,打造一个属于自己的在线绘图软件.当然,也可以看着是这个绘图库的开发教程.如果你觉得好,欢迎点个赞,让我们更有动力去做好! 本系列教程重点介绍如何开发自己的绘图 ...

随机推荐

  1. 无意进去UIView随笔闹腾着玩 -by 胡 xu

    1 @interface UIView : UIResponder<NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem> ...

  2. 1Appium Desktop 的简单应用

    由于Appium Desktop出来了,所以使用appium要比以前简单许多,现在根据以前的文章针对Appium Desktop做下修改更新 之前文章链接:https://testerhome.com ...

  3. Solution -「51nod 1584」加权约数和

    \(\mathcal{Description}\)   Link.   令 \(\sigma(n)\) 为 \(n\) 的约数之和.求: \[\sum_{i=1}^n\sum_{j=1}^n\max\ ...

  4. HTML5知识点笔记

    1.HTML是一种标记语言 2.HTML元素不区分大小写  //可以在xss绕过waf时使用 3.<code></code>为空元素标签 <code/>为自闭合标签 ...

  5. head 插件 Content-Type header [application/x-www-form-urlencoded] is not supported

    { "error": "Content-Type header [application/x-www-form-urlencoded] is not supported& ...

  6. 部署 Docker Registry 并配置认证登录

    文章目录 搭建 Docker Registry 创建本地映射目录 启动 Docker Registry 配置 Docker Registry 配置 Docker Registry 认证 启动带认证的 ...

  7. LibOpenCM3(四) VSCode IDE 环境配置

    目录 LibOpenCM3(一) Linux下命令行开发环境配置 LibOpenCM3(二) 项目模板 Makefile分析 LibOpenCM3(三) .ld文件(连接器脚本)和startup代码说 ...

  8. 从.net开发做到云原生运维(零)——序

    1. 为什么要写这个系列的文章 大家看到标题的时候肯定会感觉到困惑,这个标题里的两件事物好像并不是很搭.说到.net开发大家一般都会想到asp.net做网站,或者是wpf和winform这类桌面开发, ...

  9. 『无为则无心』Python面向对象 — 54、重写和super()函数

    目录 1.重写 2.super()函数 方式一 方式二 __mro__内置类属性说明 1.重写 在子类中如果有和父类同名的方法,则通过子类实例去调用该方法时,会调用子类中的该方法而不是父类的方法,这个 ...

  10. NSSCTF-[SWPU 2019]Network

    下载附件打开之后发现是和ascii比较像,但是尝试解码发现不是ascii,然后这里问了一下大佬然后又翻了一下自己的笔记,最后发现是TTL,这里直接上脚本, import binascii with o ...