//hbase集群业务规划,集群容量规划,Region规划,
引出问题:
1、一个集群上面到底应该运行哪些业务可以最大程度上利用系统的软硬件资源?
2、另外,对于一个给定业务来说,应该如何规划集群的硬件容量才能使得资源不浪费?
3、最后,一个给定的RegionServer上到底部署多少Region比较合适?想必这些问题都曾经困惑过很多HBaser,
集群业务规划
1、一个HBase集群上很少只跑一个业务,大多数情况都是多个业务共享集群,实际上就是共享系统软硬件资源。
2、其一是业务之间资源隔离问题,就是将各个业务在逻辑上隔离开来,互相不受影响,这个问题产生于业务共享场景下一旦某一业务一段时间内流量猛增必然会因为过度消耗系统资源而影响其他业务;
3、其二就是共享情况下如何使得系统资源利用率最高,理想情况下当然希望集群中所有软硬件资源都得到最大程度利用。
使得集群系统资源最大化利用,那首先要看业务对系统资源的需求情况。
1、硬盘容量敏感型业务
//这类业务对读写延迟以及吞吐量都没有很大的要求,唯一的需要就是硬盘容量。
//上层应用一般每隔一段时间批量写入大量数据,然后读取也是定期批量读取大量数据。
//特点:离线写、离线读,需求硬盘容量
2、带宽敏感型业务
//这类业务大多数写入吞吐量很大,但对读取吞吐量没有什么要求。比如日志实时存储业务,
//上层应用通过kafka将海量日志实时传输过来,要求能够实时写入,而读取场景一般是离线分析或者在上次业务遇到异常的时候对日志进行检索。
//特点:在线写、离线读,需求带宽 (elk+kafka)
3、io敏感性业务
//IO敏感型业务一般都是较为核心的业务。
//这类业务对读写延迟要求较高,尤其对于读取延迟通常在100ms以内,部分业务可能要求更高。
//比如在线消息存储系统、历史订单系统、实时推荐系统等。
//特点:在(离)线写、在线读,需求内存、高IOPS介质
提示:
而对于CPU资源,HBase本身就是CPU敏感型系统,主要用于数据块的压缩/解压缩,所有业务都对CPU有共同的需求
小结:
1、一个集群想要资源利用率最大化,一个思路就是各个业务之间‘扬长避短’,合理搭配,各取所需。
2、实际上就是上述几种类型的业务能够混合分布,建议不要将同一种类型的业务太多分布在同一个集群。
3、因此一个集群理论上资源利用率比较高效的配置为:硬盘敏感型业务 + 带宽敏感型业务 + IO敏感型业务。
4、建议将核心业务和非核心业务分布在同一个集群,强烈建议不要将太多核心业务同时分布在同一个集群。(考虑到运维方面)
//核心业务共享资源一定会产生竞争(无论哪个落败,都不是我们希望看见的),在一定的时候,为了保证核心业务的平稳处理,在资源共享的情况下只能牺牲其他非核心业务,甚至是关闭非核心业务。
弊端:这样的业务设计会产生很多小集群,很多人会采用资源隔离 rsgroup 进行业务资源隔离的集群(来减少小集群的数量),大集群通过隔离会将业务独立分布到很多独立的RS上,这样实际上就产生了很多逻辑上的小集群,那么,这些小集群同样适用上面提出的规划思路。
集群容量的规划 //重点
假如现在一台RegionServer的硬盘规格是3.6T * 12,总内存大小为128G,从理论上来说这样的配置是否会有资源浪费?如果有的话是硬盘浪费还是内存浪费?那合理的硬盘/内存搭配应该是什么样?和哪些影响因素有关?
这里需要提出一个’Disk / Java Heap Ratio’的概念,意思是说一台RegionServer上1bytes的Java内存大小需要搭配多大的硬盘大小最合理。在给出合理的解释在前,先把结果给出来:
Disk Size / Java Heap = RegionSize / MemstoreSize ReplicationFactor HeapFractionForMemstore * 2
按照默认配置,RegionSize = 10G,对应参数为hbase.hregion.max.filesize;MemstoreSize = 128M,对应参数为hbase.hregion.memstore.flush.size;ReplicationFactor = 3,对应参数为dfs.replication;HeapFractionForMemstore = 0.4,对应参数为hbase.regionserver.global.memstore.lowerLimit;
10G=10 1024M 1024B 1024b
———————————————————————— 30.42=192b
128M=1281024B1024b
计算为:10G / 128M 3 0.4 2 = 192,意思是说RegionServer上1bytes的Java内存大小需要搭配192bytes的硬盘大小最合理,再回到之前给出的问题,128G的内存总大小,拿出96G作为Java内存用于RegionServer(这里有个公式就是RS内存为系统内存的2/3 1282/3约等于85.4,rs内存为系统内存的3/4 128*3/4 = 96G 还有一种情况是,留给固定系统内存为32G, 剩余的都给rs内存我本人比较倾向于 当内存大的情况下给系统内存为32G,内存小的时候,可以分配介于2/3~3/4之间),那对应需要搭配96G * 192 = 18T硬盘容量,而实际采购机器配置的是36T,说明在默认配置条件下会有几乎一半硬盘被浪费。
提示:
cdh中
hbase.regionserver.global.memstore.lowerLimit = 0.95 默认值 0.95
//flush算法会首先按照Region大小进行排序,再按照该顺序依次进行flush,直至总Memstore大小低至lowerlimit。
10G=101024M1024B1024b
———————————————————————— 30.952=456b
128M=1281024B1024b
按照cdh默认配置是算法的话 96G * 465 = 43T
注意:当我们在cdh中设置
Memstore 刷新的低水位线
hbase.regionserver.global.memstore.size.lower.limit,
hbase.regionserver.global.memstore.lowerLimit = 0.4 的话,cdh出现警告:
Setting Memstore 刷新的低水位线 to 0.9 or lower can cause performance issues due to under-utilization of available memory.//将Memstore刷新的低水位线设置为0.9或更低可能会因可用内存利用不足而导致性能问题。 当我们内存大的话,遵循:
hbase.regionserver.global.memstore.lowerLimit,一般lowerLimit比upperLimit小5%。
有些参数需要在大内存下进行测试
当我在设置成
hbase.regionserver.global.memstore.upperLimit设置为0.45,
hbase.regionserver.global.memstore.lowerLimit设置为0.40
出现报错为:
Exception in thread "main" java.lang.RuntimeException: Current heap configuration for MemStore and BlockCache exceeds the threshold required for successful cluster operation. The combined value cannot exceed 0.8. Please check the settings for hbase.regionserver.global.memstore.size and hfile.block.cache.size in your configuration. hbase.regionserver.global.memstore.size is 0.45 hfile.block.cache.size is 0.4
at org.apache.hadoop.hbase.io.util.HeapMemorySizeUtil.checkForClusterFreeMemoryLimit(HeapMemorySizeUtil.java:85)
at org.apache.hadoop.hbase.HBaseConfiguration.addHbaseResources(HBaseConfiguration.java:82)
at org.apache.hadoop.hbase.HBaseConfiguration.create(HBaseConfiguration.java:96)
at org.apache.hadoop.hbase.regionserver.HRegionServer.main(HRegionServer.java:2716)
意思是说:
MemStore和BlockCache的当前堆配置超出了成功集群操作所需的阈值。 合并值不能超过0.8。 请检查配置中hbase.regionserver.global.memstore.size和hfile.block.cache.size的设置。 hbase.regionserver.global.memstore.size为0.45 hfile.block.cache.size为0.4
也就是 说
HFile 块缓存大小
hfile.block.cache.size = 0.4 默认
hbase.regionserver.global.memstore.upperLimit = 0.4 默认
但是HBase的硬规定却是按照这个参数计算的,这个参数的值加上hbase.regionserver.global.memstore.upperLimit的值不能大于0.8,上文提到hbase.regionserver.global.memstore.upperLimit值设置为0.4,因此,hfile.block.cache.size必须设置为一个小于0.14的任意值。
//实际操作为:
hbase.regionserver.global.memstore.upperLimit = 0.45
hbase.regionserver.global.memstore.lowerLimit = 0.4
hfile.block.cache.size + hbase.regionserver.global.memstore.upperLimi 不能大于0.8
hfile.block.cache.size = 0.35
成功
以上这个问题,hbase内存规划(读多写少型和写多读少型) 中的案例二:读多写少型 + BucketCache
https://blog.51cto.com/12445535/2373788
上面的计算公式怎么来的?
其实很简单,只需要从硬盘容量纬度和Java Heap纬度两方面计算Region个数,再令两者相等就可以推导出来,如下:
硬盘容量纬度下Region个数:Disk Size / (RegionSize *ReplicationFactor)
Java Heap纬度下Region个数:Java Heap HeapFractionForMemstore / (MemstoreSize / 2 )
Disk Size / (RegionSize *ReplicationFactor) = Java Heap HeapFractionForMemstore / (MemstoreSize / 2 )
=> Disk Size / Java Heap = RegionSize / MemstoreSize ReplicationFactor HeapFractionForMemstore * 2
这样的公式有什么具体意义?
- 最直观的意义就是判断在当前给定配置下是否会有资源浪费,内存资源和硬盘资源是否匹配。
- 那反过来,如果已经给定了硬件资源,比如硬件采购部已经采购了当前机器内存128G,分配给Java Heap为96G,而硬盘是40T,很显然两者是不匹配的,那能不能通过修改HBase配置来使得两者匹配?当然可以,可以通过增大RegionSize或者减少MemstoreSize来实现,比如将默认的RegionSize由10G增大到20G,此时Disk Size / Java Heap = 384,96G * 384 = 36T,基本就可以使得硬盘和内存达到匹配。//如果不匹配的话,就要去调整【增大RegionSize或者减少MemstoreSize来实现】
- 另外,如果给定配置下内存硬盘不匹配,那实际场景下内存’浪费’好呢还是硬盘’浪费’好?答案是内存’浪费’好,比如采购的机器Java Heap可以分配到126G,而总硬盘容量只有18T,默认配置下必然是Java Heap有浪费,但是可以通过修改HBase配置将多余的内存资源分配给HBase读缓存BlockCache,这样就可以保证Java Heap并没有实际浪费。
另外,还有这些资源需要注意…
带宽资源:
1、因为HBase在大量scan以及高吞吐量写入的时候特别耗费网络带宽资源,
2、强烈建议HBase集群部署在万兆交换机机房,单台机器最好也是万兆网卡+bond。
3、如果特殊情况交换机是千兆网卡,一定要保证所有的RegionServer机器部署在同一个交换机下,跨交换机会导致写入延迟很大,严重影响业务写入性能。
CPU资源:
1、HBase是一个CPU敏感型业务,无论数据写入读取,都会因为大量的压缩解压操作,特别耗费计算资源。因此对于HBase来说,CPU越多越好。
参考:
http://hadoop-hbase.blogspot.com/2013/01/hbase-region-server-memory-sizing.html
Region规划
1、Region规划主要涉及到两个方面:Region个数规划以及单Region大小规划,这两个方面并不独立,而是相互关联的,
2、大Region对应的Region个数少,小Region对应的Region个数多。
3、Region规划相信是很多HBase运维同学比较关心的问题,一个给定规格的RegionServer上运行多少Region比较合适,在刚开始接触HBase的时候,这个问题也一直困扰着笔者。在实际应用中,Region太多或者太少都有一定的利弊:
大量小Region:
优点:
- 更加有利于集群之间负载分布
- 有利于高效平稳的Compaction,这是因为小Region中HFile相对较小,Compaction代价小,详情可见:Stripe Compaction http://hbasefly.com/2016/07/25/hbase-compaction-2/
缺点: - 最直接的影响:在某台RegionServer异常宕机或者重启的情况下大量小Region重分配以及迁移是一个很耗时的操作,一般一个Region迁移需要1.5s~2.5s左右,Region个数越多,迁移时间越长。直接导致failover时间很长。
- 大量小Region有可能会产生更加频繁的flush,产生很多小文件,进而引起不必要的Compaction。特殊场景下,一旦Region数超过一个阈值,将会导致整个RegionServer级别的flush,严重阻塞用户读写。
- RegionServer管理维护开销很大
少量大Region:
优点:
- 有利于RegionServer的快速重启以及宕机恢复
- 可以减少总的RCP数量
- 有利于产生更少的、更大的flush
缺点: - Compaction效果很差,会引起较大的数据写入抖动,稳定性较差
- 不利于集群之间负载均衡
小结:
//可以看出来,在HBase当前工作模式下,Region太多或者太少都不是一件太好的事情,在实际线上环境需要选择一个折中点。官方文档给出的一个推荐范围在20~200之间,而单个Region大小控制在10G~30G,比较符合实际情况。 (我们建议region个数在100个,region大小在20G)
//HBase并不能直接配置一台RegionServer上的Region数,Region数最直接取决于RegionSize的大小配置hbase.hregion.max.filesize,HBase认为,一旦某个Region的大小大于配置值,就会进行分裂。
//可见,对于当下的HBase,如果想让HBase工作的更加平稳(Region个数控制在20~200之间,单Region大小控制在10G~30G之间),最多可以存储的数据量差不多为200 * 30G * 3= 18T。如果存储的数据量超过18T,必然会引起或多或少的性能问题。所以说,从Region规模这个角度讲,当前单台RegionServer能够合理利用起来的硬盘容量上限基本为18T。
提示:
公式:
Disk Size / Java Heap = RegionSize / MemstoreSize ReplicationFactor HeapFractionForMemstore * 2
hbase.hregion.max.filesize默认为10G,如果一台RegionServer预期运行100个Region,那单台RegionServer上数据量预估值就为:10G 100 3 = 3T。反过来想,如果一台RegionServer上想存储12T数据量,那按照单Region为10G计算,就会分裂出400个Region,很显然不合理。此时就需要调整参数hbase.hregion.max.filesize,将此值适度调大,调整为20G或者30G。而实际上当下单台物理机所能配置的硬盘越来越大,比如36T已经很普遍,如果想把所有容量都用来存储数据,依然假设一台RegionServer上分布100个Region,那么每个Region的大小将会达到可怕的120G,一旦执行Compaction将会是一个灾难。
未来新概念: Sub-Region
问题:然而随着硬件成本的不断下降,单台RegionServer可以轻松配置40T+的硬盘容量,如果按照上述说法,越来越多的硬盘其实只是’镜中月,水中花’。
1、社区也意识到了这样的问题,在当前Region的概念下提出了Sub-Region的概念
2、可以简单理解为将当前的Region切分为很多逻辑上小的Sub-Region。
3、Region还是以前的Region,只是所有之前以Region为单位进行的Compaction将会以更小的Sub-Region粒度执行
4、这样,单Region就可以配置的很大,比如50G、100G,此时单台RegionServer上也就可以存储更多的数据。
5、个人认为Sub-Region功能将会是HBase开发的一个重点。
小伙伴问的问题1:
非常好的博文; 对于 集群中服务器性能差距比较大的问题您那边有什么解决方案吗? 集群中有物理机(64个核心),有虚拟机(2核心),能不能达到让物理机承担的region个数是虚拟承担region个数的32倍,默认情况下各个regionserver承担的region个数会趋向于一致, x谢谢
答:
目前没有什么特别好的办法 只能禁用自动balance 手动迁移region~
小伙伴的问题2:
作者你好,这个公式Java Heap * HeapFractionForMemstore / (MemstoreSize / 2 ) ,为什么MemstoreSize / 2?
答:
一般认为Memstore只有一半空间充满~
问
感谢回复,还想请教下,“一半”这个值是怎么得到的,对应hbase的某个配置参数还是根据平时使用经验估计的。
另外,我们现在设备大概9T硬盘,Hbase Java Heap = 64G,写多读少场景
hbase.regionserver.global.memstore.size = 0.5
hbase.regionserver.global.memstore.size.lower.limit = 0.45
hfile.block.cache.size = 0.25
hbase.hregion.memstore.flush.size = 256M
hbase.hregion.memstore.block.multiplier = 8
hbase.hregion.max.filesize = 15G //replicate=3,最多200region
这些参数这么配置合适吗?
答:
硬盘相对来说有点小 在这样的硬盘大小下RegionSize为15G,3副本,200个Region就9T数据 建议预留一定的硬盘 所以hbase.hregion.max.filesize = 10G可能会比较合适
多谢,我们设备硬盘有10T,已经预留了~
小伙伴的问题3
感谢您的分享,关于集群中磁盘阵列使用什么模式比较合适呢?JBOD 还是RAID 0 或者是其他的,怎么评估?
答:
HBase磁盘阵列模式选择理论上取决于Hadoop磁盘阵列模式 通常Hadoop可能会倾向于选择JBOD 可以参考:http://zh.hortonworks.com/blog/why-not-raid-0-its-about-time-and-snowflakes/
为什么hdfs集群需要选择 JBOD磁盘阵列模式。
有两点原因:
- 坏盘影响:如果是RAID 0,一旦某个盘坏掉,需要卸载这个盘,而且必须要重新挂载一个新盘上去才能恢复读写,不然整个DN就需要从集群踢掉;而如果是JBOD,一旦某个盘坏掉,只需要卸载这个盘,集群就能自动检测到并恢复正常
- 长尾效应:RAID 0场景下读写性能基本取决于最差的一块盘的读写性能,这个可能会有一些影响
当然实际操作中具体选择JBOD还是RAID 0需要结合公司提供的方案来定 个人觉得RAID 0短期来看更有性能优势 长远来看JBOD可能会更好
再问:
我们每台RegionServer 挂载的硬盘是10T ,目前采用的是RAI 0磁盘阵列,数据冷热程度随着时间越来越冷并且为写多读少的场景。由于种种原因公司使用的是千兆网卡,现在极其担心某个RegionServer 挂掉,造成整个集群资源带宽不够。这个场景是不是更适合JBOD 而不是RAID 0 ?JBOD 会不会成为写入的性能瓶颈呢。
答: - 一个RegionServer挂掉可能会导致集群资源不够 而且在千兆网卡条件下写性能以及scan性能都有可能带宽瓶颈 不过这个场景和JBOD以及RAID 0没关系 。
- 所有磁盘组成RAID 0会有一个问题,就是如果一块盘性能不好或者性能下降可能会导致scan性能下降,还有就是坏盘影响。
- 写入通常会将单台RS上的所有硬盘带宽都充分利用,通俗讲就是所有盘都在写,所以RAID 0条带化对性能提升带来的优化并不明显,所以JBOD不会成为写入性能瓶颈
再问:
JBOD能否发挥多盘并发写入性能呢?每块盘单独做RAID 0不知道是不是更好,”坏盘影响”是不是也会存在?
答:
每块盘单独做RAID 0也可以的
小伙伴的问题4:
楼主,你好,如果hbase.hregion.max.filesize设置太小,那么region的分裂几率就增大了,而分裂是比较消耗资源的,进而会影响到hbase实时写入的性能;所以在我的集群上我把hbase.hregion.max.filesize设置的非常大,有100-300g大小,这样大小是我评估了我总存储量,然后在表格里设置预分区,这样regionsize* regionnum=allsize(总存储量);而且我设置了hbase.hregion.majorcompaction=0,这样虽然避免了频繁的split与major,但是你的博客中“那么每个Region的大小将会达到可怕的120G,一旦执行Compaction将会是一个灾难”,这句话是指major的合并么?我现在还没有手动major,准备挑在周末去major table 试一下,不知道会不会出现啥问题?再询问一下,像这种要存储的数据量比较大,而且要实时入库的,除了设置hbase.hregion.max.filesize避免分裂与合并,还有什么好方法么?
答:
这么大的region执行compaction会消耗大量的io资源和带宽资源,对系统读写有很大的影响。分裂对写入为什么会有影响?
//合并对读写都有影响,分裂split对写入没有影响的
再问:
我现在要做的是实时入库,我采用了flume+kafka+sparkstreaming入库hbase,每10秒一个bach,如果hbase表格正在做split或者major compaction,在region出现两种情况的同时,我的bach就会变慢,一般我的bach是5-6秒,但是在上面两种情况下,我的bach要跑1到2分钟才能跑完,而且没两分钟就出现一次,这样我streaming就永远也追不上来了,数据入库延迟越来越大。。我解决上面慢的问题就是这篇csdn的博客上解决的,https://blog.csdn.net/imgxr/article/details/80130456,好像也是您的博客?如果我开启自动split,与major compaction也能实时入库么?
答:
//自动split可以开的,不过需要做好预分区和rowkey散列;major compaction建议手动执行;
小伙伴的问题5:
Java Heap纬度下Region个数:Java Heap * HeapFractionForMemstore / (MemstoreSize / 2 )
对这个2感觉比较疑惑,请问下这个2代表的含义?
答 :
除以2表示memstore平均只使用到一半,没有用满
小伙伴的问题6:
一个hbase集群,对于表的个数不限定吧,反正只要所有表总的region的个数推荐范围在20~200之间,而单个Region大小控制在10G~30G,就可以是吧?
答:
对表没有限定
小伙伴的问题6:
我发现HBase有一个Replication机制 ,这个机制我查了下,是用于HBase集群备份用的,说有这么几个用途:
1、数据备份和容灾恢复
2、数据归集
3、数据地理分布
4、在线数据服务和线下数据分析
我有几个疑问:
1、数据备份有必要嘛?hdfs本身不就有副本功能,HBase数据肯定不会丢呀,除非hdfs服务器全部都被炸了,才可能丢数据,所以我觉得Replication机制用来数据备份应该是没啥意义吧
2、容灾恢复,我猜是不是比如我有2个机房,每个机房都是一个HBase集群,一个提供服务一个作为备份,然后第一个机房全瘫了,比如网线被挖断了,马上把第二个机房启用作为主服务,这样恢复得快
3、什么是数据地理分布?这个也没查到,可否简单说下
答:
- 如果使用HDFS三副本做数据备份,而且做的足够好(跨机架、跨机房),再使用replication做数据备份意义确实不大。
- replication可能更大的作用是服务高可用
- 数据地理分布我理解应该是异地跨机房部署吧
小伙伴的问题7:
“特殊场景下,一旦Region数超过一个阈值,将会导致整个RegionServer级别的flush,严重阻塞用户读写。”这里的region数超过一个阈值,是指region数多,那么memstore就会多,总量加起来超过rs总量设定的百分比,就会导致rs级别flush?亦或是rs的hlog文件数超过限制?
答:
恩 第一种理解 总实际占用的memstore大小超过rs设定的百分比 导致rs级别flush
参考链接:http://hbasefly.com/2016/08/22/hbase-practise-cluster-planning/
原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/191087.html