1 前言
集群中使用的 HBase 如果是 2.0.2 版本,当发生元数据不一致的时候,尴尬的事情也许就会到来,此时既不能使用 hbck 来修复,因为这个工具不了解 HBase 2.x 的架构(详细可查看官方文档 §13.3. Upgrading from 1.x to 2.x),又不能使用官方提供的 hbck2 (详细可参考官方文档 §142.6. HBase HBCK2),因为HBase 2.0.2 时 hbck2 还不支持。
根据 hbase-operator-tools 1.1.0 版本支持的 HBase 版本,我们可以选择 HBase 2.1.6 版本(同时,HBase 版本的选择还需要考虑到服务器环境中 Hadoop 和 ZooKeeper 版本,需要与当前的这些依赖组件兼容)。
本文下面会以 HDP 环境为例,尝试将 HBase 2.0.2 的版本升级到 2.1.6 版本。首先会获取 HDP HBase 2.1.6 版本的源码,然后对其进行编译,将编译后的 tar.gz 的包再打包成 rpm 包,之后对集群的 HBase 进行升级。
编译到 tar.gz 其实就已经可以解决升级的问题了,打 rpm 包方式是可选择的。前者需要手动执行升级的操作,在升级过程中也可以针对 HBase 每个节点的服务依次单独升级;后者则可以进一步与 Ambari 集成,通过管理页面完成组件的升级。
由于环境的不同,升级 HBase 涉及到对应的版本的兼容性问题,升级前最好申请同样环境的服务器上,由源码编译到升级提前整个过程走一遍,将没有问题的包及脚本提前打包,上传到待升级的集群的服务器上,申请升级的具体时间,或者将升级的整个操作文档给负责升级的人进行。
2 编译 HBase
先获取 HBase 对应版本的源码,例如这里选择 HDP-3.1.5.6014-3-tag,编译环境需要配置 JDK8 和 Maven,将获取后的源码解压,并进入源码根目录。
这里先注释掉 hbase-shaded/hbase-shaded-with-hadoop-check-invariants/pom.xml
中如下内容(注意中间有–的需要转义)。
<!--<execution>
<id>check-jar-contents-for-stuff-with-hadoop</id>
<phase>integration-test</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>${shell-executable}</executable>
<workingDirectory>${project.build.testOutputDirectory}</workingDirectory>
<requiresOnline>false</requiresOnline>
<arguments>
<argument>ensure-jars-have-correct-contents.sh</argument>
<argument>--allow-hadoop</argument>
<argument>${hbase-client-artifacts}</argument>
</arguments>
</configuration>
</execution>-->
否则编译时可能会报如下的错误:
[ERROR] Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.6.0:exec (check-jar-contents-for-stuff-with-hadoop) on project hbase-shaded-with-hadoop-check-invariants: Command execution failed.: Process exited with an error: 1 (Exit value: 1) -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.6.0:exec (check-jar-contents-for-stuff-with-hadoop) on project hbase-shaded-with-hadoop-check-invariants: Command execution failed.
另外项目中依赖了 3.1.1.3.1.6.8-1
版本的 ZooKeeper 和 Hadoop 的,所以编译的时候最好将如下镜像添加到 Maven 的 conf/setting.xml
中
<mirror>
<id>hortonworks</id>
<name>hdp</name>
<url>https://repo.hortonworks.com/content/repositories/releases</url>
<mirrorOf>central</mirrorOf>
</mirror>
最后执行 HBase 的编译命令,编译成功后可以在 hbase-assembly/target/
下看到 hbase-2.1.6.3.1.5.6014-3-bin.tar.gz
包,后面会详细介绍如果用这个包转成 rpm 包。
mvn -U clean package -DskipTests assembly:single validate -Denforcer.skip=true
报错处理: Caused by: java.lang.AbstractMethodError: org.apache.hadoop.hbase.ipc.RpcScheduler.getMetaPriorityQueueLength()I
如果在安装启动 HMaster 时报如下的错误,通过启动的日志信息,我们也可以快速定位到问题发生在调用 org.apache.hadoop.hbase.ipc.RpcScheduler.getMetaPriorityQueueLength
时的抽象方法上。
Caused by: java.lang.AbstractMethodError: org.apache.hadoop.hbase.ipc.RpcScheduler.getMetaPriorityQueueLength()I
at org.apache.hadoop.hbase.ipc.MetricsHBaseServerWrapperImpl.getMetaPriorityQueueLength(MetricsHBaseServerWrapperImpl.java:79)
at org.apache.hadoop.hbase.ipc.MetricsHBaseServerSourceImpl.getMetrics(MetricsHBaseServerSourceImpl.java:156)
at org.apache.hadoop.metrics2.impl.MetricsSourceAdapter.getMetrics(MetricsSourceAdapter.java:200)
at org.apache.hadoop.metrics2.impl.MetricsSourceAdapter.updateJmxCache(MetricsSourceAdapter.java:183)
at org.apache.hadoop.metrics2.impl.MetricsSourceAdapter.getMBeanInfo(MetricsSourceAdapter.java:156)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.getMBeanInfo(DefaultMBeanServerInterceptor.java:1378)
... 42 more
所以我们打开 hbase-server
模块的源码 ,找到 org.apache.hadoop.hbase.ipc.MetricsHBaseServerWrapperImpl
的如下方法,查看这个方法的源码,尝试修改为如下,主要添加了对获取的 RpcScheduler 类型做进一步判断的逻辑,当其为具体的实现类时再调用 getMetaPriorityQueueLength()
方法。
@Override
public int getMetaPriorityQueueLength() {
if (!isServerStarted() || this.server.getScheduler() == null) {
return 0;
}
RpcScheduler rpcScheduler = this.server.getScheduler();
if (rpcScheduler instanceof FifoRpcScheduler || rpcScheduler instanceof SimpleRpcScheduler) {
return rpcScheduler.getMetaPriorityQueueLength();
}
return 0;
}
源码修改后,重新编译 HBase。
3 HBCK2
HBCK2 是 Apache HBase 集群的修复工具,HBase 正常运行时可能会出现一些元数据方面的问题,此时可以借助工具来修复,如果是 HBase 版本是 2.x,官方文档不再建议使用 hbck 命令来修复,而是使用 HBCK2 进行修复,因为 hbck 不了解 HBase 2.x 的新架构,使用 hbck 可能会对数据造成损害,虽然在 hbase 2.x 还附带的有 hbck(hbck 将会在 hbck 3.x 移除)。
HBCK2 与 hbck 最重要的区别是前者是要求经过 HMaster 进行修复而不是尝试在修复工具的上下文中本地进行修复。
# 访问 https://github.com/apache/hbase-operator-tools/releases
# 下载源码
wget https://github.com/apache/hbase-operator-tools/archive/refs/tags/rel/1.1.0.tar.gz
tar -zxf hbase-operator-tools-rel-1.1.0.tar.gz
cd hbase-operator-tools-rel-1.1.0
# 编译打包
mvn clean install -Dmaven.test.skip=true
# 主要是下面三个包
#find ./ -name "*.jar"
hbase-hbck2/target/hbase-hbck2-1.1.0.jar
hbase-table-reporter/target/hbase-table-reporter-1.1.0.jar
hbase-tools/target/hbase-tools-1.1.0.jar
3.1 hbase-tools
在 bin/hbase
中的 export HBASE_CLASSPATH
添加上 hbase-tools-1.1.0.jar
,例如 HDP 环境下 bin/hbase
可以如下配置
#!/bin/bash
hdp_verson='3.1.0.0-78'
BIGTOP_DEFAULTS_DIR=${BIGTOP_DEFAULTS_DIR-/etc/default}
[ -n "${BIGTOP_DEFAULTS_DIR}" -a -r ${BIGTOP_DEFAULTS_DIR}/hbase ] && . ${BIGTOP_DEFAULTS_DIR}/hbase
export HBASE_HOME=${HBASE_HOME:-/usr/hdp/$hdp_verson/hbase}
export HADOOP_HOME=${HADOOP_HOME:-/usr/hdp/$hdp_verson/hadoop}
export HADOOP_CONF=${HADOOP_HOME}/conf
export ZOOKEEPER_HOME=${ZOOKEEPER_HOME:-/usr/hdp/$hdp_verson/zookeeper}
export HBASE_CLASSPATH=$HADOOP_CONF:$HADOOP_HOME/*:$HADOOP_HOME/lib/*:$ZOOKEEPER_HOME/*:$HBASE_CLASSPATH:$HBASE_HOME/hbck2-tools/hbase-tools-1.1.0.jar
#export HBASE_CLASSPATH_PREFIX=$HBASE_HOME/hbck2-tools/hbase-table-reporter-1.1.0.jar
export HDP_VERSION=${HDP_VERSION:-$hdp_verson}
export HBASE_OPTS="-Dhdp.version=${HDP_VERSION} ${HBASE_OPTS}"
exec /usr/hdp/$hdp_verson/hbase/bin/hbase.distro "$@"
使用
# 1 合并 Region
# 主要适用于 HBase 集群每个 RegionServers 的 Region 比较多的情况,
# 以减少集群中的 Region 总数并释放 RegionServers 的整体内存资源。
# 合并为异步的
#
# <TABLE_NAME> 表名
# <TARGET_NUMBER_OF_REGIONS> 合并后的目标数
hbase org.apache.hbase.RegionsMerger <TABLE_NAME> <TARGET_NUMBER_OF_REGIONS>
# 2 MissingRegionDirsRepairTool
# 不在元数据表的 sideline region 修复工具
# 如果表的 region 不存在于元数据表(仍然有 hfile 的目录,且没有检测到 holes 情况下),它会移动存在于表目录下的 region 目录,
# 当咩有报告 _region holes_ 时,使用 HBCK2.addFsRegionsMissingInMeta 并不合适,因为它会将 region 添加到 元表中导致重叠。
# 此工具执行以下操作:
# 1) 识别 hdfs 中的 region,但不识别元数据中的 region;
# 2)对于这些 region 中的每一个,将相关的目录放在一个临时文件夹中;
# 3) 将每个 sidelined region 的 hfiles 加载到相关表中;
# sidelined region 永远不会从临时文件夹中删除。 操作员应在获得数据完整性认证后手动删除这些内容。
#
hbase org.apache.hbase.MissingRegionDirsRepairTool
3.2 hbase-table-reporter
按照 3.1 的方式配置后,使用方式如下:
cd $HBASE_HOME/
# 获取前 20% 表的 region, 使用 8 个线程的执行器池(以便我们一次扫描 8 个 region)
# -h,--help 输出此帮助信息
# -l,--limit 扫描行限制(每线程):默认无
# -f,--fraction 要读取的表 region 的分数; 0 和 1 之间:默认 1.0(全部)
# -r,--region 仅扫描指定的 region; 传递编码名称; -f 将被忽略。
# -t,--threads 并发线程数(每个 region 的线程数); 默认 1
# -Dproperty=value 要连接的zookeeper等属性;例如 -Dhbase.zookeeper.quorum=ZK0.remote.cluster.example.org
#
HBASE_CLASSPATH_PREFIX=hbck2-tools/hbase-table-reporter-1.1.0.jar \
hbase org.apache.hbase.reporter.TableReporter -t 3 -f 0.2 TABLENAME
# 执行后会在 /tmp/reporter.*.gnuplotdata 的文件
3.3 hbase-hbck2
按照 3.1 的方式配置后,使用方式如下:
#
# usage: HBCK2 [OPTIONS] COMMAND <ARGS>
# -d,--debug 使用调试输出运行
# -h,--help 输出此帮助信息
# -p,--hbase.zookeeper.property.clientPort <arg> hbase ensemble 的端口
# -q,--hbase.zookeeper.quorum <arg> hbase ensemble
# -s,--skip 跳过 hbase 版本检查 (PleaseHoldException)
# -v,--version hbck2 版本
# -z,--zookeeper.znode.parent <arg> hbase ensemble 的父 znode
#
# addFsRegionsMissingInMeta <NAMESPACE|NAMESPACE:TABLENAME>...
# -d,--force_disable 如果 disable 失败,则终止 表的 fix。
# 在 hbase:meta 中缺少 region 并仍然存在于 HDFS 目录下时使用。会在 hbase:meta
# 和 HDFS 上的 region 目录之间获取差异,对于 hbase:meta 中没有匹配的 则读取
# regioninfo 元数据并在 hbase:meta 中重新创建给定 region。Region 在 hbase:meta 中
# 以 CLOSED 状态重新创建,但不在 Master 的缓存中,并且也没有分配的可以在运行完 HBCK2 后
# 运行 assigns 命令。
# 注意:如果使用早于 2.3.0 的 hbase 版本,则需要在执行 'assigns' 输出之前滚动重启 HMaster。
# 为默认命名空间中的表 'tbl_1'、命名空间 'n1' 中的 'tbl_2' 表以及命名空间 'n2' 中的所有表
# 添加缺失 region 的示例如下:
# HBCK2 addFsRegionsMissingInMeta default:tbl_1 n1:tbl_2 n2
#
# assigns [OPTIONS] <ENCODED_REGIONNAME/INPUTFILES_FOR_REGIONNAMES>...
# -o,--override 由另一个 procedure 覆盖 ownership
# -i,--inputFiles 一个或多个 Region 的编码名
# 即使在 Master 始化期间也可以使用的 'raw' 分配(如果指定了 -skip 标志)。Skirts 协处理,
# 传递一个或多个编码的 region 名,1588230740 是 hbase:meta 区域的硬编码名称,
# 而 de00010733901a05f5a2a3a382e27dd4 是用户空间(user-space)编码 region 名的示例,
# 例如:
# HBCK2 assigns 1588230740 de00010733901a05f5a2a3a382e27dd4
# 返回创建的 AssignProcedure(s) 的 pid(s),如果没有则返回 -1。如果指定了 -i
# 或 --inputFiles 则传递一个或多个输入文件名,每个文件都包含编码的 region 名,每行一个。
# 例如:
# HBCK2 assigns -i fileName1 fileName2
#
# bypass [OPTIONS] <PID>...
# -o,--override 覆盖如果 procedure 是 running/stuck
# -r,--recursive 绕过父级及其子级,SLOW! EXPENSIVE!
# -w,--lockWait 等待指定毫秒后放弃,默认值为1
# 通过一个(或多个)procedure 的 'pid' 跳到 procedure 结束,绕过 procedure 的父级
# 也将被跳过到结束。Entities 将处于不一致状态需要手动修复,可能需要重启 Master 来清除仍然
# 持有的锁,如果程序有子级绕过失败,如果您只有一个父 pid 来完成父子 procedure,
# 请添加 'recursive'。这很慢,而且很危险,所以有选择地使用。 并不总是有效。
#
# extraRegionsInMeta <NAMESPACE|NAMESPACE:TABLENAME>...
# -f, --fix 通过删除找到的所有额外 region 来修复元数据。
# 报告 hbase:meta 上存但文件系统上没有相关目录的 region,需 hbase:meta 在线。
# 对于作为参数指定的每个表,获取 hbase:meta 和给定文件系统上的 region dirs 中
# 可用 region 之间执行差异。如果通过 --fix 选项,额外的 region 将从 Meta 中删除。
# [注意]:在决定使用 --fix 选项之前,值得检查报告额外 region 是否与现有有效region重叠,
# 如果是这样,那么 "extraRegionsInMeta --fix" 确实是最佳解决方案;否则 assigns
# 命令是更简单的解决方案,因为它会在文件系统中重新创建区域目录(如果不存在)。
# 在默认命名空间下为表 'table_1' 和 'table_2' 触发执行额外 region 报告的示例:
# HBCK2 extraRegionsInMeta default:table_1 default:table_2
# 为默认命名空间下的表 'table_1' 和命名空间 'ns1' 中的所有表触发缺失region报告的示例:
# HBCK2 extraRegionsInMeta default:table_1 ns1
# 返回作为参数传递的每个表或指定为参数的命名空间上的每个表的额外 region 列表。
#
# filesystem [OPTIONS] [<TABLENAME>...]
# -f, --fix 去除损坏的 hfile、坏连接(bad links) 和引用(references)。
# 报告损坏的 hfile、引用、断开的链接、完整性。通过 --fix 来去除损坏的文件和
# 链接,--fix 不修复完整性问题,即 'holes' 或 'orphan' region。 可传递一个
# 或多个表名以缩小检查范围。默认检查所有表并在丢失时恢复 'hbase.version',
# 这个过程仅与文件系统交互!修改后的 region 需要重新打开以接收更改。
#
# fixMeta
# 对 hbase:meta 中的错误或不一致状态进行服务端修复,在 hbase 2.2.1/2.1.6 或更新版本中可用。
# Master UI 具有匹配的新 'HBCK Report' 选项页,可保存由最近运行的 _catalogjanitor_
# 和新的 'HBCK Chore' 生成的报告。在进行任何其他修复之前,首先使 hbase:meta 保持健康是至关
# 重要的。修复 'holes'、'overlaps' 等时,在 HDFS 中创建(空)region 目录以匹配添加
# 到 hbase:meta 的 region。命令与类似名字的旧 _hbck1_ 命令不同。针对上次 catalog_janitor
# 和 hbck chore 运行生成的报告工作,如果没有什么要解决的,运行就是一个 noop。 否则 'HBCK
# Report' UI 报告问题,运行 fixMeta 将清除 hbase:meta 问题。 有关如何生成新执行的信息,
# 请查看 'HBase HBCK' UI,另见:reportMissingRegionsInMeta
#
# generateMissingTableDescriptorFile <TABLENAME>
# 试图通过生成丢失的表文件来修复孤立(orphan)表,如果表文件夹丢失或存在 `.tableinfo`(我们
# 不会覆盖现有的表描述符),则此命令将不起作用。此命令将首先检查 TableDescriptor 是否
# 缓存在 HBase Master 中,在这种情况下它将相应地恢复 `.tableinfo`。如果 TableDescriptor
# 没有缓存在 master 中,那么它将创建一个默认的 `.tableinfo` 文件,其中包含以下项目:
# - 表名
# - 根据文件系统确定的列族列表
# - TableDescriptor 和 ColumnFamilyDescriptors 的默认属性
# 如果 `.tableinfo` 文件是使用默认参数生成的,请确保稍后检查表或列族属性,并在需要时更改它们。
# 此方法不会更改 HBase 中的任何内容,只会将新的 `.tableinfo` 文件写入文件系统,orphan 表可能
# 导致例如 ServerCrashProcedures 卡住,您可能需要在生成丢失的表信息文件后修复这些问题。
#
# replication [OPTIONS] [<TABLENAME>...]
# -f, --fix 修复发现的任何 replication 问题
# 查找未删除的 replication 队列,并在传递 --fix 选项时将其删除,
# 传递表名来检查 replication barrier 并清除 --fix。
#
# reportMissingRegionsInMeta <NAMESPACE|NAMESPACE:TABLENAME>...
# 在 hbase:meta 中缺少 region 并仍然存在于 HDFS 目录下时使用, 如果用户对 hbase-2.x 集群
# 运行了 _hbck1_ 'OfflineMetaRepair' 就会发生这种情况。这是一个仅用于 CHECK 的方法,
# 设计用于报告目标并且不执行任何修复,提供了查看哪些 region(如果有)将被重新添加到 hbase:meta,
# 按相应的 table/namespace 分组。想有效地在元数据表中重新添加 region,请运行
# 'addFsRegionsMissingInMeta'。此命令需要 hbase:meta 在线, 对于作为参数指定的每个
# namespace/table 它执行 hbase:meta 中 可用 region 与 HDFS 上现有 region 目录之间的
# 比对, 没有匹配项的 region 目录在其相应表名下分组打印; 没有缺失 region 的表将显示
# "No mismatching regions" 消息。如果未指定 namespace 或 table,它将验证所有现有 region,
# 它接受多个 namespace 和 table 的组合, 即使对于默认命名空间中的表也应该包含命名空间,否则它将
# 假定一个命名空间值。
# 在默认命名空间下触发表 "table_1" 和 "table_2" 缺失 region 报告的示例:
# HBCK2 reportMissingRegionsInMeta default:table_1 default:table_2
# 对于默认命名空间下的表 'table_1' 以及命名空间 'ns1' 中的所有表执行触发缺失 region 的示例:
# HBCK2 reportMissingRegionsInMeta default:table_1 ns1
# 返回作为参数传递的每个表或指定为参数的命名空间上的每个表的缺失 region 列表。
#
# setRegionState <ENCODED_REGIONNAME> <STATE>
# Region 可能的状态有:OFFLINE, OPENING, OPEN, CLOSING, CLOSED,
# SPLITTING, SPLIT, FAILED_OPEN, FAILED_CLOSE, MERGING, MERGED,
# SPLITTING_NEW,MERGING_NEW, ABNORMALLY_CLOSED
# [警告]:这是一个非常危险的选择,用作最后的手段。
# 示例场景包括无法向前移动的 unassigns/assigns,因为 region 在 'hbase:meta' 中
# 处于不一致状态,例如,'unassigns' 命令只有在以下状态之一传递 region 时才能继续:
# SPLITTING|SPLIT|MERGING|OPEN|CLOSING 在使用此命令手动设置 region 状态之前,
# 请确认该 region 未被处理通过运行 procedure,例如 'assign' 或 'split'。
# 您可以使用 'list_procedures' 命令查看 hbase shell 中正在运行的过程。
# 将 region 'de00010733901a05f5a2a3a382e27dd4' 设置为 CLOSING 的示例:
# HBCK2 setRegionState de00010733901a05f5a2a3a382e27dd4 CLOSING
# 如果 region 状态改变则返回 "0" ,否则返回 "1" 。
#
# setTableState <TABLENAME> <STATE>
# 表的可能状态有:ENABLED, DISABLED, DISABLING, ENABLING
# 要读取当前表状态,请在 hbase shell 中运行
# hbase> get 'hbase:meta', '<TABLENAME>', 'table:state'
# A value of \x08\x00 == ENABLED, \x08\x01 == DISABLED, etc.
# 还可以在 shell 提示符下运行 'describe "<TABLENAME>"'。
# 使表名为 'user' ENABLED 的示例:
# HBCK2 setTableState users ENABLED
# 返回之前的表状态。
#
# scheduleRecoveries <SERVERNAME>...
# 为 RegionServers 列表安排 ServerCrashProcedure(SCP),server 名格式
# 为 '<HOSTNAME>,<PORT>,<STARTCODE>'(见 HBase UI/logs)。
# 使用 RegionServer 'a.example.org,29100,1540348649479' 的示例:
# HBCK2 scheduleRecoveries a.example.org,29100,1540348649479
# 如果没有创建过程,则返回创建的 ServerCrashProcedure(s) 的 pid(s) 或 -1
# (查看 master 日志了解原因)。
# 在 hbase 版本 2.0.3、2.1.2、2.2.0 或更高版本中添加了命令支持。
#
# unassigns <ENCODED_REGIONNAME>...
# -o,--override 由另一个 procedure 覆盖 ownership
# 即使在 Master 初始化期间也可以使用的 “raw” 取消分配(如果指定了 -skip 标志),
# Skirts Coprocessors,传递一个或多个 region 编码名称。1588230740 是 hbase:meta
# region 的硬编码名称,而 de00010733901a05f5a2a3a382e27dd4 是用户空间编码 region
# 名的示例,例如:
# HBCK2 unassigns 1588230740 de00010733901a05f5a2a3a382e27dd4
# 返回创建的 UnassignProcedure(s) 的 pid(s),如果没有,则返回 -1。
#
# 另请参见 org.apache.hbase.hbck1.OfflineMetaRepair,离线 hbase:meta 工具。
# 有关如何使用,请参阅 HBCK2 README。
#
cd $HBASE_HOME/
bin/hbase --config /etc/hbase/conf hbck -j hbck2-tools/hbase-hbck2-1.1.0.jar
- reportMissingRegionsInMeta: 查看 HBase 中在
hbase:meta
中缺失的 Region。指定表时一定要加命名空间,即使是default,否则它会假定一个值但这个往往不存在并提示你需要指定命名空间。 - addFsRegionsMissingInMeta: 添加存在于 HDFS 上的在
hbase:meta
中缺失的 Region。 - assigns:当某个 Region 为 OFFLINE 或 CLOSED 是可通过此命令分配给 RS,例如当
addFsRegionsMissingInMeta
执行完之后 region 添加到hbase:meta
了但状态仍为 CLOSED 时使用。 - unassigns:取消分配。
- extraRegionsInMeta:报告 hbase:meta 上存但文件系统上没有相关目录的 region,如果使用
-f
或--fix
则会删除找到的所有额外 region 来修复元数据。 - filesystem:这个过程会直接与文件系统交互,报告损坏的 hfile、引用、断开的链接和完整性,如果指定了
--fix
,则会修复除有完整性问题外的 region。 - fixMeta:对 hbase:meta 中的错误或不一致状态进行服务端修复。修复 ‘holes’、‘overlaps’ 等时,在 HDFS 中创建(空)region 目录以匹配添加到 hbase:meta 的 region。
- generateMissingTableDescriptorFile:通过生成丢失的表文件来修复 orphan 表,如果表文件夹丢失或存在
.tableinfo
,则不会覆盖现有的表描述符,此命令将不起作用。 - replication --fix: 修复发现的任何 replication 问题。
- setRegionState:设置 region 的状态,这是一个非常危险的操作,作为最后的方式来选择
- setTableState:指标表的状态。
Master UI 的 HBCK Report 页面如果报 不一致的 Region,可能的原因有:
- Master 认为这个 region 打开了,但是 regionserver 没有报告。修复:使用
assigns
命令。 - Master 以为这个 region 在 Server1 上打开,但是 regionserver 报了 Server2。修复:需要检查server是否还存在,如果没有则为其调度SCP;如果存在则重启 Server2 和 Server1。
- 报告有多个 regionservers 打开了该 region。修复:重启 RegionServers。
- 注意:当有 region 在转换时,报告的在 region 服务可能不正确,请在 regionserver 的 Web UI 中检查它们。
4 tar 方式
经过前面的步骤,我们已经获得了新版本 HBase可用的二进制包,HBase 的包在 hbase-assembly/target/
下看到 hbase-2.1.6.3.1.5.6014-3-bin.tar.gz
,这是一个 tar 包,
解压这个包,其目录结构
.
├── CHANGES.md
├── LEGAL
├── LICENSE.txt
├── NOTICE.txt
├── README.txt
├── RELEASENOTES.md
├── bin
│ ├── considerAsDead.sh
│ ├── draining_servers.rb
│ ├── get-active-master.rb
│ ├── graceful_stop.sh
│ ├── hbase
│ ├── hbase-cleanup.sh
│ ├── hbase-common.sh
│ ├── hbase-config.cmd
│ ├── hbase-config.sh
│ ├── hbase-daemon.sh
│ ├── hbase-daemons.sh
│ ├── hbase-jruby
│ ├── hbase.cmd
│ ├── hirb.rb
│ ├── local-master-backup.sh
│ ├── local-regionservers.sh
│ ├── master-backup.sh
│ ├── region_mover.rb
│ ├── region_status.rb
│ ├── regionservers.sh
│ ├── replication
│ ├── rolling-restart.sh
│ ├── shutdown_regionserver.rb
│ ├── start-hbase.cmd
│ ├── start-hbase.sh
│ ├── stop-hbase.cmd
│ ├── stop-hbase.sh
│ ├── test
│ └── zookeepers.sh
├── conf
│ ├── hadoop-metrics2-hbase.properties
│ ├── hbase-env.cmd
│ ├── hbase-env.sh
│ ├── hbase-policy.xml
│ ├── hbase-site.xml
│ ├── log4j.properties
│ └── regionservers
├── hbase-webapps
│ ├── master
│ ├── regionserver
│ ├── rest
│ ├── static
│ └── thrift
└── lib
……
└── zookeeper-3.4.6.3.1.5.6014-3.jar
升级前可以将 HDFS 上的元数据目录、本地的配置文件(HDP的在 /etc/hbase
下)及安装目录(例如 /usr/hdp/3.1.0.0-78/hbase
)备份下。
HBase 的升级,如果源集群还在使用,可以选择一个低峰期进行,如果不能集群不能停止,可以选择滚动升级的方式。如果允许停止一段时间,先停止全部集群,一次性依次替换每个节点原来的所有包(配置文件不用替换,使用原先的配置即可,但如果有新增配置需要提前配置好)。
进入到 hdp 的 hbase 的安装目录,进行替换。创建一个 hback2-tools 目录,同时将前面编译好的 hbck 的包放到 hback2-tools 目录下:
一般生产环境 HBase Master 会启动多个,如果需要滚动升级,可先升级其中非 Active 的 Master,停止某个 非 Active 的 Master,进入到该节点服务器上,手动替换原来的安装包,引用上原来的配置文件,如上图,然后重启该节点的 HBase 服务即可。先 依次升级 HBase Master,然后再依次升级 HBase RegionServer。
5 RPM 方式
RPM(Red-Hat Package Manager)适用于绝大多数的 Linux 发行版本,如Red Hat、CentOS、openSUSE 等系统,下面主要以 CentOS 为例,如果手动安装可以直接使用第 2部分编译后的包 hbase-2.1.6.3.1.5.6014-3-bin.tar.gz
配置安装即可,如果是更好地管理软件包可以将部署包打成 RPM ,关于更详细的 rpm 相关的用法和介绍可参考官方文档 §rpm documentation(rpm命令使用可查看 §RPM man pages、rpm包介绍可以查看§RPM Guide - A Good introduction into RPM Packaging )。
参考 HDP 中 HBase 的 rpm 包,如下
- hbase_3_1_0_0_78-2.0.2.3.1.0.0-78.noarch.rpm
- hbase_3_1_0_0_78-doc-2.0.2.3.1.0.0-78.noarch.rpm
- hbase_3_1_0_0_78-master-2.0.2.3.1.0.0-78.noarch.rpm
- hbase_3_1_0_0_78-regionserver-2.0.2.3.1.0.0-78.noarch.rpm
- hbase_3_1_0_0_78-rest-2.0.2.3.1.0.0-78.noarch.rpm
- hbase_3_1_0_0_78-thrift-2.0.2.3.1.0.0-78.noarch.rpm
- hbase_3_1_0_0_78-thrift2-2.0.2.3.1.0.0-78.noarch.rpm
如果能有 rpm 包的 spec 文件就比较好了,因此我们可以先通过上面的 7 个 rpm 包导出对应包的 spec 文件,有了这个文件即可以简单使用 rpmbuild -bb xxx.spec
生成 rpm 包,也可以使用 Maven 的 RPM 构建插件,对文件的构建配置进行参考。
5.1 rpmbuild 方式
使用 rpmrebuild 命令,如果没有需要先安装,分别写出 7 个 包的 spec 文件
#方式一:通过 yum 安装 rpmbuild
yum install -y rpmbuild
#方式二:rpm 包方式安装
https://jaist.dl.sourceforge.net/project/rpmrebuild/rpmrebuild/2.14/rpmrebuild-2.14.tar.gz
rpmbuild -tb rpmrebuild-2.14.tar.gz
rpm -ivh ~/rpmbuild/RPMS/noarch/rpmrebuild-2.14-1.noarch.rpm
5.1.1 构建目录
在家目录下创建分别创建如下目录(详细可查看 § RPM Packaging Workspace):
~/rpmbuild/BUILD
:构建 rpm 的文件目录~/rpmbuild/BUILDROOT
:编译过程中临时的构建目录~/rpmbuild/RPMS
:编译后的 RPM 包所在的目录~/rpmbuild/SOURCES
:源码和补丁文件存放的目录~/rpmbuild/SPECS
:生成的 spec存放的目录~/rpmbuild/SRPMS
:生成的SRPM所在的目录
rpm spec 文件中 items 说明如下(详细可见 § What is a SPEC File?)。SPEC 文件可以看做 rpmbuild 实际构建应用的“配方”,它是通过一系列定义的指令部分来告诉构建系统如何构建。SPEC 文件主要有两个部分组成:Preamble Items、Body Items,一下是其主要 Item 的说明:
5.1.2 Preamble Items
RPM 包文件名包含 Name、Version、Release,格式为 NAME-VERSION-RELEASE 或者 N-V-R(简称 NVR)。
SPEC 指令 | 说明 | 示例 |
---|---|---|
Name | 包的基本名称,应与 SPEC 文件名匹配。 | Name: hbase_3_1_0_0_78 |
Version | 软件的上游版本号。 | Version: 2.0.2.3.1.0.0 |
Release | 此版本软件的发布次数,通常将初始值设置为 1%{?dist} ,并随着包的每个新版本而增加它,构建新版本的软件时重置为 1。 | Release: 78 |
Summary | 包的单行简短摘要。 | Summary: HBase is the Hadoop database. Use it when you need random, realtime read/write access to your Big Data. This project's goal is the hosting of very large tables -- billions of rows X millions of columns -- atop clusters of commodity hardware. |
License | 被打包软件的许可证,对于在 Fedora 等社区发行版中分发的软件包,这必须是遵守特定发行版许可指南的开源许可证。 | License: 2012, Apache Software Foundation 。 |
URL | 有关该程序的更多信息的完整 URL,大多数情况下,这是打包软件的上游项目网站。 | URL: http://www.apache.org |
Source0 | 上游源代码压缩存档的路径或 URL(未打补丁,补丁在别处处理),这应该指向存档的可访问且可靠的存储,例如,上游页面而不是打包器的本地存储。 如果需要,可以添加更多 SourceX 指令,每次递增数字,例如:Source1、Source2、Source3 等。 | Source0: https://www.example.com/%{name}/releases/%{name}-%{version}.tar.gz |
Patch0 | 如有必要应用于源代码的第一个补丁的名称,如果需要可以添加更多 PatchX 指令,每次递增数字,例如:Patch1、Patch2、Patch3 等。 | Patch0: cello-output-first-patch.patch |
BuildArch | 如果包不依赖于架构,例如如果完全用解释性编程语言(interpreted programming language)编写,请将其设置为 BuildArch: noarch ,如果未设置包会自动继承构建它的机器的架构,例如 x86_64。 | BuildArch: x86_64 |
BuildRequires | 构建用编译语言(compiled language)编写的程序所需的以逗号或空格分隔的包列表。 BuildRequires 可以有多个条目,每个条目都在 SPEC 文件中的一行中。 | BuildRequires: python |
Requires | 软件安装后运行所需的以逗号或空格分隔的软件包列表,可以有多个 Requires 条目,每个条目都在 SPEC 文件中的一行中。 | Requires: /bin/bash Requires: sh-utils |
ExcludeArch | 如果某个软件无法在特定的处理器架构上运行,您可以在此处排除该架构。 |
5.1.3 Preamble Items
SPEC 指令 | 说明 |
---|---|
%description | RPM 中打包的软件的完整描述,该描述可以跨越多行并且可以分成段落。 |
%prep | 用于准备要构建的软件的命令或一系列命令,例如解压缩 Source0 中的存档,该指令可以包含一个 shell 脚本。 |
%build | 用于将软件实际构建为机器代码(对于编译语言)或字节码(对于某些解释语言)的命令或一系列命令。 |
%install | 用于将所需的构建工件从 %builddir (构建发生的位置)复制到 %buildroot 目录(包含要打包的文件的目录结构)的命令或一系列命令。 这通常意味着将文件从 ~/rpmbuild/BUILD 复制到 ~/rpmbuild/BUILDROOT 并在 ~/rpmbuild/BUILDROOT 中创建必要的目录,这仅在创建包时运行,而不是在最终用户安装包时运行,有关详细信息请参阅 Working with SPEC files。 |
%check | 用于测试软件的命令或一系列命令,这通常包括单元测试等内容。 |
%files | 将安装在最终用户系统中的文件列表。 |
%changelog | 在不同版本或发布版本之间对包发生的更改的记录。 |
5.1.4 获取 HDP HBase rpm 包的 spec 文件
通过 rpmrebuild 命令,写出 hbase 所有 rpm 的 spec 文件。
rpmrebuild -e -p --spec-only=hbase_3_1_0_0_78-2.0.2.3.1.0.0-78.noarch.spec hbase_3_1_0_0_78-2.0.2.3.1.0.0-78.noarch.rpm
rpmrebuild -e -p --spec-only=hbase_3_1_0_0_78-doc-2.0.2.3.1.0.0-78.noarch.spec hbase_3_1_0_0_78-doc-2.0.2.3.1.0.0-78.noarch.rpm
rpmrebuild -e -p --spec-only=hbase_3_1_0_0_78-master-2.0.2.3.1.0.0-78.noarch.spec hbase_3_1_0_0_78-master-2.0.2.3.1.0.0-78.noarch.rpm
rpmrebuild -e -p --spec-only=hbase_3_1_0_0_78-regionserver-2.0.2.3.1.0.0-78.noarch.spec hbase_3_1_0_0_78-regionserver-2.0.2.3.1.0.0-78.noarch.rpm
rpmrebuild -e -p --spec-only=hbase_3_1_0_0_78-rest-2.0.2.3.1.0.0-78.noarch.spec hbase_3_1_0_0_78-rest-2.0.2.3.1.0.0-78.noarch.rpm
rpmrebuild -e -p --spec-only=hbase_3_1_0_0_78-thrift-2.0.2.3.1.0.0-78.noarch.spec hbase_3_1_0_0_78-thrift-2.0.2.3.1.0.0-78.noarch.rpm
rpmrebuild -e -p --spec-only=hbase_3_1_0_0_78-thrift2-2.0.2.3.1.0.0-78.noarch.spec hbase_3_1_0_0_78-thrift2-2.0.2.3.1.0.0-78.noarch.rpm
5.1.5 BUILD 文件
在用户的家目录下创建 rpm 构建需要的文件目录。
mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
mkdir ~/rpmbuild/BUILD/hbase_3_1_5_0_6014-3.1.6.3.1.5.6014-3.noarch
mkdir ~/rpmbuild/BUILD/hbase_hbase_3_1_5_0_6014-3-doc-3.1.6.3.1.5.6014-3.noarch
mkdir ~/rpmbuild/BUILD/hbase_hbase_3_1_5_0_6014-3-master-3.1.6.3.1.5.6014-3.noarch
mkdir ~/rpmbuild/BUILD/hbase_hbase_3_1_5_0_6014-3-regionserver-3.1.6.3.1.5.6014-3.noarch
mkdir ~/rpmbuild/BUILD/hbase_hbase_3_1_5_0_6014-3-rest-3.1.6.3.1.5.6014-3.noarch
mkdir ~/rpmbuild/BUILD/hbase_hbase_3_1_5_0_6014-3-thrift-3.1.6.3.1.5.6014-3.noarch
mkdir ~/rpmbuild/BUILD/hbase_hbase_3_1_5_0_6014-3-thrift2-3.1.6.3.1.5.6014-3.noarch
对比原来的 rpm 包中的内容(可以使用 rpm2cpio hbase_3_1_5_0_152-2.1.6.3.1.5.0-152.noarch.rpm |cpio -idv
命令解压 rpm 包中的文件),将前面编译好的 2.1.6.3.1.5.6014-3 包的文件放到对应的目录下,其中的脚本和某些新版本的文件可以参看下面的 5.2 节获取。
5.1.5 生成 RPM
spec 是 5.1.4 节 生成的,可以对其进行修改,例如版本、路径等。生成的 rpm 包在当前的用户的家目录下的 ~/rpmbuild/RPMS
下。
rpmbuild -bb hbase_3_1_0_0_78-2.0.2.3.1.0.0-78.noarch.spec
rpmbuild -bb hbase_3_1_0_0_78-doc-2.0.2.3.1.0.0-78.noarch.spec
rpmbuild -bb hbase_3_1_0_0_78-master-2.0.2.3.1.0.0-78.noarch.spec
rpmbuild -bb hbase_3_1_0_0_78-regionserver-2.0.2.3.1.0.0-78.noarch.spec
rpmbuild -bb hbase_3_1_0_0_78-rest-2.0.2.3.1.0.0-78.noarch.spec
rpmbuild -bb hbase_3_1_0_0_78-thrift-2.0.2.3.1.0.0-78.noarch.spec
rpmbuild -bb hbase_3_1_0_0_78-thrift2-2.0.2.3.1.0.0-78.noarch.spec
5.2 rpm-maven-plugin 方式
详细的源码可访问 【Yore Yuen / hdp-hbase-rpm】,不过当前并不完善,可作为构建 hbase RPM 的参考。也欢迎大家贡献和完善这个项目!
5.2.1 pom.xml
一种参考的 pom 文件如下(完整的可访问上面的项目),使用 org.apache.maven.plugins:maven-antrun-plugin
插件执行 ant 的命令,将前面编译的 tar.gz 的包拷贝到项目的下,并解压。使用 org.codehaus.mojo:rpm-maven-plugin
开始构建 rpm 包。
在配置 rpm-maven-plugin 时,主要参考前面提取出的各个 hbase rpm 包的 spec 文件进行。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>yore</groupId>
<artifactId>hdp-hbase-rpm</artifactId>
<version>1.0.2</version>
<name>HDP HBase RPMS</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<!--<BuildArch>x86_64</BuildArch>-->
<BuildArch>noarch</BuildArch>
<!--<hdp.verson>3.1.5.0-152</hdp.verson>-->
<hdp.verson>3.1.0.0-78</hdp.verson>
<hbase.verson>2.1.6.3.1.6.8-1</hbase.verson>
<package-version>2.1.6.3.1.6.8</package-version>
<package-release>1</package-release>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<!-- http://maven.apache.org/plugins/maven-antrun-plugin/ -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target name="Download Apache HBase">
<mkdir dir="${project.build.directory}/hbase" />
<!-- 方式二:拷贝本地文件到构建目录 -->
<!--<copy todir="hbase-assembly/target/hbase-2.1.6.3.1.6.8-1-bin.tar.gz">-->
<copy todir="${project.build.directory}/hbase">
<fileset dir="/Users/yoreyuan/Downloads/dajia">
<include name="hbase-${hbase.verson}-bin.tar.gz"/>
</fileset>
</copy>
<untar src="${project.build.directory}/hbase/hbase-${hbase.verson}-bin.tar.gz"
dest="${project.build.directory}/hbase"
compression="gzip" />
</target>
</configuration>
</execution>
</executions>
</plugin>
<!-- rpm -->
<plugin>
<!-- https://www.mojohaus.org/rpm-maven-plugin/adv-params.html -->
<groupId>org.codehaus.mojo</groupId>
<artifactId>rpm-maven-plugin</artifactId>
<version>2.2.0</version>
<configuration>
<license>2012, Apache Software Foundation</license>
<group>Development</group>
<description>Maven Recipe: RPM Package.</description>
<!--<prefix>/</prefix>-->
<needarch>${BuildArch}</needarch>
<version>${package-version}</version>
<release>${package-release}</release>
<defaultFilemode>644</defaultFilemode>
<defaultDirmode>755</defaultDirmode>
<defaultUsername>root</defaultUsername>
<defaultGroupname>root</defaultGroupname>
</configuration>
<executions>
<!-- hbase_3_1_0_0_78-2.1.6.3.1.6.8-1.noarch.rpm -->
<execution>
……
</execution>
<!-- hbase_3_1_5_0_152-doc-2.1.6.3.1.6.8-1.noarch.rpm -->
<execution>
……
</execution>
<!-- hbase_3_1_0_0_78-master-2.1.6.3.1.6.8-1.noarch.rpm -->
<execution>
……
</execution>
<!-- hbase_3_1_0_0_78-regionserver-2.1.6.3.1.6.8-1.noarch.rpm -->
<execution>
……
</execution>
<!-- hbase_3_1_0_0_78-rest-2.1.6.3.1.6.8-1.noarch.rpm -->
<execution>
……
</execution>
<!-- hbase_3_1_0_0_78-thrift-2.1.6.3.1.6.8-1.noarch.rpm -->
<execution>
……
</execution>
<!-- hbase_3_1_0_0_78-thrift2-2.1.6.3.1.6.8-1.noarch.rpm -->
<execution>
……
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
5.2.2 bin/hbase 脚本
HDP 版的 hbase 启动脚本,hortonworks 又对其进行封装,所以某些脚本需要重新修改
#!/usr/bin/env bash
hdp_verson='3.1.0.0-78'
BIGTOP_DEFAULTS_DIR=${BIGTOP_DEFAULTS_DIR-/etc/default}
[ -n "${BIGTOP_DEFAULTS_DIR}" -a -r ${BIGTOP_DEFAULTS_DIR}/hbase ] && . ${BIGTOP_DEFAULTS_DIR}/hbase
export HBASE_HOME=${HBASE_HOME:-/usr/hdp/$hdp_verson/hbase}
export HADOOP_HOME=${HADOOP_HOME:-/usr/hdp/$hdp_verson/hadoop}
export HADOOP_CONF=${HADOOP_HOME}/conf
export ZOOKEEPER_HOME=${ZOOKEEPER_HOME:-/usr/hdp/$hdp_verson/zookeeper}
export HBASE_CLASSPATH=$HADOOP_CONF:$HADOOP_HOME/*:$HADOOP_HOME/lib/*:$ZOOKEEPER_HOME/*:$HBASE_CLASSPATH:\
$HBASE_HOME/hbck2-tools/hbase-tools-1.1.0.jar
#HBASE_CLASSPATH_PREFIX=$HBASE_HOME/hbck2-tools/hbase-table-reporter-1.1.0.jar
export HDP_VERSION=${HDP_VERSION:-$hdp_verson}
export HBASE_OPTS="-Dhdp.version=${HDP_VERSION} ${HBASE_OPTS}"
exec /usr/hdp/$hdp_verson/hbase/bin/hbase.distro "$@"
5.2.3 bin/hbase.distro 脚本
由源码编译的包中的 bin/hbase 重命名为 bin/hbase.distro 脚本
5.2.4 include/thrift/hbase1.thrift
由源码中的 hbase-thrift/src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift
而来。
5.2.5 include/thrift/hbase2.thrift
由源码中的 hbase-thrift/src/main/resources/org/apache/hadoop/hbase/thrift2/hbase.thrift
而来。
5.2.6 打包
使用如下的命令在待部署的系统下执行
#mvn clean package rpm:rpm -DskipTests -Drat.skip
mvn clean package rpm:rpm
find target/rpm -name "*.rpm"
6 升级后
6.1 Ambari
访问 Ambari 管理页面的版本栈中查看版本,可以看到 Hbase 的版本已经从 2.0.2 升级到了 2.1.6
6.2 HBase UI
访问 HBase UI 可以看到 Hbase 升级后的最新版本信息
6.3 HBase HBCK2
升级后,HBase UI 页面多出了一个 HBCK 页面,在这个页面可以看到当前监控到的元数据存在的潜在问题,使我们更加方便的了解 HBase 的元数据的情况。