内容简介:HBase中表的基本单位是Region,日常在调用HBase API操作一个表时,交互的数据也会以Region的形式进行呈现。一个表可以有若干个Region,今天笔者就来和大家分享一下Region合并的一些问题和解决方法。在分析合并Region之前,我们先来了解一下Region的体系结构,如下图所示:
1.概述
HBase中表的基本单位是Region,日常在调用HBase API操作一个表时,交互的数据也会以Region的形式进行呈现。一个表可以有若干个Region,今天笔者就来和大家分享一下Region合并的一些问题和解决方法。
2.内容
在分析合并Region之前,我们先来了解一下Region的体系结构,如下图所示:
从图中可知,能够总结以下知识点:
-
HRegion:一个Region可以包含多个Store;
-
Store:每个Store包含一个Memstore和若干个StoreFile;
-
StoreFile:表数据真实存储的地方,HFile是表数据在HDFS上的文件格式。
如果要查看HFile文件,HBase有提供命令,命令如下:
1hbase hfile -p -f /hbase/data/default/ip_login/d0d7d881bb802592c09d305e47ae70a5/_d/7ec738167e9f4d4386316e5e702c8d3d
执行输出结果,如下图所示:
2.1 为什么需要合并Region
那为什么需要合并Region呢?这个需要从Region的Split来说。当一个Region被不断的写数据,达到Region的Split的阀值时(由属性hbase.hregion.max.filesize来决定,默认是10GB),该Region就会被Split成2个新的Region。随着业务数据量的不断增加,Region不断的执行Split,那么Region的个数也会越来越多。
一个业务表的Region越多,在进行读写操作时,或是对该表执行Compaction操作时,此时集群的压力是很大的。这里笔者做过一个线上统计,在一个业务表的Region个数达到9000+时,每次对该表进行Compaction操作时,集群的负载便会加重。而间接的也会影响应用程序的读写,一个表的Region过大,势必整个集群的Region个数也会增加,负载均衡后,每个RegionServer承担的Region个数也会增加。
因此,这种情况是很有必要的进行Region合并的。比如,当前Region进行Split的阀值设置为30GB,那么我们可以对小于等于10GB的Region进行一次合并,减少每个业务表的Region,从而降低整个集群的Region,减缓每个RegionServer上的Region压力。
2.2 如何进行Region合并
那么我们如何进行Region合并呢?HBase有提供一个合并Region的命令,具体操作如下:
1# 合并相邻的两个Region 2hbase> merge_region 'ENCODED_REGIONNAME', 'ENCODED_REGIONNAME' 3# 强制合并两个Region 4hbase> merge_region 'ENCODED_REGIONNAME', 'ENCODED_REGIONNAME', true
但是,这种方式会有一个问题,就是只能一次合并2个Region,如果这里有几千个Region需要合并,这种方式是不可取的。
2.2.1 批量合并
这里有一种批量合并的方式,就是通过编写脚本(merge_small_regions.rb)来实现,实现代码如下:
1# Test Mode: 2# 3# hbase org.jruby.Main merge_empty_regions.rb namespace.tablename <skip_size> <batch_regions> <merge?> 4# 5# Non Test - ie actually do the merge: 6# 7# hbase org.jruby.Main merge_empty_regions.rb namespace.tablename <skip_size> <batch_regions> merge 8# 9# Note: Please replace namespace.tablename with your namespace and table, eg NS1.MyTable. This value is case sensitive. 10 11require 'digest' 12require 'java' 13java_import org.apache.hadoop.hbase.HBaseConfiguration 14java_import org.apache.hadoop.hbase.client.HBaseAdmin 15java_import org.apache.hadoop.hbase.TableName 16java_import org.apache.hadoop.hbase.HRegionInfo; 17java_import org.apache.hadoop.hbase.client.Connection 18java_import org.apache.hadoop.hbase.client.ConnectionFactory 19java_import org.apache.hadoop.hbase.client.Table 20java_import org.apache.hadoop.hbase.util.Bytes 21 22def list_bigger_regions(admin, table, low_size) 23 cluster_status = admin.getClusterStatus() 24 master = cluster_status.getMaster() 25 biggers = [] 26 cluster_status.getServers.each do |s| 27 cluster_status.getLoad(s).getRegionsLoad.each do |r| 28 # getRegionsLoad returns an array of arrays, where each array 29 # is 2 elements 30 31 # Filter out any regions that don't match the requested 32 # tablename 33 next unless r[1].get_name_as_string =~ /#{table}\,/ 34 if r[1].getStorefileSizeMB() > low_size 35 if r[1].get_name_as_string =~ /\.([^\.]+)\.$/ 36 biggers.push $1 37 else 38 raise "Failed to get the encoded name for #{r[1].get_name_as_string}" 39 end 40 end 41 end 42 end 43 biggers 44end 45 46# Handle command line parameters 47table_name = ARGV[0] 48low_size = 1024 49if ARGV[1].to_i >= low_size 50 low_size=ARGV[1].to_i 51end 52 53limit_batch = 1000 54if ARGV[2].to_i <= limit_batch 55 limit_batch = ARGV[2].to_i 56end 57do_merge = false 58if ARGV[3] == 'merge' 59 do_merge = true 60end 61 62config = HBaseConfiguration.create(); 63connection = ConnectionFactory.createConnection(config); 64admin = HBaseAdmin.new(connection); 65 66bigger_regions = list_bigger_regions(admin, table_name, low_size) 67regions = admin.getTableRegions(Bytes.toBytes(table_name)); 68 69puts "Total Table Regions: #{regions.length}" 70puts "Total bigger regions: #{bigger_regions.length}" 71 72filtered_regions = regions.reject do |r| 73 bigger_regions.include?(r.get_encoded_name) 74end 75 76puts "Total regions to consider for Merge: #{filtered_regions.length}" 77 78filtered_regions_limit = filtered_regions 79 80if filtered_regions.length < 2 81 puts "There are not enough regions to merge" 82 filtered_regions_limit = filtered_regions 83end 84 85if filtered_regions.length > limit_batch 86 filtered_regions_limit = filtered_regions[0,limit_batch] 87 puts "But we will merge : #{filtered_regions_limit.length} regions because limit in parameter!" 88end 89 90 91r1, r2 = nil 92filtered_regions_limit.each do |r| 93 if r1.nil? 94 r1 = r 95 next 96 end 97 if r2.nil? 98 r2 = r 99 end 100 # Skip any region that is a split region 101 if r1.is_split() 102 r1 = r2 103 r2 = nil 104 puts "Skip #{r1.get_encoded_name} bcause it in spliting!" 105 next 106 end 107 if r2.is_split() 108 r2 = nil 109 puts "Skip #{r2.get_encoded_name} bcause it in spliting!" 110 next 111 end 112 if HRegionInfo.are_adjacent(r1, r2) 113 # only merge regions that are adjacent 114 puts "#{r1.get_encoded_name} is adjacent to #{r2.get_encoded_name}" 115 if do_merge 116 admin.mergeRegions(r1.getEncodedNameAsBytes, r2.getEncodedNameAsBytes, false) 117 puts "Successfully Merged #{r1.get_encoded_name} with #{r2.get_encoded_name}" 118 sleep 2 119 end 120 r1, r2 = nil 121 else 122 puts "Regions are not adjacent, so drop the first one and with the #{r2.get_encoded_name} to iterate again" 123 r1 = r2 124 r2 = nil 125 end 126end 127admin.close
该脚本默认是合并1GB以内的Region,个数为1000个。如果我们要合并小于10GB,个数在4000以内,脚本(merging-region.sh)如下:
1#! /bin/bash 2 3num=$1 4 5echo "[`date "+%Y-%m-%d %H:%M:%S"`] INFO : RegionServer Start Merging..." 6if [ ! -n "$num" ]; then 7 echo "[`date "+%Y-%m-%d %H:%M:%S"`] INFO : Default Merging 10 Times." 8 num=10 9elif [[ $num == *[!0-9]* ]]; then 10 echo "[`date "+%Y-%m-%d %H:%M:%S"`] INFO : Input [$num] Times Must Be Number." 11 exit 1 12else 13 echo "[`date "+%Y-%m-%d %H:%M:%S"`] INFO : User-Defined Merging [$num] Times." 14fi 15 16for (( i=1; i<=$num; i++ )) 17do 18 echo "[`date "+%Y-%m-%d %H:%M:%S"`] INFO : Merging [$i] Times,Total [$num] Times." 19 hbase org.jruby.Main merge_small_regions.rb namespace.tablename 10240 4000 merge 20 sleep 5 21done
在merging-region.sh脚本中,做了参数控制,可以循环来执行批量合并脚本。可能在实际操作过程中,批量执行一次Region合并,合并后的结果Region还是有很多(可能此时又有新的Region生成),这是我们可以使用merging-region.sh这个脚本多次执行批量合并Region操作,具体操作命令如下:
1# 默认循环10次,例如本次循环执行5次 2sh merging-region.sh 5
2.3 如果在合并Region的过程中出现永久RIT怎么办
在合并Region的过程中出现永久RIT怎么办?笔者在生产环境中就遇到过这种情况,在批量合并Region的过程中,出现了永久MERGING_NEW的情况,虽然这种情况不会影响现有集群的正常的服务能力,但是如果集群有某个节点发生重启,那么可能此时该RegionServer上的Region是没法均衡的。因为在RIT状态时,HBase是不会执行Region负载均衡的,即使手动执行balancer命令也是无效的。
如果不解决这种RIT情况,那么后续有HBase节点相继重启,这样会导致整个集群的Region验证不均衡,这是很致命的,对集群的性能将会影响很大。经过查询HBase JIRA单,发现这种MERGING_NEW永久RIT的情况是触发了HBASE-17682的BUG,需要打上该Patch来修复这个BUG,其实就是HBase源代码在判断业务逻辑时,没有对MERGING_NEW这种状态进行判断,直接进入到else流程中了。源代码如下:
1for (RegionState state : regionsInTransition.values()) { 2 HRegionInfo hri = state.getRegion(); 3 if (assignedRegions.contains(hri)) { 4 // Region is open on this region server, but in transition. 5 // This region must be moving away from this server, or splitting/merging. 6 // SSH will handle it, either skip assigning, or re-assign. 7 LOG.info("Transitioning " + state + " will be handled by ServerCrashProcedure for " + sn); 8 } else if (sn.equals(state.getServerName())) { 9 // Region is in transition on this region server, and this 10 // region is not open on this server. So the region must be 11 // moving to this server from another one (i.e. opening or 12 // pending open on this server, was open on another one. 13 // Offline state is also kind of pending open if the region is in 14 // transition. The region could be in failed_close state too if we have 15 // tried several times to open it while this region server is not reachable) 16 if (state.isPendingOpenOrOpening() || state.isFailedClose() || state.isOffline()) { 17 LOG.info("Found region in " + state + 18 " to be reassigned by ServerCrashProcedure for " + sn); 19 rits.add(hri); 20 } else if(state.isSplittingNew()) { 21 regionsToCleanIfNoMetaEntry.add(state.getRegion()); 22 } else { 23 LOG.warn("THIS SHOULD NOT HAPPEN: unexpected " + state); 24 } 25 } 26 }
修复之后的代码如下:
1for (RegionState state : regionsInTransition.values()) { 2 HRegionInfo hri = state.getRegion(); 3 if (assignedRegions.contains(hri)) { 4 // Region is open on this region server, but in transition. 5 // This region must be moving away from this server, or splitting/merging. 6 // SSH will handle it, either skip assigning, or re-assign. 7 LOG.info("Transitioning " + state + " will be handled by ServerCrashProcedure for " + sn); 8 } else if (sn.equals(state.getServerName())) { 9 // Region is in transition on this region server, and this 10 // region is not open on this server. So the region must be 11 // moving to this server from another one (i.e. opening or 12 // pending open on this server, was open on another one. 13 // Offline state is also kind of pending open if the region is in 14 // transition. The region could be in failed_close state too if we have 15 // tried several times to open it while this region server is not reachable) 16 if (state.isPendingOpenOrOpening() || state.isFailedClose() || state.isOffline()) { 17 LOG.info("Found region in " + state + 18 " to be reassigned by ServerCrashProcedure for " + sn); 19 rits.add(hri); 20 } else if(state.isSplittingNew()) { 21 regionsToCleanIfNoMetaEntry.add(state.getRegion()); 22 } else if (isOneOfStates(state, State.SPLITTING_NEW, State.MERGING_NEW)) { 23 regionsToCleanIfNoMetaEntry.add(state.getRegion()); 24 }else { 25 LOG.warn("THIS SHOULD NOT HAPPEN: unexpected " + state); 26 } 27 } 28 }
但是,这里有一个问题,目前该JIRA单只是说了需要去修复BUG,打Patch。但是,实际生产情况下,面对这种RIT情况,是不可能长时间停止集群,影响应用程序读写的。那么,有没有临时的解决办法,先临时解决当前的MERGING_NEW这种永久RIT,之后在进行HBase版本升级操作。
办法是有的,在分析了MERGE合并的流程之后,发现HBase在执行Region合并时,会先生成一个初始状态的MERGING_NEW。整个Region合并流程如下:
从流程图中可以看到,MERGING_NEW是一个初始化状态,在Master的内存中,而处于Backup状态的Master内存中是没有这个新Region的MERGING_NEW状态的,那么可以通过对HBase的Master进行一个主备切换,来临时消除这个永久RIT状态。而HBase是一个高可用的集群,进行主备切换时对用户应用来说是无感操作。因此,面对MERGING_NEW状态的永久RIT可以使用对HBase进行主备切换的方式来做一个临时处理方案。之后,我们在对HBase进行修复BUG,打Patch进行版本升级。
3.总结
HBase的RIT问题,是一个比较常见的问题,在遇到这种问题时,可以先冷静的分析原因,例如查看Master的日志、仔细阅读HBase Web页面RIT异常的描述、使用hbck命令查看Region、使用fsck查看HDFS的block等。分析出具体的原因后,我们在对症下药,做到大胆猜想,小心求证。
4.结束语
长按关注,获取更多干货
这篇博客就和大家分享到这里,如果大家在研究学习的过程当中有什么问题,可以加群进行讨论或发送邮件给我,我会尽我所能为您解答,与君共勉!
博主出版了《Hadoop大数据挖掘从入门到进阶实战》,喜欢的朋友或同学, 可以去购买博主的书进行学习,在此感谢大家的支持。
以上所述就是小编给大家介绍的《HBase Region 合并分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 数据分析之Pandas合并操作总结
- 不容错过的Pandas小技巧:万能转格式、轻松合并、压缩数据,让数据分析更高效
- 分组字符合并SQL语句 按某字段合并字符串之一(简单合并)
- git 的合并原理(递归三路合并算法)
- git 合并策略
- 算法 - 合并若干有序文件
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
VISUAL FOXPRO程序设计实用教程习题解答与实验指导
康萍 / 中国经济出版社 / 2006-6 / 22.80元
本书为康萍等主编的《VisUal FosxPro程序设计实用教程》的配套习题解答与实验指导教材,由常年工作在计算机教学第一线的教师组织编写。全书共分为三部分:第1部分为实验指导,包括33个实验,分别讲述了每个实验的实验目的.实验内容和操作步骤;第2部分为开发实例,介绍了图书营理系统的分析、设计与实现过程;第3部分为配套教材各章节习题参考答案。 本书实验部分可操作性及实用性较强。系统开发案......一起来看看 《VISUAL FOXPRO程序设计实用教程习题解答与实验指导》 这本书的介绍吧!