首先根据目前17台机器,50000+的QPS,而且观察磁盘的I/O利用率和CPU利用率都至关低来判断:当前的请求数量根本没有达到系统的性能瓶颈,不须要新增机器来提升性能。若是不是硬件资源问题,那么性能的瓶颈到底是什么? java
打开HBase的Web端,发现HBase下面各个RegionServer的请求数量很是不均匀,第一个想到的就是HBase的热点问题,具体到某个具体表上的请求分布以下: apache
HBase表请求分布 服务器
上面是HBase下某张表的region请求分布状况,从中咱们明显能够看到,部分region的请求数量为0,而部分的请求数量能够上百万,这是一个典型的热点问题。 网络
HBase出现热点问题的主要缘由无非就是rowkey设计的合理性,像上面这种问题,若是rowkey设计得很差,很容易出现,好比:用时间戳生 成rowkey,因为时间戳在一段时间内都是连续的,致使在不一样的时间段,访问都集中在几个RegionServer上,从而形成热点问题。 分布式
知道了问题的缘由,对症下药便可,联系应用修改rowkey规则,使rowkey数据随机均匀分布,效果以下: oop
Rowkey重定义后请求分布 性能
对于HBase来讲,rowkey的范围划定了RegionServer,每一段rowkey区间对应一个RegionServer,咱们要保证每段时间内的rowkey访问都是均匀的,因此咱们在设计的时候,尽可能要以hash或者md5等开头来组织rowkey。 测试
HBase的集群是在不断扩展的,分布式系统的最大好处除了性能外,不停服横向扩展也是其中之一,扩展过程当中有一个问题:每次扩展的机器的配置是不 同样的,通常,后面新加入的机器性能会比老的机器好,可是后面加入的机器常常被分配不多的region,这样就形成了资源分布不均匀,随之而来的就是性能 上的损失,以下: this
HBase各个RegionServer请求 spa
上图中咱们能够看到,每台RegionServer上的请求极为不均匀,多的好几千,少的只有几十
资源分配不均匀,形成部分机器压力较大,部分机器负载较低,而且部分Region过大过热,致使请求相对较集中。
迁移部分老的RegionServer上的region到新加入的机器上,使每一个RegionServer的负载均匀。经过split切分部分较大region,均匀分布热点region到各个RegionServer上。
HBase region请求分布
对比先后两张截图咱们能够看到,Region总数量从1336增长到了1426,而增长的这90个region就是经过split切分大的region获得的。而对region从新分布后,整个HBase的性能有了大幅度提升。
Region迁移的时候不能简单开启自动balance,由于balance主要的问题是不会根据表来进行balance,HBase的自动 balance只会根据每一个RegionServer上的Region数量来进行balance,因此自动balance可能会形成同张表的region 会被集中迁移到同一个台RegionServer上,这样就达不到分布式的效果。
基本上,新增RegionServer后的region调整,能够手工进行,尽可能使表的Region都平均分配到各个RegionServer上,另一点,新增的RegionServer机器,配置最好与前面的一致,不然资源没法更好利用。
对于过大,过热的region,能够经过切分的方法生成多个小region后均匀分布(注意:region切分会触发major compact操做,会带来较大的I/O请求,请务必在业务低峰期进行)
HBase写入缓慢,查看HBase日志,常常有慢日志以下:
WARN org.apache.hadoop.ipc.HBaseServer- (responseTooSlow): {“processingtimems”:36096, “call”:”multi(org.apache.hadoop.hbase.client.MultiAction@7884377e), rpc version=1, client version=29, methodsFingerPrint=1891768260″, “client”:”xxxx.xxx.xxx.xxxx:44367″, “starttimems”:1440239670790, “queuetimems”:42081, “class”:”HRegionServer”, “responsesize”:0, “method”:”multi”}
而且伴有HDFS建立block异常以下:
INFO org.apache.hadoop.hdfs.DFSClient – Exception in createBlockOutputStream
org.apache.hadoop.hdfs.protocol.HdfsProtoUtil.vintPrefixed(HdfsProtoUtil.java:171)
org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.createBlockOutputStream(DFSOutputStream.java:1105)
org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.nextBlockOutputStream(DFSOutputStream.java:1039)
org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.run(DFSOutputStream.java:487)
通常地,HBase客户端的写入到RegionServer下某个region的memstore后就返回,除了网络外,其余都是内存操做,应该不会有长达30多秒的延迟,外加HDFS层抛出的异常,咱们怀疑极可能跟底层数据存储有关。
定位到多是HDFS层出现了问题,那就先从底层开始排查,发现该台机器上10块盘的空间利用率都已经达到100%。按理说,做为一个成熟的分布式 文件系统,对于部分数据盘满的状况,应该有其应对措施。的确,HDFS自己能够设置数据盘预留空间,若是部分数据盘的预留空间小于该值时,HDFS会自动 把数据写入到另外的空盘上面,那么咱们这个又是什么状况?
最终经过多方面的沟通确认,发现了主要缘由:咱们这批机器,在上线前SA已经通过处理,每块盘默认预留100G空间,因此当经过df命令查看盘使用 率为100%时,其实盘还有100G的预留空间,而HDFS层面咱们配置的预留空间是50G,那么问题就来了:HDFS认为盘还有100G空间,而且多于 50G的预留,因此数据能够写入本地盘,可是系统层面却禁止了该写入操做,从而致使数据写入异常。
解决的方法可让SA释放些空间出来便于数据写入。固然,最直接有效的就是把HDFS的预留空间调整至100G以上,咱们也正是这样作的,经过调整 后,异常再也不出现,HBase层面的slow log也没有再出现。同时咱们也开启了HDFS层面的balance,使数据自动在各个服务器之间保持平衡。
磁盘满了致使的问题很难预料,HDFS可能会致使部分数据写入异常,MySQL可能会出现直接宕机等等,因此最好的办法就是:不要使盘的利用率达到100%。
经过rowkey调整,HDFS数据balance等操做后,HBase的确稳定了许多,在很长一段时间都没有出现写入缓慢问题,总体的性能也上涨了不少。但时常会隔一段时间出现些slow log,虽然对总体的性能影响不大,但性能上的抖动仍是很明显。
因为该问题不常常出现,对系统的诊断带来不小的麻烦,排查了HBase层和HDFS层,几乎一无所得,由于在大多数状况下,系统的吞吐量都是正常 的。经过脚本收集RegionServer所在服务器的系统资源信息,也看不出问题所在,最后怀疑到系统的物理拓扑上,HBase集群的最大特色是数据量 巨大,在作一些操做时,很容易把物理机的千兆网卡都吃满,这样若是网络拓扑结构存在问题,HBase的全部机器没有部署在同一个交换机上,上层交换机的进 出口流量也有可能存在瓶颈。网络测试仍是挺简单的,直接ping就能够,咱们获得如下结果:共17台机器,只有其中一台的延迟存在问题,以下:
网络延迟测试:Ping结果
同一个局域网内的机器,延迟达到了毫秒级别,这个延迟是比较致命的,由于分布式存储系统HDFS自己对网络有要求,HDFS默认3副本存在不一样的机器上,若是其中某台机器的网络存在问题,这样就会影响到该机器上保存副本的写入,拖慢整个HDFS的写入速度。
网络问题,联系机房解决,机房的反馈也验证了咱们的想法:因为HBase的机器后面进行了扩展,后面加入的机器有一台跟其余机器不在同一个交换机下,而这台机器正是咱们找出的有较大ping延时这台,整个HBase物理结构以下:
HBase物理拓扑结构
跟机房协调,调整机器位置,使全部的HBase机器都位于同一个交换机下,问题迎刃而解。
对于分布式大流量的系统,除了系统自己,物理机的部署和流量规划也至关重要,尽可能使集群中全部的机器位于相同的交换机下(有容灾需求的应用除外),集群较大,须要跨交换机部署时,也要充分考虑交换机的出口流量是否够用,网络硬件上的瓶颈诊断起来相对更为困难。
解决了网络上面的不稳定因素,HBase的性能又获得进一步的提升,随之也带来了另外的问题。
根据应用反应,HBase会阶段性出现性能降低,致使应用数据写入缓慢,形成应用端的数据堆积,这又是怎么回事?通过一系列改善后HBase的系统较之之前有了大幅度增加,怎么还会出现数据堆积的问题?为何会阶段性出现?
HBase流量统计
从上图看,HBase平均流量QPS基本能达到12w,可是每过一段时间,流量就会降低到接近零点,同时这段时间,应用会反应数据堆积。
这个问题定位相对仍是比较简单,结合HBase的日志,很容易找到问题所在:
org.apache.hadoop.hbase.util.Sleeper – We slept 41662ms instead of 3000ms, this is likely due to a long garbage collecting pause and it’s usually bad
经过上述日志,基本上能够断定是HBase的某台RegionServer出现GC问题,致使了服务在很长一段时间内禁止访问。
HBase经过一系列的调整后,整个系统的吞吐量增长了好几倍,然而JVM的堆大小没有进行相应的调整,整个系统的内存需求变大,而虚拟机又来不及回收,最终致使出现Full GC
GC问题致使HBase整个系统的请求降低,经过适当调整JVM参数的方式,解决HBase RegionServer的GC问题。
对于HBase来讲,自己不存在单点故障,即便宕掉1,2台RegionServer,也只是使剩下几台的压力有所增长,不会致使整个集群服务能力 降低不少。可是,若是其中某台RegionServer出现Full GC问题,那么这台机器上全部的访问都会被挂起,客户端请求通常都是batch发送的,rowkey的随机分布致使部分请求会落到该台 RegionServer上,这样该客户端的请求就会被阻塞,致使客户端没法正常写数据到HBase。因此,对于HBase来讲,宕机并不可怕,但长时间 的Full GC是比较致命的,配置JVM参数的时候,尽可能要考虑避免Full GC的出现。