HBase自身具有极好的扩展性,也因此,构建扩展集群是它的天生强项之一。在实际线上应用中很多业务都运行在一个集群上,业务之间共享集群硬件、软件资源。那问题来了,一个集群上面到底应该运行哪些业务可以最大程度上利用系统的软硬件资源?另外,对于一个给定业务来说,应该如何规划集群的硬件容量才能使得资源不浪费?最后,一个给定的RegionServer上到底部署多少Region比较合适?想必这些问题都曾经困惑过很多HBaser,那本文将结合前人的分享以及笔者的经验简单的对这三个问题分别进行解析,抛砖引玉,希望大家能够针对这几个话题进行深入的交流!
集群业务规划
一般而言,一个HBase集群上很少只跑一个业务,大多数情况都是多个业务共享集群,实际上就是共享系统软硬件资源。这里通常涉及两大问题,其一是业务之间资源隔离问题,就是将各个业务在逻辑上隔离开来,互相不受影响,这个问题产生于业务共享场景下一旦某一业务一段时间内流量猛增必然会因为过度消耗系统资源而影响其他业务;其二就是共享情况下如何使得系统资源利用率最高,理想情况下当然希望集群中所有软硬件资源都得到最大程度利用。前者本次并不讨论,后期会开’专场’讨论,本节主要就后者进行探讨。
使得集群系统资源最大化利用,那首先要看业务对系统资源的需求情况。经过对线上业务的梳理,通常可将这些业务分为如下几类:
1. 硬盘容量敏感型业务:这类业务对读写延迟以及吞吐量都没有很大的要求,唯一的需要就是硬盘容量。比如大多数离线读写分析业务,上层应用一般每隔一段时间批量写入大量数据,然后读取也是定期批量读取大量数据。特点:离线写、离线读,需求硬盘容量
2. 带宽敏感型业务:这类业务大多数写入吞吐量很大,但对读取吞吐量没有什么要求。比如日志实时存储业务,上层应用通过kafka将海量日志实时传输过来,要求能够实时写入,而读取场景一般是离线分析或者在上次业务遇到异常的时候对日志进行检索。特点:在线写、离线读,需求带宽
3. IO敏感型业务:相比前面两类业务来说,IO敏感型业务一般都是较为核心的业务。这类业务对读写延迟要求较高,尤其对于读取延迟通常在100ms以内,部分业务可能要求更高。比如在线消息存储系统、历史订单系统、实时推荐系统等。特点:在(离)线写、在线读,需求内存、高IOPS介质
(而对于CPU资源,HBase本身就是CPU敏感型系统,主要用于数据块的压缩/解压缩,所有业务都对CPU有共同的需求)
一个集群想要资源利用率最大化,一个思路就是各个业务之间‘扬长避短’,合理搭配,各取所需。实际上就是上述几种类型的业务能够混合分布,建议不要将同一种类型的业务太多分布在同一个集群。因此一个集群理论上资源利用率比较高效的配置为:硬盘敏感型业务 + 带宽敏感型业务 + IO敏感型业务。
另外,集群业务规划的时候除了考虑资源使用率最大化这个问题之外,还需要考虑实际运维的需求。建议将核心业务和非核心业务分布在同一个集群,强烈建议不要将太多核心业务同时分布在同一个集群。这主要有两方面的考虑:
1. 一方面是因为‘一山不容二虎’,核心业务共享资源必然会产生竞争,一旦出现竞争无论哪个业务’落败’都不是我们愿意看到的;
2. 另一方面在特殊场景下方便运维童鞋进行降级处理,比如类似于淘宝双十一这类大促活动,某个核心业务预期会有很大的流量涌入,为了保证核心业务的平稳,在资源共享的情况下只能牺牲其他非核心业务,在和非核心业务方充分交流沟通的基础上限制这些业务的资源使用,在流量极限的时候甚至可以直接停掉这些非核心业务。试想,如果是很多核心业务共享集群的话,哪个核心业务愿意轻易让路?
那有些同学就说了:如果按照你这样设计,那岂不是会产生很多小集群。的确,这种设计会产生很多小集群,相信如果没有资源隔离的话,小集群是没法避免的。有些使用’rsgroup’进行业务资源隔离的集群会做的很大,大集群通过隔离会将业务独立分布到很多独立的RS上,这样实际上就产生了很多逻辑上的小集群,那么,这些小集群同样适用上面提出的规划思路。
集群容量规划
每个季度公司都会要求采购新机器,一般情况下机器的规格(硬盘总容量、内存大小、CPU规格)都是固定的。假如现在一台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 / 128M * 3 * 0.4 * 2 = 192,意思是说RegionServer上1bytes的Java内存大小需要搭配192bytes的硬盘大小最合理,再回到之前给出的问题,128G的内存总大小,拿出96G作为Java内存用于RegionServer,那对应需要搭配96G * 192 = 18T硬盘容量,而实际采购机器配置的是36T,说明在默认配置条件下会有几乎一半硬盘被浪费。
计算公式是如何’冒’出来的?
再回过头来看看那个计算公式是怎么’冒’出来的,其实很简单,只需要从硬盘容量纬度和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
这样的公式有什么具体意义?
1. 最直观的意义就是判断在当前给定配置下是否会有资源浪费,内存资源和硬盘资源是否匹配。
2. 那反过来,如果已经给定了硬件资源,比如硬件采购部已经采购了当前机器内存128G,分配给Java Heap为96G,而硬盘是40T,很显然两者是不匹配的,那能不能通过修改HBase配置来使得两者匹配?当然可以,可以通过增大RegionSize或者减少MemstoreSize来实现,比如将默认的RegionSize由10G增大到20G,此时Disk Size / Java Heap = 384,96G * 384 = 36T,基本就可以使得硬盘和内存达到匹配。
3. 另外,如果给定配置下内存硬盘不匹配,那实际场景下内存’浪费’好呢还是硬盘’浪费’好?答案是内存’浪费’好,比如采购的机器Java Heap可以分配到126G,而总硬盘容量只有18T,默认配置下必然是Java Heap有浪费,但是可以通过修改HBase配置将多余的内存资源分配给HBase读缓存BlockCache,这样就可以保证Java Heap并没有实际浪费。
另外,还有这些资源需要注意…
带宽资源:因为HBase在大量scan以及高吞吐量写入的时候特别耗费网络带宽资源,强烈建议HBase集群部署在万兆交换机机房,单台机器最好也是万兆网卡+bond。如果特殊情况交换机是千兆网卡,一定要保证所有的RegionServer机器部署在同一个交换机下,跨交换机会导致写入延迟很大,严重影响业务写入性能。
CPU资源:HBase是一个CPU敏感型业务,无论数据写入读取,都会因为大量的压缩解压操作,特别耗费计算资源。因此对于HBase来说,CPU越多越好。
参考:
http://hadoop-hbase.blogspot.com/2013/01/hbase-region-server-memory-sizing.html
Region规划
Region规划主要涉及到两个方面:Region个数规划以及单Region大小规划,这两个方面并不独立,而是相互关联的,大Region对应的Region个数少,小Region对应的Region个数多。Region规划相信是很多HBase运维同学比较关心的问题,一个给定规格的RegionServer上运行多少Region比较合适,在刚开始接触HBase的时候,这个问题也一直困扰着笔者。在实际应用中,Region太多或者太少都有一定的利弊:
优点 | 缺点 | |||
大量小Region |
|
| ||
少量大Region |
|
|
可以看出来,在HBase当前工作模式下,Region太多或者太少都不是一件太好的事情,在实际线上环境需要选择一个折中点。官方文档给出的一个推荐范围在20~200之间,而单个Region大小控制在10G~30G,比较符合实际情况。
然而,HBase并不能直接配置一台RegionServer上的Region数,Region数最直接取决于RegionSize的大小配置hbase.hregion.max.filesize,HBase认为,一旦某个Region的大小大于配置值,就会进行分裂。
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将会是一个灾难。
可见,对于当下的HBase,如果想让HBase工作的更加平稳(Region个数控制在20~200之间,单Region大小控制在10G~30G之间),最多可以存储的数据量差不多为200 * 30G * 3= 18T。如果存储的数据量超过18T,必然会引起或多或少的性能问题。所以说,从Region规模这个角度讲,当前单台RegionServer能够合理利用起来的硬盘容量上限基本为18T。
然而随着硬件成本的不断下降,单台RegionServer可以轻松配置40T+的硬盘容量,如果按照上述说法,越来越多的硬盘其实只是’镜中月,水中花’。社区也意识到了这样的问题,在当前Region的概念下提出了Sub-Region的概念,可以简单理解为将当前的Region切分为很多逻辑上小的Sub-Region。Region还是以前的Region,只是所有之前以Region为单位进行的Compaction将会以更小的Sub-Region粒度执行。这样,单Region就可以配置的很大,比如50G、100G,此时单台RegionServer上也就可以存储更多的数据。个人认为Sub-Region功能将会是HBase开发的一个重点。
总结
本文结合HBase相关理论知识以及笔者的实际经验,对HBase集群规划中最常见的三个问题 - 业务规划、容量规划以及Region规划做了简单的解析,希望给大家一些启发和思考。线上集群规划是一个经验积累的过程,相信每个HBase运维同学或多或少都会碰到一些坑,也肯定会有自己的思考和见解,本文是一篇转载的文章,原作者讲解的非常详细,感兴趣的同学可以直接访问上述原文连接。
============================================================================
以下记录原作者与评论之间的问答,对我很有帮助,这里我一并记录下来,再次感谢原作者,膜拜大神:
问题一:
作者你好,这个公式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可能会比较合适
问题三:
感谢您的分享,关于集群中磁盘阵列使用什么模式比较合适呢?JBOD 还是RAID 0 或者是其他的,怎么评估?
回答:
HBase磁盘阵列模式选择理论上取决于Hadoop磁盘阵列模式 通常Hadoop可能会倾向于选择JBOD 可以参考:http://zh.hortonworks.com/blog/why-not-raid-0-its-about-time-and-snowflakes/
有两点原因:
1. 坏盘影响:如果是RAID 0,一旦某个盘坏掉,需要卸载这个盘,而且必须要重新挂载一个新盘上去才能恢复读写,不然整个DN就需要从集群踢掉;而如果是JBOD,一旦某个盘坏掉,只需要卸载这个盘,集群就能自动检测到并恢复正常
2. 长尾效应:RAID 0场景下读写性能基本取决于最差的一块盘的读写性能,这个可能会有一些影响
当然实际操作中具体选择JBOD还是RAID 0需要结合公司提供的方案来定 个人觉得RAID 0短期来看更有性能优势 长远来看JBOD可能会更好
问题四:
我们每台RegionServer 挂载的硬盘是10T ,目前采用的是RAI 0磁盘阵列,数据冷热程度随着时间越来越冷并且为写多读少的场景。由于种种原因公司使用的是千兆网卡,现在极其担心某个RegionServer 挂掉,造成整个集群资源带宽不够。这个场景是不是更适合JBOD 而不是RAID 0 ?JBOD 会不会成为写入的性能瓶颈呢。
回答:
1. 一个RegionServer挂掉可能会导致集群资源不够 而且在千兆网卡条件下写性能以及scan性能都有可能带宽瓶颈 不过这个场景和JBOD以及RAID 0没关系 。
2. 所有磁盘组成RAID 0会有一个问题,就是如果一块盘性能不好或者性能下降可能会导致scan性能下降,还有就是坏盘影响。
3. 写入通常会将单台RS上的所有硬盘带宽都充分利用,通俗讲就是所有盘都在写,所以RAID 0条带化对性能提升带来的优化并不明显,所以JBOD不会成为写入性能瓶颈
问题五:JBOD能否发挥多盘并发写入性能呢?每块盘单独做RAID 0不知道是不是更好,”坏盘影响”是不是也会存在?
回答:
每块盘单独做RAID 0也可以的
问题六:
楼主,你好,如果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资源和带宽资源,对系统读写有很大的影响。分裂对写入为什么会有影响?
问题七:
我现在要做的是实时入库,我采用了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建议手动执行;
问题八:
Java Heap纬度下Region个数:Java Heap * HeapFractionForMemstore / (MemstoreSize / 2 )
对这个2感觉比较疑惑,请问下这个2代表的含义?
回答:除以2表示memstore平均只使用到一半,没有用满
问题九:一个hbase集群,对于表的个数不限定吧,反正只要所有表总的region的个数推荐范围在20~200之间,而单个Region大小控制在10G~30G,就可以是吧?
回答:对表没有限定
问题十:
我发现HBase有一个Replication机制 ,这个机制我查了下,是用于HBase集群备份用的,说有这么几个用途:
1、数据备份和容灾恢复
2、数据归集
3、数据地理分布
4、在线数据服务和线下数据分析
我有几个疑问:
1、数据备份有必要嘛?hdfs本身不就有副本功能,HBase数据肯定不会丢呀,除非hdfs服务器全部都被炸了,才可能丢数据,所以我觉得Replication机制用来数据备份应该是没啥意义吧
2、容灾恢复,我猜是不是比如我有2个机房,每个机房都是一个HBase集群,一个提供服务一个作为备份,然后第一个机房全瘫了,比如网线被挖断了,马上把第二个机房启用作为主服务,这样恢复得快
3、什么是数据地理分布?这个也没查到,可否简单说下
回答:
1. 如果使用HDFS三副本做数据备份,而且做的足够好(跨机架、跨机房),再使用replication做数据备份意义确实不大。
2. replication可能更大的作用是服务高可用
3. 数据地理分布我理解应该是异地跨机房部署吧
问题十一:“特殊场景下,一旦Region数超过一个阈值,将会导致整个RegionServer级别的flush,严重阻塞用户读写。”这里的region数超过一个阈值,是指region数多,那么memstore就会多,总量加起来超过rs总量设定的百分比,就会导致rs级别flush?亦或是rs的hlog文件数超过限制?
回答:恩 第一种理解 总实际占用的memstore大小超过rs设定的百分比 导致rs级别flush