# 构建和开发 Apache HBase

本章包含有关构建和发布 HBase 代码和文档的信息和指南。熟悉这些指南将有助于 HBase 提交者更轻松地使用您的贡献。

## 164.参与进来

只有当人们贡献时，Apache HBase 才会变得更好！如果您希望为 Apache HBase 做出贡献，请在 JIRA 中查找标有'beginner'％20AND％20status％20in％20 标签的[问题（开放％2C％20％22In％20Progress％22％2C ％20Reopened））。这些是 HBase 贡献者认为值得的问题，但不是当下的优先事项，也是延长 HBase 内部的好方法。请参阅](https://issues.apache.org/jira/issues/?jql=project%20%3D%20HBASE%20AND%20labels%20in%20(beginner)[对于新贡献者的斜坡问题，使用什么标签？](http://search-hadoop.com/m/DHED43re96) 来自 dev 邮件列表的背景信息。

在开始向 HBase 提交代码之前，请参考[开发](#developing)。

由于 Apache HBase 是 Apache Software Foundation 项目，请参阅 [asf](#asf) 以获取有关 ASF 如何运行的更多信息。

### 164.1。邮件列表

注册 dev-list 和用户列表。请参阅[邮件列表](https://hbase.apache.org/mail-lists.html)页面。鼓励提出问题 - 并帮助回答其他人的问题！两个列表都有不同程度的经验，因此鼓励耐心和礼貌（请留待主题。）

### 164.2。松弛

Apache HBase 项目有自己的链接： [Slack Channel](http://apache-hbase.slack.com) ，用于实时问题和讨论。邮寄 [dev@hbase.apache.org](mailto:dev@hbase.apache.org) 请求邀请。

### 164.3。互联网中继聊天（IRC）

（注意：我们的 IRC 频道似乎已被弃用，以支持上述 Slack 频道）

对于实时问题和讨论，请使用 [FreeNode](https://freenode.net/) IRC 网络上的`#hbase` IRC 频道。 FreeNode 提供基于 Web 的客户端，但大多数人更喜欢本机客户端，并且每个操作系统都有几个客户端。

### 164.4。吉拉

检查 [Jira](https://issues.apache.org/jira/projects/HBASE/issues) 中的现有问题。如果是新功能请求，增强功能或错误，请提交故障单。

我们在 JIRA 中跟踪多种类型的工作：

*   错误：HBase 本身就有问题。

*   测试：需要进行测试，或者测试被破坏。

*   新功能：您对新功能有所了解。通常最好首先将它们放在邮件列表上，然后编写一个设计规范，添加到功能请求 JIRA 中。

*   改进：存在一个功能，但可以进行调整或扩充。通常最好先将它们放在邮件列表上并进行讨论，然后总结或链接到讨论，如果其他人似乎对改进感兴趣。

*   希望：这就像一个新功能，但对于某些你可能没有背景来充实自己的东西。

错误和测试具有最高优先级，应该是可操作的。

#### 164.4.1。报告有效问题的指南

*   **搜索重复项**：您的问题可能已被报告过。看一看，意识到其他人可能会以不同的方式描述摘要。

    还可以搜索邮件列表，其中可能包含有关您的问题以及如何解决问题的信息。不要为已经在邮件列表中讨论和解决的问题提出问题，除非您强烈反对决议**并且**愿意帮助解决问题。

    *   **公开讨论**：使用邮件列表讨论您发现的内容，看看是否有遗漏的内容。避免使用反向渠道，以便您从整个项目的经验和专业知识中受益。

    *   **不要代表他人提交**：你可能没有所有的上下文，而且你没有那么多的动机来把它看成是实际遇到这个 bug 的人。从长远来看，鼓励他人提出自己的问题会更有帮助。指出这些材料并提供第一次或第二次帮助。

    *   **写一个很好的总结**：一个很好的总结包括有关问题的信息，对用户或开发人员的影响以及代码的区域。

        *   好：`Address new license dependencies from hadoop3-alpha4`

        *   改进空间：`Canary is broken`

            如果你写了一个糟糕的标题，别人会为你重写它。这是他们本可以花时间处理这个问题的时候了。

    *   **在描述**中给出上下文：在多个部分中考虑这个可能是好的：

        *   会发生什么或不会发生什么？

        *   它对你有何影响？

        *   别人怎么能重现它？

        *   什么会“固定”的样子？

            您不需要知道所有这些的答案，但尽可能多地提供信息。如果您可以提供技术信息，例如您认为可能导致问题的 Git 提交 SHA，或者您认为问题首次出现在 builds.apache.org 上的构建失败，请分享该信息。

    *   **填写所有相关字段**：这些字段可帮助我们过滤，分类和查找内容。

    *   **一个错误，一个问题，一个补丁**：为了帮助反向移植，不要在多个错误之间拆分问题或修复。

    *   **如果可以**增加价值：即使您不知道如何解决问题，提交问题仍然很好。但是提供尽可能多的信息，愿意分类和回答问题，并愿意测试潜在的修复程序甚至更好！我们希望尽快修复您的问题。

    *   **如果我们不解决它，请不要沮丧**：时间和资源是有限的。在某些情况下，我们可能无法（或可能选择不）修复问题，特别是如果它是边缘情况或有解决方法。即使它没有得到修复，JIRA 也是它的公开记录，并且如果它们将来遇到类似的问题，将帮助其他人。

#### 164.4.2。处理一个问题

要检查您作为初学者可以解决的现有问题，请在 JIRA 中搜索标有“初学者”％20AND％20status％20in％20 标签的[问题（开放％2C％20％22In％20Progress％ 22％2C％20Reopened））。](https://issues.apache.org/jira/issues/?jql=project%20%3D%20HBASE%20AND%20labels%20in%20(beginner)

JIRA 优先事项

*   **Blocker** ：仅在问题可能导致数据丢失或群集不稳定时使用。

*   **严重**：在某些情况下，所描述的问题可能导致数据丢失或群集不稳定。

*   **主要**：重要但不是悲剧性的问题，例如客户端 API 的更新，它将添加许多急需的功能或需要修复但不会导致数据丢失的重大错误。

*   **次要**：有用的增强功能和烦人但不会破坏性的错误。

*   **琐碎**：有用的增强功能，但通常是化妆品。

示例 41\. Jira 评论中的代码块

Jira 中常用的宏是{code}。标签内的所有内容都已预先格式化，如本例所示。

```
{code}
code snippet
{code} 
```

## 165\. Apache HBase 存储库

Apache HBase 由多个存储库组成，这些存储库托管在 [Apache GitBox](https://gitbox.apache.org/) 上。这些是以下内容：

*   [hbase](https://gitbox.apache.org/repos/asf?p=hbase.git) - 主要的 Apache HBase 存储库

*   [hbase-connectors](https://gitbox.apache.org/repos/asf?p=hbase-connectors.git) - Apache Kafka 和 Apache Spark 的连接器

*   [hbase-operator-tools](https://gitbox.apache.org/repos/asf?p=hbase-operator-tools.git) - 可操作性和可支持性工具，如 [HBase `HBCK2`](#HBCK2)

*   [hbase-site](https://gitbox.apache.org/repos/asf?p=hbase-site.git) - hbase.apache.org 网站

*   [hbase-thirdparty](https://gitbox.apache.org/repos/asf?p=hbase-thirdparty.git) - 流行的第三方库的重新定位版本

## 166\. IDE

### 166.1。日食

#### 166.1.1。代码格式

在 _dev-support /_ 文件夹下，您将找到 _hbase_eclipse _formatter.xml_ 。我们鼓励您在编辑 HBase 代码时在 eclipse 中使用此格式化程序。

转到`Preferences→Java→Code Style→Formatter→Import`加载 xml 文件。转到`Preferences→Java→Editor→Save Actions`，确保选中“格式化源代码”和“格式化编辑行”。

除自动格式化外，请确保遵循 [common.patch.feedback](#common.patch.feedback) 中说明的样式指南。

#### 166.1.2。 Eclipse Git 插件

如果您通过 git 克隆项目，请下载并安装 Git 插件（EGit）。附加到您当地的 git 仓库（通过 Git Repositories 窗口），您将能够看到文件修订历史记录，生成补丁等。

#### 166.1.3。使用`m2eclipse`在 Eclipse 中进行 HBase 项目设置

最简单的方法是使用 Eclipse 的 m2eclipse 插件。 Eclipse Indigo 或更新版本包括 m2eclipse，或者您可以从 [http://www.eclipse.org/m2e/](http://www.eclipse.org/m2e/) 下载它。它为 Eclipse 提供了 Maven 集成，甚至允许您使用 Eclipse 中的直接 Maven 命令来编译和测试您的项目。

要导入项目，请单击并选择 HBase 根目录。 `m2eclipse`为您找到所有 hbase 模块。

如果在工作区中安装 m2eclipse 并导入 HBase，请执行以下操作来修复 eclipse Build Path。

1.  删除 _ 目标 _ 文件夹

2.  添加 _target / generated-jamon_ 和 _target / generated-sources / java_ 文件夹。

3.  从构建路径中删除 _src / main / resources_ 和 _src / test / resources_ 上的排除项，以避免在控制台中出现错误消息，如下所示：

    ```
    Failed to execute goal
    org.apache.maven.plugins:maven-antrun-plugin:1.6:run (default) on project hbase:
    'An Ant BuildException has occurred: Replace: source file .../target/classes/hbase-default.xml
    doesn't exist 
    ```

    这也将减少日食构建周期，并使您在开发时更轻松。

#### 166.1.4。使用命令行在 Eclipse 中进行 HBase 项目设置

您可以从命令行生成 Eclipse 文件，而不是使用`m2eclipse`。

1.  首先，运行以下命令，构建 HBase。你只需要这样做一次。

    ```
    mvn clean install -DskipTests 
    ```

2.  关闭 Eclipse，并在终端的本地 HBase 项目目录中执行以下命令，以生成新的 _.project_ 和 _.classpath_ 文件。

    ```
    mvn eclipse:eclipse 
    ```

3.  重新打开 Eclipse 并将 HBase 目录中的 _.project_ 文件导入工作区。

#### 166.1.5。 Maven 类路径变量

需要为项目设置`$M2_REPO`类路径变量。这需要设置为您的本地 Maven 存储库，通常是 _〜/ .m2 / repository_

如果未配置此类路径变量，您将在 Eclipse 中看到如下编译错误：

```
Description    Resource    Path    Location    Type
The project cannot be built until build path errors are resolved    hbase        Unknown    Java Problem
Unbound classpath variable: 'M2_REPO/asm/asm/3.1/asm-3.1.jar' in project 'hbase'    hbase        Build path    Build Path Problem
Unbound classpath variable: 'M2_REPO/com/google/guava/guava/r09/guava-r09.jar' in project 'hbase'    hbase        Build path    Build Path Problem
Unbound classpath variable: 'M2_REPO/com/google/protobuf/protobuf-java/2.3.0/protobuf-java-2.3.0.jar' in project 'hbase'    hbase        Build path    Build Path Problem Unbound classpath variable: 
```

#### 166.1.6。 Eclipse 已知问题

Eclipse 目前会抱怨 _Bytes.java_ 。无法关闭这些错误。

```
Description    Resource    Path    Location    Type
Access restriction: The method arrayBaseOffset(Class) from the type Unsafe is not accessible due to restriction on required library /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/classes.jar    Bytes.java    /hbase/src/main/java/org/apache/hadoop/hbase/util    line 1061    Java Problem
Access restriction: The method arrayIndexScale(Class) from the type Unsafe is not accessible due to restriction on required library /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/classes.jar    Bytes.java    /hbase/src/main/java/org/apache/hadoop/hbase/util    line 1064    Java Problem
Access restriction: The method getLong(Object, long) from the type Unsafe is not accessible due to restriction on required library /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/classes.jar    Bytes.java    /hbase/src/main/java/org/apache/hadoop/hbase/util    line 1111    Java Problem 
```

#### 166.1.7。 Eclipse - 更多信息

有关在 Windows 上设置 Eclipse for HBase 开发的其他信息，请参阅 [Michael Morello 关于该主题的博客](http://michaelmorello.blogspot.com/2011/09/hbase-subversion-eclipse-windows.html)。

### 166.2。 IntelliJ IDEA

您可以设置 IntelliJ IDEA 以实现与 Eclipse 类似的功能。跟着这些步骤。

1.  选择

2.  您无需选择配置文件。确保选中所需的 Maven 项目，然后单击 **Next** 。

3.  选择 JDK 的位置。

在 IntelliJ IDEA 中使用 HBase Formatter

使用 IntelliJ IDEA 的 Eclipse Code Formatter 插件，您可以导入 [eclipse.code.formatting](#eclipse.code.formatting) 中描述的 HBase 代码格式化程序。

### 166.3。其他 IDE

为其他 IDE 镜像 [eclipse](#eclipse) 设置指令会很有用。如果您想提供帮助，请查看 [HBASE-11704](https://issues.apache.org/jira/browse/HBASE-11704) 。

## 167.构建 Apache HBase

### 167.1。基本编译

HBase 是使用 Maven 编译的。您必须至少使用 Maven 3.0.4。要检查 Maven 版本，请运行命令 mvn -version。

> JDK 版本要求
> 
> 从 HBase 1.0 开始，您必须使用 Java 7 或更高版本从源代码构建。有关受支持的 JDK 版本的更完整信息，请参见 [java](#java) 。

#### 167.1.1。 Maven 构建命令

所有命令都从本地 HBase 项目目录执行。

##### 包

从其 java 源代码编译 HBase 的最简单命令是使用`package`目标，该目标使用编译的文件构建 JAR。

```
mvn package -DskipTests 
```

或者，在编译之前进行清理：

```
mvn clean package -DskipTests 
```

如上面在 [eclipse](#eclipse) 中所述设置 Eclipse，您也可以在 Eclipse 中使用 Build 命令。要创建完整的可安装 HBase 包需要多做一些工作，请继续阅读。

##### 编

`compile`目标不会使用编译的文件创建 JAR。

```
mvn compile 
```

```
mvn clean compile 
```

##### 安装

要在 _〜/ .m2 /_ 目录中安装 JAR，请使用`install`目标。

```
mvn install 
```

```
mvn clean install 
```

```
mvn clean install -DskipTests 
```

#### 167.1.2。运行所有或单个单元测试

请参阅 [hbase.unittests](#hbase.unittests) 中的 [hbase.unittests.cmds](#hbase.unittests.cmds) 部分

#### 167.1.3。建立各种 hadoop 版本。

HBase 支持针对 Apache Hadoop 版本构建：2.y 和 3.y（早期版本工件）。默认情况下，我们针对 Hadoop 2.x 进行构建。

要针对 Hadoop 2.y 行中的特定版本进行构建，请设置为`-Dhadoop-two.version=2.6.3`。

```
mvn -Dhadoop-two.version=2.6.3 ... 
```

要更改我们构建的 Hadoop 的主要版本行，请在调用 mvn 时添加 hadoop.profile 属性：

```
mvn -Dhadoop.profile=3.0 ... 
```

以上内容将针对我们在 _pom.xml_ 中作为我们的'3.0'版本的任何显式 hadoop 3.y 版本构建。测试可能不会全部通过，因此您可能需要通过`-DskipTests`，除非您倾向于修复失败的测试。

要选择特定的 Hadoop 3.y 版本，您需要设置 hadoop-three.version 属性，例如`-Dhadoop-three.version=3.0.0`。

#### 167.1.4。构建 Protobuf

您可能需要更改驻留在 _hbase-protocol_ 模块或其他模块中的 protobuf 定义。

在 hbase-2.0.0 之前，protobuf 定义文件遍布所有 hbase 模块，但现在所有与 protobuf 相关的文件必须驻留在 hbase 协议模块中;我们正在尝试包含我们的 protobuf 使用，以便我们可以自由地更改版本而不会破坏任何下游项目使用 protobuf。

protobuf 文件位于 _hbase-protocol / src / main / protobuf_ 中。要使更改生效，您需要重新生成类。

```
mvn package -pl hbase-protocol -am 
```

类似地，内部使用的 protobuf 定义位于 _hbase-protocol-shaded_ 模块中。

```
mvn package -pl hbase-protocol-shaded -am 
```

通常，使用本机`protoc`二进制文件完成 protobuf 代码生成。在我们的构建中，我们使用 maven 插件以方便使用;但是，插件可能无法为所有平台检索适当的二进制文件。如果您发现自己处于 protoc 失败的平台上，则必须从源代码编译 protoc，并独立于我们的 maven 构建运行它。您可以通过在 maven 参数中指定`-Dprotoc.skip`来禁用内联代码生成，从而允许您的构建继续进行。

> 如果您需要手动生成 protobuf 文件，则不应在后续 maven 调用中使用`clean`，因为这将删除新生成的文件。

有关更多详细信息，请阅读 _hbase-protocol / README.txt_

#### 167.1.5。建立节俭

您可能需要更改驻留在 _hbase-thrift_ 模块或其他模块中的 thrift 定义。

thrift 文件位于 _hbase-thrift / src / main / resources_ 中。要使更改生效，您需要重新生成类。您可以使用 maven profile `compile-thrift`来执行此操作。

```
mvn compile -Pcompile-thrift 
```

您可能还想使用以下命令为 thrift 二进制文件定义`thrift.path`：

```
 mvn compile -Pcompile-thrift -Dthrift.path=/opt/local/bin/thrift 
```

#### 167.1.6。建立一个 Tarball

您可以通过运行以下命令，在不通过[发布](#releasing)中描述的发布过程的情况下构建 tarball：

```
mvn -DskipTests clean install && mvn -DskipTests package assembly:single 
```

分发 tarball 构建在 _hbase-assembly / target / hbase- &lt;version&gt;-bin.tar.gz&lt;/version&gt;_ 中。

您可以通过在 maven 命令中安装或部署之前使用程序集：单个目标来安装或部署 tarball：

```
mvn -DskipTests package assembly:single install 
```

```
mvn -DskipTests package assembly:single deploy 
```

#### 167.1.7。建立陷阱

##### Maven Site 失败

如果看到`Unable to find resource 'VM_global_library.vm'`，请忽略它。这不是错误。虽然这是[官方丑陋](https://issues.apache.org/jira/browse/MSITE-286)。

## 168.发布 Apache HBase

> 建立针对 HBase 1。
> 
> HBase 1.x 需要 Java 7 才能构建。有关每个 HBase 版本的 Java 要求，请参阅 [java](#java) 。

示例 42.示例 _〜/ .m2 / settings.xml_ 文件

发布到 maven 需要您签署要上传的工件。为了让您为自己签名，您可以在 _.m2_ 下的本地存储库中正确配置 _settings.xml_ ，如下所示。

```
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                      http://maven.apache.org/xsd/settings-1.0.0.xsd">
  <servers>
    <!- To publish a snapshot of some part of Maven -->
    <server>
      <id>apache.snapshots.https</id>
      <username>YOUR_APACHE_ID
      </username>
      <password>YOUR_APACHE_PASSWORD
      </password>
    </server>
    <!-- To publish a website using Maven -->
    <!-- To stage a release of some part of Maven -->
    <server>
      <id>apache.releases.https</id>
      <username>YOUR_APACHE_ID
      </username>
      <password>YOUR_APACHE_PASSWORD
      </password>
    </server>
  </servers>
  <profiles>
    <profile>
      <id>apache-release</id>
      <properties>
    <gpg.keyname>YOUR_KEYNAME</gpg.keyname>
    <!--Keyname is something like this ... 00A5F21E... do gpg --list-keys to find it-->
    <gpg.passphrase>YOUR_KEY_PASSWORD
    </gpg.passphrase>
      </properties>
    </profile>
  </profiles>
</settings> 
```

### 168.1。发布候选人

只有提交者可以发布 hbase 工件。

在你开始之前

确保您的环境设置正确。 Maven 和 Git 是下面使用的主要工具。您需要在本地 _〜/ .m2_ maven 存储库中正确配置 _settings.xml_ 文件，其中包含 apache repos 的登录信息（参见[示例 _〜/ .m2 /settings.xml_ 文件](#maven.settings.xml)）。您还需要具有已发布的签名密钥。浏览 Hadoop [如何发布](http://wiki.apache.org/hadoop/HowToRelease) wiki 页面，了解如何发布。它是下面大多数说明的模型。它通常包含有关特定步骤的更多详细信息，例如，在 Apache 中将代码签名密钥添加到项目 KEYS 文件中，或者如何更新 JIRA 以准备发布。

在制作候选版本之前，请通过部署 SNAPSHOT 进行练习。检查以确保最近的版本已经从您将要发布的分支传递到该分支。您还应该在加载的集群上尝试最近的分支提示，可能是通过运行`hbase-it`集成测试套件几个小时来“烧入”近候选位。

> 为 Maven 指定堆空间
> 
> 您可能会遇到 OutOfMemoryErrors 构建，特别是构建站点和文档。通过设置`MAVEN_OPTS`变量为 Maven 堆起来。您可以将变量作为 Maven 命令的前缀，如下例所示：
> 
> ```
> MAVEN_OPTS="-Xmx4g -XX:MaxPermSize=256m" mvn package 
> ```
> 
> 您也可以在 shell 中的环境变量或别名中设置它。
> 
> 脚本 _dev-support / make _rc.sh_ 自动执行以下许多步骤。它将检出标签，清理结帐，构建 src 和 bin tarball，并将构建的 jar 部署到 repository.apache.org。它没有对发布的 _CHANGES.txt_ 进行修改，检查生成的工件以确保它们“良好” - 例如提取生成的 tarball，验证它们是否正确，然后启动 HBase 并检查一切是否正常运行 - 或者将 tarball 签名并推送到 [people.apache.org](https://people.apache.org) 。看一看。根据需要修改/改进。

程序：发布程序

1.  更新 _CHANGES.txt_ 文件和 POM 文件。

    使用自上次发布以来的更改更新 _CHANGES.txt_ 。确保 JIRA 的 URL 指向正确的位置，该位置列出了此版本的修复程序。适当调整所有 POM 文件中的版本。如果要创建候选发布版，则必须从所有 pom.xml 文件中的所有版本中删除`-SNAPSHOT`标签。如果您正在运行此 receipe 以发布快照，则必须在 hbase 版本上保留`-SNAPSHOT`后缀。 [版本 Maven 插件](http://www.mojohaus.org/versions-maven-plugin/)可以在这里使用。要在 hbase 多模块项目的所有 poms 中设置版本，请使用如下命令：

    ```
    $ mvn clean org.codehaus.mojo:versions-maven-plugin:2.5:set -DnewVersion=2.1.0-SNAPSHOT 
    ```

    确保 poms 中的所有版本都已更改！检查 _CHANGES.txt_ 并更改任何 maven 版本。

2.  更新文档。

    更新 _src / main / asciidoc_ 下的文档。这通常涉及从主分支复制最新版本并进行版本特定调整以适应此候选版本。

3.  清洁结帐目录

    ```
    $ mvn clean
    $ git clean -f -x -d 
    ```

4.  运行 Apache-Rat Check 许可证很好

    ```
    $ mvn apache-rat 
    ```

    如果上述操作失败，请检查鼠标日志。

    ```
    $ grep 'Rat check' patchprocess/mvn_apache_rat.log 
    ```

5.  创建发布标记。假设您已经运行了基本测试，鼠标检查，通过并且一切看起来都很好，现在是标记候选发布者的时间（如果您需要重做，则总是删除标记）。要标记，请在适合您的构建的版本中进行替换。所有标签都应该是签名标签;即通过 _-s_ 选项（参见[签署您的工作](http://https://git-scm.com/book/id/v2/Git-Tools-Signing-Your-Work)，了解如何设置您的 git 环境进行签名）。

    ```
    $ git tag -s 2.0.0-alpha4-RC0 -m "Tagging the 2.0.0-alpha4 first Releae Candidate (Candidates start at zero)" 
    ```

或者，如果您要发布，标签应该有一个 _rel /_ 前缀，以确保它们保存在 Apache repo 中，如下所示：

```
+$ git tag -s rel/2.0.0-alpha4 -m "Tagging the 2.0.0-alpha4 Release" 
```

推送（特定）标签（仅限）以便其他人可以访问。

+

```
$ git push origin 2.0.0-alpha4-RC0 
```

*   有关如何删除标签的信息，请参阅[如何删除标签](http://www.manikrathee.com/how-to-delete-a-tag-in-git.html)。涵盖删除尚未推送到远程 Apache repo 的标签以及删除推送到 Apache 的标签。

*   构建源代码 tarball。

    现在，构建源代码 tarball。让我们假设我们正在为 _/tmp/hbase-2.0.0-alpha4-RC0/_ 标记 _2.0.0-alpha4-RC0_ 构建源码 tarball（此步骤要求刚刚完成了上面描述的 mvn 和 git clean 步骤）。

    ```
    $ git archive --format=tar.gz --output="/tmp/hbase-2.0.0-alpha4-RC0/hbase-2.0.0-alpha4-src.tar.gz" --prefix="hbase-2.0.0-alpha4/" $git_tag 
    ```

上面我们将 hbase-2.0.0-alpha4-src.tar.gz tarball 生成到 _/tmp/hbase-2.0.0-alpha4-RC0_ 构建输出目录中（我们不想要 _] RC0_ 在名称或前缀中。这些位当前是候选版本，但如果 VOTE 通过，它们将成为释放，因此我们不会使用 _RCX_ 来污染工件名称。

1.  构建二进制 tarball。接下来，构建二进制 tarball。在构建时添加`-Prelease`配置文件。它运行许可证 apache-rat 检查以及其他有助于确保所有内容都有益的规则。分两步完成。

首先安装到本地存储库

```
$ mvn clean install -DskipTests -Prelease 
```

接下来，生成文档并组装 tarball。请注意，下一步可能需要一段时间，几个小时生成站点文档。

```
$ mvn install -DskipTests site assembly:single -Prelease 
```

*   否则，当您尝试一步完成所有操作时，构建会抱怨 hbase 模块不在 maven 存储库中，尤其是在新的存储库中。您似乎需要在两个步骤中都需要安装目标。

*   提取生成的 tarball - 你会在 _hbase-assembly / target_ 下找到它并检查出来。查看文档，查看它是否运行等。如果好，请复制构建输出目录中源 tarball 旁边的 tarball。

*   部署到 Maven 资源库。

    接下来，将 HBase 部署到 Apache Maven 存储库。添加 apache-release `profile when running the` mvn deploy`命令。此配置文件来自我们的 pom 文件引用的 Apache 父 pom。只要 _settings.xml_ 配置正确，它就会对发布到 Maven 的工件进行签名，如[示例 _〜/ .m2 / settings.xml_ 文件](#maven.settings.xml)。此步骤取决于已由前一个 bin tarball 构建填充的本地存储库。

    ```
    $ mvn deploy -DskipTests -Papache-release -Prelease 
    ```

    此命令将所有工件复制到处于“打开”状态的临时暂存 Apache maven 存储库。需要对这些 maven 工件进行更多的工作，以使它们普遍可用。

    我们不会将 HBase tarball 发布到 Apache Maven 存储库。要避免部署 tarball，请不要在`mvn deploy`命令中包含`assembly:single`目标。检查已部署的工件，如下一节中所述。

> make_rc.s
> 
> 如果你运行 _dev-support / make _rc.sh_ 脚本，这就是你需要的。要完成发布，请从此处开始编写脚本。

1.  使候选版本可用。

    工件位于“打开”状态的暂存区域中的 maven 存储库中。在这种“开放”状态下，您可以查看您发布的内容，以确保一切顺利。为此，请使用您的 Apache ID 在 [repository.apache.org](https://repository.apache.org) 上登录 Apache 的 Nexus。在临时存储库中查找工件。单击“Staging Repositories”并查找以“hbase”结尾的新状态，状态为“Open”，然后选择它。使用树视图展开存储库内容列表，并检查您期望的工件是否存在。检查 POM。只要暂存存储仓库处于打开状态，您就可以在缺少某些内容或构建错误时重新上传。

    如果出现严重错误并且您想要撤消上传，可以使用“删除”按钮删除和删除暂存存储库。有时上传在中间失败。这是您可能必须从暂存存储库中“删除”上载的另一个原因。

    如果签出，请使用“关闭”按钮关闭仓库。必须先关闭存储库，然后才能使用它的公共 URL。存储库可能需要几分钟才能关闭。完成后，您将在 Nexus UI 中看到存储库的公共 URL。您可能还会收到一封包含该 URL 的电子邮件。在宣布候选发布版的电子邮件中提供临时登台存储库的 URL。 （人们需要将此 repo URL 添加到其本地 poms 或其本地 _settings.xml_ 文件中以提取已发布的候选工件。）

    当发布投票成功结束时，返回此处并单击“发布”按钮以将工件发布到中央。发布过程将自动删除并删除暂存存储库。

    &gt; HBase 的-downstreamer
    &gt; 
    &gt; 请参阅 [hbase-downstreamer](https://github.com/saintstack/hbase-downstreamer) 测试，了解 HBase 下游的项目的简单示例，具体取决于它。检查并运行其简单测试，以确保 maven 工件正确部署到 maven 存储库。请务必编辑 pom 以指向正确的临时存储库。确保在测试运行时从存储库中提取并且未从本地存储库获取，方法是传递`-U`标志或删除本地存储库内容并检查 maven 是否已从远程存储库中移出。

有关此 maven 登台过程的一些指示，请参阅[发布 Maven 工件](https://www.apache.org/dev/publishing-maven-artifacts.html)。

*   如果 HBase 版本以`-SNAPSHOT`结尾，则工件将转移到其他位置。它们直接放入 Apache 快照存储库并立即可用。发布 SNAPSHOT，这就是您想要发生的事情。

*   在此阶段，您在“构建输出目录”中有两个 tarball，并且在 maven 存储库的暂存区域中有一组工件处于“关闭”状态。下一个签名，指纹然后通过 svnpubsub“释放”你的发布候选构建输出目录，将你的目录提交到[开发分发目录](https://dist.apache.org/repos/dist/dev/hbase/)（参见 [HBASE-10554 上的评论请从镜像系统中删除旧版本](https://issues.apache.org/jira/browse/HBASE-10554)但实质上它是 [dev / hbase](https://dist.apache.org/repos/dist/dev/hbase) 的 svn 结账 - 发布在[发布/ hbase](https://dist.apache.org/repos/dist/release/hbase) ）。在 _ 版本目录 _ 中运行以下命令：

```
$ for i in *.tar.gz; do echo $i; gpg --print-md MD5 $i > $i.md5 ; done
$ for i in *.tar.gz; do echo $i; gpg --print-md SHA512 $i > $i.sha ; done
$ for i in *.tar.gz; do echo $i; gpg --armor --output $i.asc --detach-sig $i  ; done
$ cd ..
# Presuming our 'build output directory' is named 0.96.0RC0, copy it to the svn checkout of the dist dev dir
# in this case named hbase.dist.dev.svn
$ cd /Users/stack/checkouts/hbase.dist.dev.svn
$ svn info
Path: .
Working Copy Root Path: /Users/stack/checkouts/hbase.dist.dev.svn
URL: https://dist.apache.org/repos/dist/dev/hbase
Repository Root: https://dist.apache.org/repos/dist
Repository UUID: 0d268c88-bc11-4956-87df-91683dc98e59
Revision: 15087
Node Kind: directory
Schedule: normal
Last Changed Author: ndimiduk
Last Changed Rev: 15045
Last Changed Date: 2016-08-28 11:13:36 -0700 (Sun, 28 Aug 2016)
$ mv 0.96.0RC0 /Users/stack/checkouts/hbase.dist.dev.svn
$ svn add 0.96.0RC0
$ svn commit ... 
```

*   通过检查 [https://dist.apache.org/repos/dist/dev/hbase/](https://dist.apache.org/repos/dist/dev/hbase/) 确保实际发布。

宣布邮件列表中的候选发布者并进行投票。

### 168.2。将 SNAPSHOT 发布到 maven

确保您的 _settings.xml_ 设置正确（参见[示例 _〜/ .m2 / settings.xml_ 文件](#maven.settings.xml)）。确保 hbase 版本包含`-SNAPSHOT`作为后缀。以下是发布其 poms 中 hbase 版本为 0.96.0 的发行版的 SNAPSHOTS 的示例。

```
 $ mvn clean install -DskipTests  javadoc:aggregate site assembly:single -Prelease
 $ mvn -DskipTests  deploy -Papache-release 
```

上面提到的 _make _rc.sh_ 脚本（参见 [maven.release](#maven.release) ）可以帮助您发布`SNAPSHOTS`。在运行脚本之前，请确保`hbase.version`后缀为`-SNAPSHOT`。它会将快照放入 apache 快照存储库中。

## 169.对候选人进行投票

鼓励每个人尝试对 HBase 候选人进行投票。只有 PMC 成员的投票具有约束力。 PMC 成员，请阅读关于候选发布候选人[发布政策](https://github.com/rectang/asfrelease/blob/master/release.md)的政策投票的 WIP 文档。 [quote] _ 在投出 1 个绑定票之前，个人需要将签名的源代码包下载到他们自己的硬件上，按照提供的方式编译，并在自己的平台上测试生成的可执行文件，同时验证加密签名和验证该程序包符合 ASF 关于发布的策略的要求。_ 关注后者，运行+ mvn apache-rat：检查以验证所有文件是否获得适当许可。参见 [HBase，mail＃dev - 最近讨论澄清 ASF 发布政策](http://search-hadoop.com/m/DHED4dhFaU)。我们是如何到达这个过程的。

## 170.宣布发布

一旦 RC 成功通过并且所需的工件已经上演分配，您需要让每个人都知道我们闪亮的新版本。这不是一项要求，但为了让发布经理们更轻松，我们可以为您提供一个模板。请务必使用相关版本号替换 _ 版本 _ 和其他标记。您应该在发送之前手动验证所有链接。

```
The HBase team is happy to announce the immediate availability of HBase _version_.

Apache HBase™ is an open-source, distributed, versioned, non-relational database.
Apache HBase gives you low latency random access to billions of rows with
millions of columns atop non-specialized hardware. To learn more about HBase,
see https://hbase.apache.org/.

HBase _version_ is the _nth_ minor release in the HBase _major_.x line, which aims to
improve the stability and reliability of HBase. This release includes roughly
XXX resolved issues not covered by previous _major_.x releases.

Notable new features include:
- List text descriptions of features that fit on one line
- Including if JDK or Hadoop support versions changes
- If the "stable" pointer changes, call that out
- For those with obvious JIRA IDs, include them (HBASE-YYYYY)

The full list of issues can be found in the included CHANGES.md and RELEASENOTES.md,
or via our issue tracker:

    https://s.apache.org/hbase-_version_-jira

To download please follow the links and instructions on our website:

    https://hbase.apache.org/downloads.html

Question, comments, and problems are always welcome at: dev@hbase.apache.org.

Thanks to all who contributed and made this release possible.

Cheers,
The HBase Dev Team 
```

您应将此消息发送到以下列表： [dev@hbase.apache.org](mailto:dev@hbase.apache.org) ， [user@hbase.apache.org](mailto:user@hbase.apache.org) ， [announce@apache.org](mailto:announce@apache.org) 。如果您想在发送之前进行抽查，请随时通过 jira 或开发者列表询问。

## 171.生成 HBase 参考指南

该手册使用 Asciidoc 进行了标记。然后我们使用 [Asciidoctor maven 插件](http://asciidoctor.org/docs/asciidoctor-maven-plugin/)将标记转换为 html。当您在运行 mvn site 时指定站点目标时，将运行此插件。有关构建文档的更多信息，请参阅文档的[附录。](#appendix_contributing_to_documentation)

## 172.更新 [hbase.apache.org](https://hbase.apache.org)

### 172.1。贡献给 hbase.apache.org

有关对文档或网站做出贡献的更多信息，请参阅文档的[附录。](#appendix_contributing_to_documentation)

### 172.2。发布 [hbase.apache.org](https://hbase.apache.org)

有关发布网站和文档的说明，请参阅[发布 HBase 网站和文档](#website_publish)。

## 173.测试

开发人员至少应该熟悉单元测试细节; HBase 中的单元测试具有其他项目中通常不会出现的特征。

此信息是关于 HBase 本身的单元测试。有关为 HBase 应用程序开发单元测试的信息，请参阅 [unit.tests](#unit.tests) 。

### 173.1。 Apache HBase 模块

截至 0.96，Apache HBase 分为多个模块。这为编写测试的方式和位置创建了“有趣的”规则。如果您正在为`hbase-server`编写代码，请参阅 [hbase.unittests](#hbase.unittests) 以了解如何编写测试。这些测试可以启动 minicluster 并需要进行分类。对于任何其他模块，例如`hbase-common`，测试必须是严格的单元测试，并且只测试被测试的类 - 不允许使用 HBaseTestingUtility 或 minicluster（或者甚至可以给定依赖树）。

#### 173.1.1。测试 HBase Shell

HBase shell 及其测试主要用 jruby 编写。

为了使这些测试作为标准构建的一部分运行，有一些 JUnit 测试类负责加载 jruby 实现的测试并运行它们。测试分为不同的类，以适应类级超时（详见[单元测试](#hbase.unittests)）。您可以从顶层运行所有这些测试：

```
 mvn clean test -Dtest=Test*Shell 
```

如果您之前已经完成了`mvn install`，那么您可以指示 maven 仅运行 hbase-shell 模块中的测试：

```
 mvn clean test -pl hbase-shell 
```

或者，您可以限制使用系统变量`shell.test`运行的 shell 测试。此值应按名称指定特定测试用例的 ruby 文字等效项。例如，覆盖用于更改表的 shell 命令的测试包含在测试用例`AdminAlterTableTest`中，您可以使用以下命令运行它们：

```
 mvn clean test -pl hbase-shell -Dshell.test=/AdminAlterTableTest/ 
```

您还可以使用 [Ruby Regular Expression 文字](http://docs.ruby-doc.com/docs/ProgrammingRuby/html/language.html#UJ)（`/pattern/`样式）来选择一组测试用例。您可以使用以下命令运行所有与 HBase 管理相关的测试，包括正常管理和安全管理：

```
 mvn clean test -pl hbase-shell -Dshell.test=/.*Admin.*Test/ 
```

如果测试失败，您可以通过检查 surefire 报告结果的 XML 版本来查看详细信息

```
 vim hbase-shell/target/surefire-reports/TEST-org.apache.hadoop.hbase.client.TestShell.xml 
```

#### 173.1.2。在其他模块中运行测试

如果您正在开发的模块没有其他 HBase 模块的其他依赖项，那么您可以进入该模块并运行：

```
mvn test 
```

这将只运行模块中的测试。如果其他模块存在其他依赖关系，那么您将从 ROOT HBASE DIRECTORY 运行该命令。这将在其他模块中运行测试，除非您指定跳过该模块中的测试。例如，要跳过 hbase-server 模块中的测试，您将运行：

```
mvn clean test -PskipServerTests 
```

从顶级目录运行除 hbase-server 之外的模块中的所有测试。请注意，您可以指定跳过多个模块中的测试以及单个模块的测试。例如，要跳过`hbase-server`和`hbase-common`中的测试，您将运行：

```
mvn clean test -PskipServerTests -PskipCommonTests 
```

另外，请记住，如果在`hbase-server`模块中运行测试，则需要应用 [hbase.unittests.cmds](#hbase.unittests.cmds) 中讨论的 maven 配置文件，以使测试正常运行。

### 173.2。单元测试

Apache HBase 单元测试必须带有类别注释，从`hbase-2.0.0`开始，必须加上 HBase `ClassRule`。以下是包含 Category 和 ClassRule 的 Test Class 的示例：

```
...
@Category(SmallTests.class)
public class TestHRegionInfo {
  @ClassRule
  public static final HBaseClassTestRule CLASS_RULE =
      HBaseClassTestRule.forClass(TestHRegionInfo.class);

  @Test
  public void testCreateHRegionInfoName() throws Exception {
    // ...
  }
} 
```

这里的测试类是`TestHRegionInfo`。 `CLASS_RULE`在每个测试类中具有相同的形式，只有你传递的`.class`是本地测试的形式;即在 TestTimeout 测试类中，你将`TestTimeout.class`传递给`CLASS_RULE`而不是我们上面的`TestHRegionInfo.class`。 `CLASS_RULE`是我们强制执行超时的（目前设置为所有测试的硬限制为 13 分钟 - 780 秒）和其他跨单元测试设施。测试在`SmallTest`类别中。

类别可以是任意的，并作为列表提供，但每个测试必须携带以下列表中的一个：`small`，`medium`，`large`和`integration`。使用 JUnit [类别](https://github.com/junit-team/junit4/wiki/Categories)：`SmallTests`，`MediumTests`，`LargeTests`，`IntegrationTests`指定测试大小。 JUnit 类别使用 java 注释表示（特殊单元测试在所有单元 tess 中查找@Category 注释的存在，如果发现测试套件缺少大小标记，则会失败）。

前三个类别`small`，`medium`和`large`用于键入`$ mvn test`时运行的测试用例。换句话说，这三个分类用于 HBase 单元测试。 `integration`类别不是用于单元测试，而是用于集成测试。这些通常在您调用`$ mvn verify`时运行。集成测试在 [integration.tests](#integration.tests) 中描述。

继续阅读以确定新的 HBase 测试用例上的集合`small`，`medium`和`large`的注释。

分类测试

小测试

_ 小型 _ 测试用例在共享 JVM 中执行，每个测试套件/测试类应在 15 秒或更短时间内运行;即一个 [junit 测试夹具](https://en.wikipedia.org/wiki/JUnit)，一个由测试方法组成的 java 对象，应该在 15 秒内完成，无论它有多少或几乎没有测试方法。这些测试用例不应使用 minicluster。

中等测试

_ 中 _ 测试用例在单独的 JVM 和单独的测试套件或测试类中执行，或者以 junit 的说法执行，[测试夹具](https://en.wikipedia.org/wiki/JUnit)应该在 50 秒或更短的时间内运行。这些测试用例可以使用迷你集群。

大型测试

_ 大型 _ 测试案例就是其他一切。它们通常是大规模测试，特定错误的回归测试，超时测试或性能测试。没有大型测试套件可能需要超过十分钟。随着时间的推移会被杀死。如果需要运行更长时间，请将测试作为集成测试。

集成测试

_ 集成 _ 测试是系统级测试。有关详细信息，请参阅 [integration.tests](#integration.tests) 。如果在集成测试中调用`$ mvn test`，则测试没有超时。

### 173.3。运行测试

#### 173.3.1。默认值：中小类别测试

运行`mvn test`将在单个 JVM（无分支）中执行所有小测试，然后在单独的 JVM 中为每个测试实例执行中等测试。如果小测试中存在错误，则不执行中等测试。不执行大型测试。

#### 173.3.2。运行所有测试

运行`mvn test -P runAllTests`将在单个 JVM 中执行小型测试，然后在单独的 JVM 中为每个测试执行中型和大型测试。如果小测试中存在错误，则不执行中型和大型测试。

#### 173.3.3。在包中运行单个测试或所有测试

要进行单独测试，例如`MyTest`，朗姆酒`mvn test -Dtest=MyTest`您还可以将多个单独的测试作为逗号分隔列表传递：

```
mvn test  -Dtest=MyTest1,MyTest2,MyTest3 
```

您还可以传递一个包，它将运行包下的所有测试：

```
mvn test '-Dtest=org.apache.hadoop.hbase.client.*' 
```

指定`-Dtest`时，将使用`localTests`配置文件。每个 junit 测试都在一个单独的 JVM（每个测试类的一个 fork）中执行。在此模式下运行测试时没有并行化。您将在-report 的末尾看到一条新消息：`"[INFO] Tests are skipped"`。这是无害的。但是，您需要确保测试报告的`Results:`部分中`Tests run:`的总和与您指定的测试数相匹配，因为在指定不存在的测试用例时不会报告错误。

#### 173.3.4。其他测试调用排列

运行`mvn test -P runSmallTests`将仅使用单个 JVM 执行“小”测试。

运行`mvn test -P runMediumTests`将仅执行“中”测试，为每个测试类启动一个新的 JVM。

运行`mvn test -P runLargeTests`将仅执行“大型”测试，为每个测试类启动一个新的 JVM。

为方便起见，您可以使用单个 JVM 运行`mvn test -P runDevTests`来执行小型和中型测试。

#### 173.3.5。更快地运行测试

默认情况下，`$ mvn test -P runAllTests`并行运行 5 个测试。它可以在开发人员的机器上增加。允许每个核心可以并行进行 2 次测试，每次测试需要大约 2GB 内存（在极端情况下），如果你有 8 核 24GB 盒子，你可以并行进行 16 次测试。但可用内存将其限制为 12（24/2），要并行执行 12 次测试的所有测试，请执行以下操作：mvn test -P runAllTests -Dsurefire.secondPartForkCount = 12。如果使用早于 2.0 的版本，请执行：+ mvn test -P runAllTests -Dsurefire.secondPartThreadCount = 12 +。要提高速度，您也可以使用 ramdisk。您将需要 2GB 的内存来运行所有测试。您还需要在两次测试运行之间删除文件。在 Linux 上配置 ramdisk 的典型方法是：

```
$ sudo mkdir /ram2G
sudo mount -t tmpfs -o size=2048M tmpfs /ram2G 
```

然后，您可以使用以下命令在 2.0 上运行所有 HBase 测试：

```
mvn test
                        -P runAllTests -Dsurefire.secondPartForkCount=12
                        -Dtest.build.data.basedirectory=/ram2G 
```

在早期版本中，使用：

```
mvn test
                        -P runAllTests -Dsurefire.secondPartThreadCount=12
                        -Dtest.build.data.basedirectory=/ram2G 
```

#### 173.3.6。 hbasetests.sh

也可以使用脚本 hbasetests.sh。此脚本与两个 maven 实例并行运行中型和大型测试，并提供单个报告。此脚本不使用 surefire 的 hbase 版本，因此除了脚本设置的两个 maven 实例之外，不会进行任何并行化。它必须从包含 _pom.xml_ 的目录执行。

例如，运行./dev-support/hbasetests.sh 将执行中小型测试。运行./dev-support/hbasetests.sh runAllTests 将执行所有测试。运行./dev-support/hbasetests.sh replayFailed 将在单独的 jvm 中重新运行失败的测试，并且没有并行化。

#### 173.3.7。测试超时

不严格执行 HBase 单元测试大小分类超时。

任何运行时间超过十分钟的测试都将超时/终止。

从 hbase-2.0.0 开始，我们已经清除了所有的每个测试方法超时：即

```
...
  @Test(timeout=30000)
  public void testCreateHRegionInfoName() throws Exception {
    // ...
  } 
```

考虑到我们是整个测试夹具/类/套件需要多长时间的基础，并且测试方法所需的时间差异在很大程度上取决于上下文（加载的 Apache 基础设施与开发人员机器），因此他们不鼓励并且没有多大意义没有别的东西在上面运行）。

#### 173.3.8。测试资源检查器

自定义 Maven SureFire 插件监听器在每个 HBase 单元测试运行之前和之后检查许多资源，并在测试输出文件的末尾记录其结果，这些文件可以在每个 Maven 模块的 _target / surefire-reports_ 中找到（测试将为测试类命名的测试报告写入此目录。检查 _* -out.txt_ 文件）。计算的资源是线程数，文件描述符数等。如果数量增加，它会增加 _LEAK？_ 在日志中发表评论。由于您可以在后台运行 HBase 实例，因此可以删除/创建一些线程，而无需在测试中执行任何特定操作。但是，如果测试不能按预期工作，或者测试不会影响这些资源，则值得检查这些日志行... hbase.ResourceChecker（157）：before ...和... hbase.ResourceChecker（157 ）：之后....例如：

```
2012-09-26 09:22:15,315 INFO [pool-1-thread-1]
hbase.ResourceChecker(157): after:
regionserver.TestColumnSeeking#testReseeking Thread=65 (was 65),
OpenFileDescriptor=107 (was 107), MaxFileDescriptor=10240 (was 10240),
ConnectionCount=1 (was 1) 
```

### 173.4。写测试

#### 173.4.1。通用规则

*   尽可能将测试编写为类别小测试。

*   必须编写所有测试以支持在同一台机器上并行执行，因此它们不应将共享资源用作固定端口或固定文件名。

*   测试不应该过度。超过 100 行/秒使得日志复杂化以便读取和使用 i / o，因此不能用于其他测试。

*   可以使用`HBaseTestingUtility`编写测试。此类提供辅助函数来创建临时目录并执行清理或启动集群。

#### 173.4.2。类别和执行时间

*   必须对所有测试进行分类，否则可以跳过它们。

*   所有测试都应尽可能快地编写。

*   见＆lt; &lt;hbase.unittests&gt;用于测试用例类别和相应的超时。这应确保使用它的人员具有良好的并行性，并在测试失败时简化分析。&lt;/hbase.unittests&gt;

#### 173.4.3。在测试中睡觉

只要有可能，测试不应该使用 Thread.sleep，而是等待他们需要的真实事件。这对读者来说更快更清晰。测试不应该在没有测试结束条件的情况下执行 Thread.sleep。这样可以了解测试正在等待的内容。而且，无论机器性能如何，测试都能正常工作。睡眠应该尽可能快。等待变量应该在 40ms 的睡眠循环中完成。等待套接字操作应该在 200 毫秒的睡眠循环中完成。

#### 173.4.4。使用群集进行测试

使用 HRegion 进行的测试不必启动集群：区域可以使用本地文件系统。启动/停止群集成本大约 10 秒。它们不应该按照测试方法而是按测试类启动。必须使用 HBaseTestingUtility＃shutdownMiniCluster 关闭已启动的集群，该程序清除目录。尽可能多地，测试应使用群集的默认设置。如果他们不这样做，他们应该记录下来。这将允许稍后共享群集。

#### 173.4.5。测试骨架代码

这是一个带有分类和基于类别的超时规则的测试框架代码，用于复制和粘贴并用作测试贡献的基础。

```
/**
 * Describe what this testcase tests. Talk about resources initialized in @BeforeClass (before
 * any test is run) and before each test is run, etc.
 */
// Specify the category as explained in <<hbase.unittests,hbase.unittests>>.
@Category(SmallTests.class)
public class TestExample {
  // Replace the TestExample.class in the below with the name of your test fixture class.
  private static final Log LOG = LogFactory.getLog(TestExample.class);

  // Handy test rule that allows you subsequently get the name of the current method. See
  // down in 'testExampleFoo()' where we use it to log current test's name.
  @Rule public TestName testName = new TestName();

  // The below rule does two things. It decides the timeout based on the category
  // (small/medium/large) of the testcase. This @Rule requires that the full testcase runs
  // within this timeout irrespective of individual test methods' times. The second
  // feature is we'll dump in the log when the test is done a count of threads still
  // running.
  @Rule public static TestRule timeout = CategoryBasedTimeout.builder().
    withTimeout(this.getClass()).withLookingForStuckThread(true).build();

  @Before
  public void setUp() throws Exception {
  }

  @After
  public void tearDown() throws Exception {
  }

  @Test
  public void testExampleFoo() {
    LOG.info("Running test " + testName.getMethodName());
  }
} 
```

### 173.5。集成测试

HBase 集成/系统测试是超出 HBase 单元测试的测试。它们通常是持久的，相当大的（测试可以被要求为 1M 行或 1B 行），可以定位（它们可以采取配置，将它们指向它们要运行的现成集群;集成测试不包括集群启动/停止代码），并验证成功，集成测试仅依赖于公共 API;他们不会尝试检查服务器内部断言成功/失败。当您需要对单元测试可以执行的发布候选项进行更详细的校对时，您将运行集成测试。它们通常不在 Apache Continuous Integration 构建服务器上运行，但是，一些站点选择运行集成测试作为其在实际集群上进行连续测试的一部分。

集成测试目前位于 hbase-it 子模块中的 _src / test_ 目录下，并且将匹配正则表达式： _*** / IntegrationTest** .java_ 。所有集成测试也使用`@Category(IntegrationTests.class)`进行注释。

集成测试可以以两种模式运行：使用迷你集群，或针对实际的分布式集群。 Maven failsafe 用于使用迷你集群运行测试。 IntegrationTestsDriver 类用于对分布式集群执行测试。集成测试不应该假设它们是针对迷你集群运行的，并且不应该使用私有 API 来访问集群状态。要统一地与分布式或迷你集群交互，可以使用`IntegrationTestingUtility`和`HBaseCluster`类以及公共客户端 API。

在分布式群集上，使用 ChaosMonkey 的集成测试或通过集群管理器（例如，重新启动区域服务器）操纵服务的集成测试使用 SSH 来执行此操作。要运行这些，测试进程应该能够在远程端运行命令，因此应该相应地配置 ssh（例如，如果 HBase 在集群中的 hbase 用户下运行，则可以为该用户设置无密码 ssh 并运行测试在它下面）。为此，可以使用`hbase.it.clustermanager.ssh.user`，`hbase.it.clustermanager.ssh.opts`和`hbase.it.clustermanager.ssh.cmd`配置设置。 “User”是集群管理器用于执行 ssh 命令的远程用户。 “Opts”包含传递给 SSH 的其他选项（例如，“ - i / tmp / my-key”）。最后，如果您有一些自定义环境设置，“cmd”是整个隧道（ssh）命令的覆盖格式。默认字符串是{`/usr/bin/ssh %1$s %2$s%3$s%4$s "%5$s"`}，是一个很好的起点。这是一个标准的 Java 格式字符串，带有 5 个参数，用于执行远程命令。参数 1（％1 $ s）是 SSH 选项设置 via opts 设置或通过环境变量，2 是 SSH 用户名，如果设置了 username，则 3 是“@”，否则，“4”是目标主机名，并且 5 是要执行的逻辑命令（可能包括单引号，因此不要使用它们）。例如，如果您在非 hbase 用户下运行测试并希望 ssh 作为该用户并在远程计算机上更改为 hbase，则可以使用：

```
/usr/bin/ssh %1$s %2$s%3$s%4$s "su hbase - -c \"%5$s\"" 
```

这样，杀死 RS（例如）集成测试可能会运行：

```
{/usr/bin/ssh some-hostname "su hbase - -c \"ps aux | ... | kill ...\""} 
```

该命令记录在测试日志中，因此您可以验证它是否适合您的环境。

要禁用集成测试的运行，请在命令行`-PskipIntegrationTests`上传递以下配置文件。例如，

```
$ mvn clean install test -Dtest=TestZooKeeper  -PskipIntegrationTests 
```

#### 173.5.1。针对迷你群集运行集成测试

HBase 0.92 添加了`verify` maven 目标。调用它，例如通过执行`mvn verify`，将通过 maven [故障安全插件](https://maven.apache.org/plugins/maven-failsafe-plugin/)运行所有阶段，包括验证阶段，运行所有上述 HBase 单元测试以及中的测试 HBase 集成测试组。完成 mvn install -DskipTests 后，您可以通过调用以下命令运行集成测试：

```
cd hbase-it
mvn verify 
```

如果您只想在顶层运行集成测试，则需要运行两个命令。第一：mvn failsafe：integration-test 这实际上运行所有集成测试。

> 即使存在测试失败，该命令也将始终输出`BUILD SUCCESS`。

此时，您可以手动查找输出失败的测试。但是，maven 会为我们这样做;只需使用：mvn failsafe：verify 上面的命令基本上查看了测试失败的所有测试结果（因此不要删除'target'目录）并报告结果。

##### 运行 Integration 测试的子集

这与您指定运行单元测试子集（参见上文）的方式非常相似，但使用属性`it.test`而不是`test`。要运行`IntegrationTestClassXYZ.java`，请使用：mvn failsafe：integration-test -Dit.test = IntegrationTestClassXYZ 您可能要做的下一件事是运行集成测试组，例如所有名为 IntegrationTestClassX _.java 的集成测试： mvn failsafe：integration-test -Dit.test =_ ClassX _ 这将运行与 **ClassX** 匹配的集成测试。这意味着任何匹配：“**_ / IntegrationTest _ClassX **”。您还可以使用逗号分隔列表运行多组集成测试（类似于单元测试）。使用匹配列表仍支持每个组的完整正则表达式匹配。这看起来像：mvn failsafe：integration-test -Dit.test =_ ClassX _，_ ClassY

#### 173.5.2。针对分布式群集运行集成测试

如果您已经安装了 HBase 集群，则可以通过调用类`IntegrationTestsDriver`来启动集成测试。您可能必须先运行 test-compile。配置将由 bin / hbase 脚本选取。

```
mvn test-compile 
```

然后启动测试：

```
bin/hbase [--config config_dir] org.apache.hadoop.hbase.IntegrationTestsDriver 
```

通过`-h`来使用这个甜蜜的工具。不带任何参数运行 IntegrationTestsDriver 将启动在`hbase-it/src/test`下找到的测试，具有`@Category(IntegrationTests.class)`注释，名称以`IntegrationTests`开头。通过传递-h 来查看用法，以了解如何过滤测试类。您可以传递一个正则表达式，该正则表达式将根据完整的类名进行检查;所以，可以使用类名的一部分。 IntegrationTestsDriver 使用 Junit 来运行测试。目前，不支持使用 maven 对分布式集群运行集成测试（参见 [HBASE-6201](https://issues.apache.org/jira/browse/HBASE-6201) ）。

测试通过使用`DistributedHBaseCluster`（实现`HBaseCluster`）类中的方法与分布式集群交互，后者又使用可插入的`ClusterManager`。具体实现提供了用于执行特定于部署和环境的任务（SSH 等）的实际功能。默认`ClusterManager`是`HBaseClusterManager`，它使用 SSH 远程执行 start / stop / kill / signal 命令，并假设一些 posix 命令（ps 等）。还假设运行测试的用户具有足够的“电源”来启动/停止远程计算机上的服务器。默认情况下，它从 env 中获取`HBASE_SSH_OPTS`，`HBASE_HOME`，`HBASE_CONF_DIR`，并使用`bin/hbase-daemon.sh`执行操作。目前支持 tarball 部署，使用 _hbase-daemons.sh_ 和 [Apache Ambari](https://incubator.apache.org/ambari/) 部署的部署。 _/etc/init.d/_ 脚本现在不受支持，但可以轻松添加。对于其他部署选项，可以实现和插入 ClusterManager。

#### 173.5.3。破坏性集成/系统测试（ChaosMonkey）

HBase 0.96 引入了一个名为`ChaosMonkey`的工具，该工具以 Netflix 的混沌猴工具的[同名工具为蓝本。 ChaosMonkey 通过终止或断开随机服务器或将其他故障注入环境来模拟正在运行的集群中的实际故障。您可以使用 ChaosMonkey 作为独立工具在其他测试运行时运行策略。在某些环境中，ChaosMonkey 始终在运行，以便不断检查高可用性和容错是否按预期工作。](https://netflix.github.io/chaosmonkey/)

ChaosMonkey 定义**动作**和**策略**。

操作

操作是预定义的事件序列，例如：

*   重启活动主人（睡 5 秒）

*   重启随机区域服务器（睡 5 秒）

*   重启随机区域服务器（睡眠 60 秒）

*   重启 META regionserver（睡 5 秒）

*   重启 ROOT regionserver（睡 5 秒）

*   批量重启 50％的区域服务器（睡眠 5 秒）

*   滚动重启 100％的区域服务器（睡眠 5 秒）

政策

策略是用于执行一个或多个动作的策略。默认策略基于预定义的操作权重每分钟执行一次随机操作。在 ChaosMonkey 中断之前，将执行给定的策略。

大多数 ChaosMonkey 操作都配置为具有合理的默认值，因此您可以针对现有群集运行 ChaosMonkey，而无需任何其他配置。以下示例使用默认配置运行 ChaosMonkey：

```
$ bin/hbase org.apache.hadoop.hbase.util.ChaosMonkey

12/11/19 23:21:57 INFO util.ChaosMonkey: Using ChaosMonkey Policy: class org.apache.hadoop.hbase.util.ChaosMonkey$PeriodicRandomActionPolicy, period:60000
12/11/19 23:21:57 INFO util.ChaosMonkey: Sleeping for 26953 to add jitter
12/11/19 23:22:24 INFO util.ChaosMonkey: Performing action: Restart active master
12/11/19 23:22:24 INFO util.ChaosMonkey: Killing master:master.example.com,60000,1353367210440
12/11/19 23:22:24 INFO hbase.HBaseCluster: Aborting Master: master.example.com,60000,1353367210440
12/11/19 23:22:24 INFO hbase.ClusterManager: Executing remote command: ps aux | grep master | grep -v grep | tr -s ' ' | cut -d ' ' -f2 | xargs kill -s SIGKILL , hostname:master.example.com
12/11/19 23:22:25 INFO hbase.ClusterManager: Executed remote command, exit code:0 , output:
12/11/19 23:22:25 INFO hbase.HBaseCluster: Waiting service:master to stop: master.example.com,60000,1353367210440
12/11/19 23:22:25 INFO hbase.ClusterManager: Executing remote command: ps aux | grep master | grep -v grep | tr -s ' ' | cut -d ' ' -f2 , hostname:master.example.com
12/11/19 23:22:25 INFO hbase.ClusterManager: Executed remote command, exit code:0 , output:
12/11/19 23:22:25 INFO util.ChaosMonkey: Killed master server:master.example.com,60000,1353367210440
12/11/19 23:22:25 INFO util.ChaosMonkey: Sleeping for:5000
12/11/19 23:22:30 INFO util.ChaosMonkey: Starting master:master.example.com
12/11/19 23:22:30 INFO hbase.HBaseCluster: Starting Master on: master.example.com
12/11/19 23:22:30 INFO hbase.ClusterManager: Executing remote command: /homes/enis/code/hbase-0.94/bin/../bin/hbase-daemon.sh --config /homes/enis/code/hbase-0.94/bin/../conf start master , hostname:master.example.com
12/11/19 23:22:31 INFO hbase.ClusterManager: Executed remote command, exit code:0 , output:starting master, logging to /homes/enis/code/hbase-0.94/bin/../logs/hbase-enis-master-master.example.com.out
....
12/11/19 23:22:33 INFO util.ChaosMonkey: Started master: master.example.com,60000,1353367210440
12/11/19 23:22:33 INFO util.ChaosMonkey: Sleeping for:51321
12/11/19 23:23:24 INFO util.ChaosMonkey: Performing action: Restart random region server
12/11/19 23:23:24 INFO util.ChaosMonkey: Killing region server:rs3.example.com,60020,1353367027826
12/11/19 23:23:24 INFO hbase.HBaseCluster: Aborting RS: rs3.example.com,60020,1353367027826
12/11/19 23:23:24 INFO hbase.ClusterManager: Executing remote command: ps aux | grep regionserver | grep -v grep | tr -s ' ' | cut -d ' ' -f2 | xargs kill -s SIGKILL , hostname:rs3.example.com
12/11/19 23:23:25 INFO hbase.ClusterManager: Executed remote command, exit code:0 , output:
12/11/19 23:23:25 INFO hbase.HBaseCluster: Waiting service:regionserver to stop: rs3.example.com,60020,1353367027826
12/11/19 23:23:25 INFO hbase.ClusterManager: Executing remote command: ps aux | grep regionserver | grep -v grep | tr -s ' ' | cut -d ' ' -f2 , hostname:rs3.example.com
12/11/19 23:23:25 INFO hbase.ClusterManager: Executed remote command, exit code:0 , output:
12/11/19 23:23:25 INFO util.ChaosMonkey: Killed region server:rs3.example.com,60020,1353367027826\. Reported num of rs:6
12/11/19 23:23:25 INFO util.ChaosMonkey: Sleeping for:60000
12/11/19 23:24:25 INFO util.ChaosMonkey: Starting region server:rs3.example.com
12/11/19 23:24:25 INFO hbase.HBaseCluster: Starting RS on: rs3.example.com
12/11/19 23:24:25 INFO hbase.ClusterManager: Executing remote command: /homes/enis/code/hbase-0.94/bin/../bin/hbase-daemon.sh --config /homes/enis/code/hbase-0.94/bin/../conf start regionserver , hostname:rs3.example.com
12/11/19 23:24:26 INFO hbase.ClusterManager: Executed remote command, exit code:0 , output:starting regionserver, logging to /homes/enis/code/hbase-0.94/bin/../logs/hbase-enis-regionserver-rs3.example.com.out

12/11/19 23:24:27 INFO util.ChaosMonkey: Started region server:rs3.example.com,60020,1353367027826\. Reported num of rs:6 
```

输出表明 ChaosMonkey 启动了默认的`PeriodicRandomActionPolicy`策略，该策略配置了所有可用的操作。它选择运行`RestartActiveMaster`和`RestartRandomRs`动作。

#### 173.5.4。可用政策

HBase 附带了几个 ChaosMonkey 策略，可在`hbase/hbase-it/src/test/java/org/apache/hadoop/hbase/chaos/policies/`目录中找到。

#### 173.5.5。配置单个 ChaosMonkey 操作

可以在每次测试运行中配置 ChaosMonkey 集成测试。在 HBase CLASSPATH 中创建 Java 属性文件，并使用`-monkeyProps`配置标志将其传递给 ChaosMonkey。可配置属性及其默认值（如果适用）列在`org.apache.hadoop.hbase.chaos.factories.MonkeyConstants`类中。对于具有默认值的属性，可以通过将它们包含在属性文件中来覆盖它们。

以下示例使用名为 [monkey.properties](#monkey.properties) 的属性文件。

```
$ bin/hbase org.apache.hadoop.hbase.IntegrationTestIngest -m slowDeterministic -monkeyProps monkey.properties 
```

上面的命令将启动集成测试和混乱猴子。它将在 HBase CLASSPATH 上查找属性文件 _monkey.properties_ ;例如在 HBASE _conf_ dir 里面。

这是一个混乱的猴子文件示例：

示例 ChaosMonkey 属性文件

```
sdm.action1.period=120000
sdm.action2.period=40000
move.regions.sleep.time=80000
move.regions.max.time=1000000
move.regions.sleep.time=80000
batch.restart.rs.ratio=0.4f 
```

周期/时间以毫秒表示。

HBase 1.0.2 和更新版本增加了重启 HBase 底层 ZooKeeper 仲裁或 HDFS 节点的能力。要使用这些操作，您需要在 ChaosMonkey 属性文件中配置一些新属性，这些属性没有合理的默认值，因为它们是特定于部署的，可能是`hbase-site.xml`或不同的属性文件。

```
<property>
  <name>hbase.it.clustermanager.hadoop.home</name>
  <value>$HADOOP_HOME</value>
</property>
<property>
  <name>hbase.it.clustermanager.zookeeper.home</name>
  <value>$ZOOKEEPER_HOME</value>
</property>
<property>
  <name>hbase.it.clustermanager.hbase.user</name>
  <value>hbase</value>
</property>
<property>
  <name>hbase.it.clustermanager.hadoop.hdfs.user</name>
  <value>hdfs</value>
</property>
<property>
  <name>hbase.it.clustermanager.zookeeper.user</name>
  <value>zookeeper</value>
</property> 
```

## 174.开发者指南

### 174.1。分行

我们使用 Git 进行源代码管理，并在`master`分支上进行最新的开发。过去的主要/次要/维护版本都有分支，重要的功能和错误修复通常会反向移植到它们。

### 174.2。代码标准

#### 174.2.1。接口分类

界面按受众和稳定性级别进行分类。这些标签出现在班级的头部。 HBase 遵循的约定由其父项目 Hadoop 继承。

通常使用以下接口分类：

InterfaceAudience

`@InterfaceAudience.Public`

用户和 HBase 应用程序的 API。这些 API 将通过主要版本的 HBase 弃用。

`@InterfaceAudience.Private`

HBase 内部开发人员的 API。在将来的版本中不保证兼容性或可用性。专用接口不需要`@InterfaceStability`分类。

`@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.COPROC)`

HBase 协处理器编写器的 API。

没有`@InterfaceAudience`分类

没有`@InterfaceAudience`标签的包被视为私有。如果可以公开访问，请标记新包。

> 从 API 文档中排除非公共接口
> 
> 只有分类`@InterfaceAudience.Public`的接口才应包含在 API 文档（Javadoc）中。对于不包含公共类的新包，提交者必须为 _pom.xml_ 添加新包，不包括`ExcludePackageNames`部分。

@InterfaceStability

`@InterfaceStability`对标有`@InterfaceAudience.Public`的包很重要。

`@InterfaceStability.Stable`

如果没有弃用路径或非常好的理由，则无法更改标记为稳定的公共包。

`@InterfaceStability.Unstable`

标记为不稳定的公共包可以在没有弃用路径的情况下进行更改。

`@InterfaceStability.Evolving`

标记为演变的公共包可能会被更改，但不鼓励使用。

没有`@InterfaceStability`标签

不鼓励没有`@InterfaceStability`标签的公共类，并且应该将其视为隐式不稳定。

如果您不清楚如何标记包，请在开发列表中询问。

#### 174.2.2。代码格式约定

请遵循以下准则，以便更快地审核您的补丁。这些指南是基于对新贡献者的补丁的共同反馈而开发的。

有关 Java 编码约定的更多信息，请参见 [Java 编程语言的代码约定](http://www.oracle.com/technetwork/java/index-135089.html)。请参阅 [eclipse.code.formatting](#eclipse.code.formatting) 以设置 Eclipse 以自动检查其中一些指南。

##### 太空侵略者

不要在括号周围使用额外的空格。使用第二种风格，而不是第一种风格。

```
if ( foo.equals( bar ) ) {     // don't do this 
```

```
if (foo.equals(bar)) { 
```

```
foo = barArray[ i ];     // don't do this 
```

```
foo = barArray[i]; 
```

##### 自动生成的代码

Eclipse 中自动生成的代码通常使用错误的变量名，例如`arg0`。使用更具信息性的变量名称。像这里的第二个例子一样使用代码。

```
 public void readFields(DataInput arg0) throws IOException {    // don't do this
   foo = arg0.readUTF();                                       // don't do this 
```

```
 public void readFields(DataInput di) throws IOException {
   foo = di.readUTF(); 
```

##### 排长龙

保持行少于 100 个字符。您可以将 IDE 配置为自动执行此操作。

```
Bar bar = foo.veryLongMethodWithManyArguments(argument1, argument2, argument3, argument4, argument5, argument6, argument7, argument8, argument9);  // don't do this 
```

```
Bar bar = foo.veryLongMethodWithManyArguments(
 argument1, argument2, argument3,argument4, argument5, argument6, argument7, argument8, argument9); 
```

##### 尾随空间

确保在代码结束后有一个换行符，并避免只有空格的行。这使得差异更有意义。您可以配置 IDE 以帮助解决此问题。

```
Bar bar = foo.getBar();     <--- imagine there is an extra space(s) after the semicolon. 
```

##### API 文档（Javadoc）

别忘了 Javadoc！

在预先提交期间检查 Javadoc 警告。如果预先提交工具给你一个'-1'，请修复 javadoc 问题。如果添加此类警告，则不会提交您的补丁。

此外，没有`@author`标签 - 这是一个规则。

##### FindBugs 的

`Findbugs`用于检测常见错误模式。在 precommit 构建期间检查它。如果发现错误，请修复它们。您可以使用`mvn findbugs:findbugs`在本地运行 findbugs，它将在本地生成`findbugs`文件。有时，您可能必须编写比`findbugs`更智能的代码。您可以通过使用以下注释对类进行注释来注释代码以告诉`findbugs`您知道自己在做什么：

```
@edu.umd.cs.findbugs.annotations.SuppressWarnings(
value="HE_EQUALS_USE_HASHCODE",
justification="I know what I'm doing") 
```

使用 Apache 许可版本的注释很重要。这通常意味着在`edu.umd.cs.findbugs.annotations`包中使用注释，这样我们就可以依赖于洁净室重新实现而不是`javax.annotations`包中的注释。

##### Javadoc - 无用的默认值

不要像 IDE 生成它们那样保留 javadoc 标记，也不要在其中填充冗余信息。

```
 /**
   * @param table                              <---- don't leave them empty!
   * @param region An HRegion object.          <---- don't fill redundant information!
   * @return Foo Object foo just created.      <---- Not useful information
   * @throws SomeException                     <---- Not useful. Function declarations already tell that!
   * @throws BarException when something went wrong  <---- really?
   */
  public Foo createFoo(Bar bar); 
```

添加描述符号的内容，或者只删除它们。首选是添加描述性和有用的东西。

##### 一次一件事，伙计们

如果您为一件事提交补丁，请不要在完全不同的代码区域上进行自动重新格式化或不相关的代码重新格式化。

同样，不要在 Jira 的范围之外添加不相关的清理或重构。

##### 模糊单元测试

确保您清楚自己在单元测试中测试的内容以及原因。

##### 实现可写

> 适用于 0.96 之前的版本
> 
> 在 0.96 中，HBase 转移到协议缓冲区（protobufs）。关于 Writables 的以下部分适用于 0.94.x 及之前，而不是 0.96 及更高版本。

RegionServers 返回的每个类都必须实现`Writable`接口。如果要创建需要实现此接口的新类，请不要忘记默认构造函数。

#### 174.2.3。垃圾收集保护指南

以下指南来自 [http://engineering.linkedin.com/performance/linkedin-feed-faster-less-jvm-garbage](http://engineering.linkedin.com/performance/linkedin-feed-faster-less-jvm-garbage) 。牢记这一点，将可预防的垃圾收集工作降至最低。请查看博客文章，了解如何根据这些指南重构代码的一些很好的示例。

*   对迭代器要小心

*   初始化时估计集合的大小

*   推迟表达评估

*   提前编译正则表达式模式

*   如果可以，请缓存它

*   字符串实习生很有用但很危险

### 174.3。不变

我们没有很多，但我们在下面列出了什么。当然所有都受到挑战，但在此之前，请遵守道路规则。

#### 174.3.1。 ZooKeeper 中没有永久状态

ZooKeeper 状态应该是瞬态的（将其视为内存）。如果删除 ZooKeeper 状态，hbase 应该能够恢复并且基本上处于相同的状态。

*   .Exceptions：目前我们需要解决几个例外，无论表是启用还是禁用。

*   复制数据当前仅存储在 ZooKeeper 中。删除与复制相关的 ZooKeeper 数据可能会导致禁用复制。不要删除复制树， _/ hbase / replication /_ 。

    &gt; 如果从 ZooKeeper 中删除复制树（ _/ hbase / replication /_ ），则可能会中断复制并导致数据丢失。在 [HBASE-10295](https://issues.apache.org/jira/browse/HBASE-10295) 上关注此问题的进展。

### 174.4。原地运行

如果您正在开发 Apache HBase，那么测试您对更真实的集群的更改通常比您在单元测试中找到的更有用。在这种情况下，HBase 可以在本地模式下直接从源运行。您需要做的就是运行：

```
${HBASE_HOME}/bin/start-hbase.sh 
```

这将启动一个完整的本地群集，就像您已打包 HBase 并将其安装在您的计算机上一样。

请记住，您需要将 HBase 安装到本地 maven 存储库中，以使原位群集正常工作。也就是说，您需要运行：

```
mvn clean install -DskipTests 
```

确保 maven 可以找到正确的类路径和依赖项。一般来说，如果 maven 行为奇怪，上面的命令首先尝试运行是一件好事。

### 174.5。添加指标

添加新功能后，开发人员可能希望添加指标。 HBase 使用 Hadoop Metrics 2 系统公开指标，因此添加新指标涉及将该指标公开给 hadoop 系统。不幸的是，metrics2 的 API 从 hadoop 1 变为 hadoop 2.为了解决这个问题，必须在运行时加载一组接口和实现。要深入了解这些类的推理和结构，您可以阅读[这里的博客文章](https://blogs.apache.org/hbase/entry/migration_to_the_new_metrics)。要向现有 MBean 添加指标，请遵循以下简短指南：

#### 174.5.1。将度量标准名称和函数添加到 Hadoop Compat 接口。

在源接口内部，对应于生成度量的位置（例如，来自 HMaster 的事物的 MetricsMasterSource）为度量标准名称和描述创建新的静态字符串。然后添加一个将被调用以添加新读数的新方法。

#### 174.5.2。将实现添加到 Hadoop 1 和 Hadoop 2 Compat 模块。

在源的实现内部（例如，上例中的 MetricsMasterSourceImpl）在 init 方法中创建新的直方图，计数器，计量器或 stat。然后在添加到接口的方法中连接传入直方图的参数。

现在添加测试以确保数据正确导出到 metrics 2 系统。为此，提供了 MetricsAssertHelper。

### 174.6。 Git 最佳实践

避免 git 合并。

使用`git pull --rebase`或`git fetch`，然后按`git rebase`。

不要使用`git push --force`。

如果推送不起作用，请解决问题或寻求帮助。

如果您考虑其他 Git 最佳实践，请参与此文档。

#### 174.6.1。 `rebase_all_git_branches.sh`

提供了 _dev-support / rebase_all_git _branches.sh_ 脚本以帮助保持 Git 存储库的清洁。使用`-h`参数获取使用说明。该脚本会自动刷新您的跟踪分支，尝试针对其远程分支自动重新定位每个本地分支，并为您提供删除代表已关闭`HBASE-` JIRA 的任何分支的选项。该脚本有一个可选的配置选项，即 Git 目录的位置。您可以通过编辑脚本来设置默认值。否则，您可以使用`-d`参数手动传递 git 目录，然后使用绝对或相对目录名称，甚至是“。”对于当前的工作目录。在继续之前，脚本会检查目录中是否有名为 _.git /_ 的子目录。

### 174.7。提交补丁

如果您不熟悉提交补丁到开源或新提交补丁到 Apache，请首先阅读 [Apache Commons Project](https://commons.apache.org/) 中的 [On Contributing Patches](https://commons.apache.org/patches.html) 页面。它提供了一个很好的概述，同样适用于 Apache HBase 项目。

#### 174.7.1。创建补丁

请务必查看 [common.patch.feedback](#common.patch.feedback) 的代码样式。如果您的补丁生成不正确或您的代码不符合代码格式指南，则可能会要求您重做某些工作。

使用 submit-patch.py​​（推荐）

```
$ dev-support/submit-patch.py -jid HBASE-xxxxx 
```

使用此脚本创建修补程序，上传到 jira 并可选择在 Re​​view Board 上创建/更新评论。补丁名称自动格式化为 _（JIRA）。（分支名称）。（补丁号）。补丁 _ 遵循 Yetus 的命名规则。使用`-h`标志了解详细的使用信息。最有用的选项是：

*   `-b BRANCH, --branch BRANCH`：指定用于生成 diff 的基本分支。如果未指定，则使用跟踪分支。如果没有跟踪分支，则会抛出错误。

*   `-jid JIRA_ID, --jira-id JIRA_ID`：如果使用，则从 jira 中的附件推断下一个补丁版本并上传新补丁。脚本将要求 jira 用户名/密码进行身份验证。如果未设置，则将补丁命名为 &lt;branch&gt;.patch。&lt;/branch&gt;

默认情况下，它还会创建/更新审核委员会。要跳过该操作，请使用`-srb`选项。它使用 jira 中的“问题链接”来确定审核请求是否已存在。如果没有审核请求，则创建一个新请求并使用 jira 摘要，补丁说明等填充所有必填字段。此外，还将此评论的链接添加到 jira。

保存身份验证凭据（可选）

由于在 JIRA 上附加补丁并在 ReviewBoard 上创建/更改审阅请求需要有效的用户身份验证，因此脚本将提示您输入用户名和密码。为了避免每次麻烦，请使用登录详细信息设置`~/.apache-creds`并按照脚本帮助消息页脚中的步骤对其进行加密。

Python 依赖项

要安装所需的 python 依赖项，请从 master 分支执行`pip install -r dev-support/python-requirements.txt`。

手动

1.  首先使用`git rebase -i`，将较小的提交组合（压缩）到一个较大的提交中。

2.  使用 IDE 或 Git 命令创建补丁。 `git format-patch`是首选，因为它保留了补丁作者的姓名和提交消息。此外，它默认处理二进制文件，而`git diff`忽略它们，除非您使用`--binary`选项。

3.  补丁名称应如下符合 Ye​​tus 的命名约定：`(JIRA).(branch name).(patch number).patch`例如。 HBASE-11625.master.001.patch，HBASE-XXXXX.branch-1.2.0005.patch 等

4.  使用`More→Attach Files`将补丁附加到 JIRA，然后单击 **Submit Patch** 按钮，这将触发 Hudson 作业以检查补丁的有效性。

5.  如果您的补丁长于单个屏幕，还可以在 Review Board 上创建评论并添加指向 JIRA 的链接。参见[评论板](#reviewboard)。

一般指导原则很少

*   即使您要在另一个分支中进行修补，也要始终首先修补主分支。 HBase 提交程序始终首先将修补程序应用于主分支，并在必要时应用反向端口。

*   提交一个修补程序的单个修补程序。如有必要，首先将本地提交压缩为单个提交。有关压缩提交的更多信息，请参阅此[堆栈溢出问题](http://stackoverflow.com/questions/5308816/how-to-use-git-merge-squash)。

*   请理解并非每个补丁都可能会被提交，并且可能会在补丁上提供反馈。

*   如果您需要修改补丁，请将之前的补丁文件保留在 JIRA 上，然后上传一个补丁编号增加的补丁文件。单击**取消补丁**，然后单击**提交补丁**以触发预提交运行。

#### 174.7.2。单元测试

在进行更改时始终添加和/或更新相关的单元测试。在提交补丁之前确保新的/更改的单元测试在本地通过，因为它比等待运行完整测试套件的预提交结果更快。这将节省您自己的时间和精力。使用 [mockito](#mockito) 制作模拟，这些模拟对于通过注入适当的故障来测试故障情况非常有用。

如果要创建新的单元测试类，请注意其他单元测试类在类名称之前是否具有分类/大小调整注释以及用于设置/拆除测试环境的静态方法。请务必在任何新的单元测试文件中包含注释。有关测试的更多信息，请参见 [hbase.tests](#hbase.tests) 。

#### 174.7.3。集成测试

除了单元测试之外，重要的新功能还应提供集成测试，适用于在其配置空间的不同点执行新功能。

#### 174.7.4。 ReviewBoard

大于一个屏幕的补丁或者难以查看的补丁应该通过 [ReviewBoard](https://reviews.apache.org) 。

过程：使用 ReviewBoard

1.  如果您还没有帐户，请注册一个帐户。它不使用 [issues.apache.org](https://issues.apache.org) 的凭据。登录。

2.  单击“新建审阅请求”

3.  选择`hbase-git`存储库。单击“选择文件”以选择差异和可选的父差异。单击**创建审核请求**。

4.  根据需要填写字段。至少，填写摘要并选择`hbase`作为审核组。如果您填写 Bugs 字段，审核委员会会链接回相关的 JIRA。您填写的字段越多越好。点击**发布**即可公开您的评论请求。将向`hbase`组中的每个人发送一封电子邮件，以查看该补丁。

5.  返回 JIRA，单击并粘贴 ReviewBoard 请求的 URL。这将 ReviewBoard 附加到 JIRA，以便于访问。

6.  要取消请求，请单击。

有关如何使用 ReviewBoard 的更多信息，请参阅 [ReviewBoard 文档](http://www.reviewboard.org/docs/manual/1.5/)。

#### 174.7.5。 HBase 提交者指南

##### 成为提交者

提交者负责审查和整合代码更改，测试和投票候选版本，权衡设计讨论以及其他类型的项目贡献。 PMC 根据对项目贡献的评估，投票决定让贡献者成为提交者。预计提交者将展示对项目和社区参与的高质量贡献的持续历史。

贡献可以通过多种方式进行。成为提交者没有单一的途径，也没有任何预期的时间表。提交功能，改进和错误修复是最常见的途径，但其他方法都得到了认可和鼓励（对于 HBase 作为项目和社区的健康状况可能更为重要）。潜在贡献的非详尽清单（无特定顺序）：

*   [更新文档](#appendix_contributing_to_documentation)以了解新的更改，最佳做法，配方和其他改进。

*   使网站保持最新。

*   执行测试并报告结果。例如，总是赞赏尺度测试和测试非标准配置。

*   维护共享的 Jenkins 测试环境和其他测试基础架构。

*   [在执行验证后投票发布候选](#hbase.rc.voting)，即使不具有约束力。非约束性投票是非提交者的投票。

*   为[邮件列表](/mail-lists.html)（通常在主题行中有`[DISCUSS]`）的讨论主题提供输入。

*   回答用户或开发人员邮件列表和 Slack 上的问题。

*   确保 HBase 社区是一个热情的社区，并且我们遵守我们的[行为准则](/coc.html)。如果您有疑虑，请提醒 PMC。

*   查看其他人的工作（代码和非代码）并提供公众反馈。

*   报告找到的错误或提交新功能请求。

*   分类问题并保持 JIRA 的组织。这包括根据需要关闭陈旧问题，标记新问题，更新元数据和其他任务。

*   各种导师的新贡献者。

*   谈谈和写关于 HBase 的博客。将这些添加到网站的[新闻](/)部分。

*   提供有关 HBase，Web UI，CLI，API 和网站的 UX 反馈。

*   编写演示应用程序和脚本。

*   帮助吸引和留住多元化的社区。

*   以有利于 HBase 和其他项目的方式与其他项目互动。

并非每个人都能够完成此列表中的所有（甚至任何）项目。如果您想到其他贡献方式，请选择它（并将它们添加到列表中）。为了对 HBase 项目产生积极影响，您需要一个愉快的风度和贡献的意愿。邀请成为提交者是长期与社区稳定互动的结果，这建立了信任和认可。

##### 新的提交者

鼓励新的提交者首先阅读 Apache 的通用提交者文档：

*   [Apache 新提交者指南](https://www.apache.org/dev/new-committers-guide.html)

*   [Apache Committer FAQ](https://www.apache.org/dev/committers.html)

##### 评论

HBase 提交者应尽可能多地尝试审查其他人提交的补丁。理想情况下，每个提交的补丁都会在几天内由提交者 _ 审核 _。如果提交者审查他们没有创作的补丁，并认为它具有足够的质量，那么他们可以提交补丁。否则，应该取消补丁，并清楚解释它被拒绝的原因。

提交的补丁列表位于 [HBase Review Queue](https://issues.apache.org/jira/secure/IssueNavigator.jspa?mode=hide&requestId=12312392) 中，该队列按上次修改时间排序。提交者应该从上到下扫描列表，寻找他们认为有资格审查并可能提交的补丁。如果您看到一个补丁，您认为其他人更有资格审核，您可以在 JIRA 中通过用户名提及它们。

对于非平凡的更改，需要另一个提交者在提交之前检查您的修补程序。 **不允许自行提交非平凡补丁。** 使用 JIRA 中的 **Submit Patch** 按钮，就像其他贡献者一样，然后在提交之前等待来自另一个提交者的`+1`响应。

##### 拒绝

应拒绝不符合 [HowToContribute](https://hbase.apache.org/book.html#developer) 和[代码审查清单](https://wiki.apache.org/hadoop/CodeReviewChecklist)中的指南的补丁。提交者应始终对贡献者保持礼貌，并尝试指导并鼓励他们提供更好的补丁。如果提交者希望改进不可接受的补丁，那么首先应该拒绝补丁，并且应该由提交者附加新的补丁以供进一步审查。

##### 承诺

提交者向 Apache HBase GIT 存储库提交补丁。

> 在你提交之前！
> 
> 确保您的本地配置正确，尤其是您的身份和电子邮件。检查$ git config --list 命令的输出并确保它是正确的。如果需要指针，请参阅[设置 Git](https://help.github.com/articles/set-up-git) 。

提交补丁时：

1.  在提交消息中包含 Jira 问题 ID 以及更改的简短描述。尝试添加不仅仅是 Jira 标题的东西，以便有人看`git log`输出不必去 Jira 来辨别变化是什么。确保问题 ID 正确，因为这会导致 Jira 链接到 Git 中的更改（使用问题的“所有”选项卡查看这些自动链接）。

2.  将补丁提交到基于`master`或其他预期分支的新分支。在这个分支的名称中包含 JIRA ID 是个好主意。查看要提交的相关目标分支，并通过执行 git pull --rebase 或其他类似命令确保本地分支具有所有远程更改。接下来，樱桃选择每个相关分支（例如 master）的更改，并使用 git push &lt;remote-server&gt;&lt;remote-branch&gt;等命令将更改推送到远程分支。&lt;/remote-branch&gt;&lt;/remote-server&gt;

    &gt; 如果您没有进行所有远程更改，则推送将失败。如果推送因任何原因失败，请解决问题或寻求帮助。不要做 git push --force。

    在提交补丁之前，您需要确定补丁的创建方式。围绕创建补丁的方式的说明和偏好已经改变，并且将存在过渡期。

    确定修补程序的创建方式

    *   如果补丁的前几行看起来像电子邮件的标题，带有 From，Date 和 Subject，则使用 git format-patch 创建。这是首选方法，因为您可以重用提交者的提交消息。如果提交消息不合适，您仍然可以使用提交，然后根据需要运行`git commit --amend`和 reword。

    *   如果补丁的第一行看起来类似于以下内容，则使用 git diff 创建而不使用`--no-prefix`。这也是可以接受的。注意文件名前面的`a`和`b`。这表明补丁不是用`--no-prefix`创建的。

        ```
        diff --git a/src/main/asciidoc/_chapters/developer.adoc b/src/main/asciidoc/_chapters/developer.adoc 
        ```

    *   如果补丁的第一行看起来类似于以下（没有`a`和`b`），则补丁是使用 git diff --no-prefix 创建的，您需要将`-p0`添加到下面的 git apply 命令中。

        ```
        diff --git src/main/asciidoc/_chapters/developer.adoc src/main/asciidoc/_chapters/developer.adoc 
        ```

    示例 43.提交补丁的示例

    你会注意到这些例子的一件事是有很多 git pull 命令。实际将任何东西写入远程存储库的唯一命令是 git push，你需要确保你拥有正确的所有版本，并且在推送之前没有任何冲突。额外的 git pull 命令通常是多余的，但比抱歉更安全。

    第一个示例显示如何应用使用 git format-patch 生成的补丁并将其应用于`master`和`branch-1`分支。

    使用 git format-patch 而不是 git diff 而不使用`--no-prefix`的指令是一个新指令。请参阅第二个示例，了解如何应用使用 git diff 创建的补丁，并教育创建补丁的人员。

    ```
    $ git checkout -b HBASE-XXXX
    $ git am ~/Downloads/HBASE-XXXX-v2.patch --signoff  # If you are committing someone else's patch.
    $ git checkout master
    $ git pull --rebase
    $ git cherry-pick &lt;sha-from-commit&gt;
    # Resolve conflicts if necessary or ask the submitter to do it
    $ git pull --rebase          # Better safe than sorry
    $ git push origin master

    # Backport to branch-1
    $ git checkout branch-1
    $ git pull --rebase
    $ git cherry-pick &lt;sha-from-commit&gt;
    # Resolve conflicts if necessary
    $ git pull --rebase          # Better safe than sorry
    $ git push origin branch-1
    $ git branch -D HBASE-XXXX 
    ```

    此示例显示如何提交使用 git diff 而不使用`--no-prefix`创建的修补程序。如果使用`--no-prefix`创建补丁，请将`-p0`添加到 git apply 命令。

    ```
    $ git apply ~/Downloads/HBASE-XXXX-v2.patch
    $ git commit -m "HBASE-XXXX Really Good Code Fix (Joe Schmo)" --author=&lt;contributor&gt; -a  # This and next command is needed for patches created with 'git diff'
    $ git commit --amend --signoff
    $ git checkout master
    $ git pull --rebase
    $ git cherry-pick &lt;sha-from-commit&gt;
    # Resolve conflicts if necessary or ask the submitter to do it
    $ git pull --rebase          # Better safe than sorry
    $ git push origin master

    # Backport to branch-1
    $ git checkout branch-1
    $ git pull --rebase
    $ git cherry-pick &lt;sha-from-commit&gt;
    # Resolve conflicts if necessary or ask the submitter to do it
    $ git pull --rebase           # Better safe than sorry
    $ git push origin branch-1
    $ git branch -D HBASE-XXXX 
    ```

3.  将问题解决为固定的，感谢贡献者。此时始终设置“修复版本”，但仅为已提交更改的每个分支设置单个修订版本，即将在其中显示更改的分支中的最早版本。

###### 提交消息格式

提交消息应包含 JIRA ID 以及修补程序的功能描述。首选的提交消息格式为：

```
<jira-id> <jira-title> (<contributor-name-if-not-commit-author>) 
```

```
HBASE-12345 Fix All The Things (jane@example.com) 
```

如果贡献者使用 git format-patch 生成补丁，则他们的提交消息在他们的补丁中，您可以使用它，但请确保 JIRA ID 位于提交消息的前面，即使贡献者将其遗漏。

###### 在冲突樱桃回击后添加修改 - 作者

我们已经建立了承诺掌握的做法，然后尽可能地回到分支机构，除非

*   它正在打破 compat：在这种情况下，如果它可以进入次要版本，则向后移植到 branch-1 和 branch-2。

*   这是一个新功能：对于维护版本不适用，对于次要版本，讨论并达成共识。

当存在轻微冲突时，我们可以修复它并继续提交。生成的提交保留原始作者。当修改作者与原始提交者不同时，在提交消息的末尾添加以下内容：`Amending-Author: Author &lt;committer&apache&gt;`参见[HBase，mail＃dev - [讨论](http://search-hadoop.com/m/DHED4wHGYS)的讨论修改提交时的最佳实践从主人到分店挑选]。

###### 关闭相关的 GitHub PR

作为一个项目，我们努力确保每个变更都有一个 JIRA，但我们并未要求任何特定工具用于评审。由于 ASF 在托管的 git 存储库和 GitHub 之间的集成的实现细节，PMC 无法直接关闭我们的 GitHub 存储库上的 PR。如果贡献者在 GitHub 上发出了拉取请求，或者因为贡献者发现比将补丁附加到 JIRA 更容易，或者因为审阅者更喜欢用于检查更改的 UI，那么在提交中记下 PR 是很重要的。到主分支，以便 PR 保持最新。

要阅读有关 GitHub“close via keyword in commit”机制的提示消息的详细信息，请参阅 [GitHub 文档“使用关键字关闭问题”](https://help.github.com/articles/closing-issues-using-keywords/)。总之，您应该包含一个包含短语“closing #XXX”的行，其中 XXX 是拉取请求 ID。拉取请求 ID 通常在主题标题末尾的灰色 GitHub UI 中给出。

###### 提交者负责确保提交不会破坏构建或测试

如果提交者提交补丁，他们有责任确保它通过测试套件。如果贡献者注意他们的补丁不会破坏 hbase 构建和/或测​​试，那么这是有帮助的，但最终，不能指望贡献者知道像 HBase 这样的项目中发生的所有特定变幻莫测和互连。提交者应该。

###### 修补礼仪

在线程 [HBase，邮件#dev - 通知：Git Migration In Progress（WAS⇒Re：Git Migration）](http://search-hadoop.com/m/DHED4EiwOz)中，对以下补丁流程达成了一致意见

1.  首先开发并提交针对 master 的补丁。

2.  如果可能的话，尝试在向后移动时挑选补丁。

3.  如果这不起作用，请手动将修补程序提交到分支。

###### 合并提交

避免合并提交，因为它们会在 git 历史记录中产生问题。

###### 提交文档

参见文献的[附录。](#appendix_contributing_to_documentation)

#### 174.7.6。对话

提交者应该在 irc.freenode.net 的#hbase 会议室中进行实时讨论。但是，任何实质性讨论（与任何列表项目相关的讨论一样）都应该在 Jira 或开发人员列表中重新进行。

#### 174.7.7。不要编辑 JIRA 评论

拼写错误和/或错误的语法比 JIRA 评论编辑导致的中断更可取：参见[上的讨论 Re：（HBASE-451）从 HRegionInfo](http://search-hadoop.com/?q=%5BReopened%5D+%28HBASE-451%29+Remove+HTableDescriptor+from+HRegionInfo&fc_project=HBase) 中删除 HTableDescriptor

### 174.8。 hbase-thirdparty 依赖和着色/重定位

为 hbase-2.0.0 的发布创建了一个新项目。它被称为`hbase-thirdparty`。该项目仅用于为主 hbase 项目提供流行的第三方库（如番石榴，netty 和 protobuf）的重定位或阴影版本。主线 HBase 项目依赖于从 hbase-thirdparty 获取的这些库的重定位版本，而不是在通常位置查找这些类。我们这样做，所以我们可以指定我们希望的任何版本。如果我们不重新定位，我们必须协调我们的版本以匹配 hadoop，spark 和其他项目使用的版本。

对于开发人员来说，这意味着你需要小心引用 netty，guava，protobuf，gson 等类。（参见 hbase-thirdparty pom.xml 提供的内容）。开发人员必须参考 hbase-thirdparty 提供的类。在实践中，这通常不是问题（虽然它可能有点痛苦）。您将不得不寻找特定类的重定位版本。您可以通过添加`org.apache.hbase.thirdparty.`的常规重定位前缀来找到它。例如，如果您正在寻找`com.google.protobuf.Message`，HBase 内部使用的重新定位版本可以在`org.apache.hbase.thirdparty.com.google.protobuf.Message`中找到。

对于一些第三方库，比如 protobuf（参见本书中的 protobuf 章节了解原因），你的 IDE 可能会给你两个选项 - `com.google.protobuf.` **和`org.apache.hbase.thirdparty.com.google.protobuf.`** - 因为这两个类都在你的 CLASSPATH。除非您正在进行协处理器端点开发所需的特定杂耍（再次参见上面引用的 protobuf 章节），否则您将始终使用着色版本。

`hbase-thirdparty`项目的 groupid 为`org.apache.hbase.thirdparty`。在撰写本文时，它提供了三个罐子;一个用于`hbase-thirdparty-netty`的人工制造，一个用于`hbase-thirdparty-protobuf`的 protobuf，然后是一个罐子用于其他所有 - gson，番石榴 - 在`hbase-thirdpaty-miscellaneous`。

hbase-thirdparty 工件是由 HBase 项目管理委员会支持下的 Apache HBase 项目生成的产品。发布是通过 hbase dev 邮件列表上的常规投票项目完成的。如果在 hbase-thirdparty 中出现问题，请使用 hbase JIRA 和邮件列表发布通知。

### 174.9。 HBase 相关 Maven 原型的开发

HBase 相关 Maven 原型的开发始于 [HBASE-14876](https://issues.apache.org/jira/browse/HBASE-14876) 。有关 hbase-archetypes 基础结构的概述以及开发新的 HBase 相关 Maven 原型的说明，请参阅`hbase/hbase-archetypes/README.md`。