vlambda博客
学习文章列表

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8


  • 1. 前言

  • 2. G1

  • 3. ZGC

  • 4. 用 AdoptOpenJDK15 重编译 hbase-1.4.8

    • 4.1 JDK15 在滴滴 HBase 上的应用

    • 4.2 准备工作

    • 4.3 项目配置

    • 4.4 处理 sun.misc.Unsafe not found 异常

    • 4.5 替换 javax.xml.ws.http.HTTPException

    • 4.6 程序包 javax.annotation 不存在

    • 4.7 程序包 com.sun.javadoc 不存在

    • 4.8 升级 jetty

    • 4.9 提升一些 maven 插件的版本

    • 4.10 Jruby 组件版本升级

    • 4.11 编译时 jdk 忘记切换至 jdk15

    • 4.12 license 受检异常

  • 5. 为 HBase 源码打补丁

  • 6. IDEA 中 DEBUG 调试源码

  • 7. 最终打 tar.gz 包

  • 8. 总结


1. 前言

我们线上 HBase 集群的 GC 方式早已切换至 G1,而且对 G1 的各个参数也做了详细的压测,并对比实验结果,搭配出了一组较为优秀的参数配置,再结合我们接口级别的主备熔断机制,在过去很长的一段时间里,我们集群的超时率一直控制在很低的范围之内,优于业务方的预期。

但随着业务方对 HBase 集群查询延时的要求越来越高,线上集群单纯 getRow 的查询响应已无法到达其满意的三个 9。一系列的测试之后我们得出结论,GC 毛刺导致查询超时毛刺,这里不过多描述测试的细节,后续会继续发文介绍 GC 与 HBase 的爱恨纠葛。

在我们可以完全排除网络抖动、硬盘延迟等方面的因素影响之后,GC 的瓶颈就是拖慢 HBase 性能的最大掣肘。关于 GC 更深层次的理论知识,奈何我也在找书看,目前只能寥寥数字,记录一些粗浅的理解。

我们配置 HBase 的时候,会重点对 RegionServer 的 JVM 参数进行调优,会给它分配一个合适的内存大小,会为它设置一些 GC 参数,会调整读缓存和写缓存占用整个 RS 内存的比例,以上种种操作都是为了最大程度地把发挥出集群的性能。

一条 HBase 的查询请求从客户端达到服务端之后,会首先经过读缓存,缓存查不到数据才会去到磁盘中寻址。读缓存的机制是把最有可能被访问到的数据加载到内存里,而把一些不太可能被读到的数据所占的内存空间释放掉,这些无用对象的回收就需要 GC 的参与,合理的 GC 方式和合适的 GC 参数,会帮助我们更快、更及时地回收掉无用的对象,释放内存空间,进而保证整个服务高效而又稳定地运行。

以下内容将记录 G1 与 ZGC 的简单对比,将着重记录我用AdoptOpenJDK15重编译社区版hbase-1.4.8,并在 IDEA 中 DEBUG 调试和编译成最终安装包的过程,且在后续计划中,会对比 G1,测试 ZGC 在 HBase 中表现究竟有多优秀。

2. G1

G1(Garbage First)垃圾收集器是当今垃圾回收技术最前沿的成果之一。早在 JDK7 就已加入 JVM 的收集器大家庭中,成为 HotSpot 重点发展的垃圾回收技术。同优秀的 CMS 垃圾回收器一样,G1 也是关注最小时延的垃圾回收器,也同样适合大尺寸堆内存的垃圾收集,官方也推荐使用 G1 来代替选择 CMS。G1 最大的特点是引入分区的思路,弱化了分代的概念,合理利用垃圾收集各个周期的资源,解决了其他收集器甚至 CMS 的众多缺陷。

初识 JVM,初始 GC,让我感触最深的一个词是,STW,stop the world,意指,当 GC 发生的时候,整个世界都将停止,那是否也意味着你整个系统中的所有 application 都将在此刻停顿,为 GC 让步?因此,从 JDK3(1.3)开始,HotSpot 团队一直努力朝着高效收集、减少停顿(STW: Stop The World)的方向努力,也贡献了从串行到 CMS 乃至最新的 G1 在内的一系列优秀的垃圾收集器,而 ZGC 则是比 G1 更优秀的 GC 算法。

3. ZGC

直接查看 ZGC 的目标吧。

zgc
  • 低延迟,保证最大停顿时间在几毫秒之内,不管你堆多大或者存活的对象有多少
  • 可以处理 8MB-16TB 的堆

暂时触及到了知识盲区,就不误人子弟了,还是直接上链接吧!https://www.zhihu.com/question/287945354/answer/458761494

4. 用 AdoptOpenJDK15 重编译 hbase-1.4.8

4.1 JDK15 在滴滴 HBase 上的应用

重编译 hbase-1.4.8 的想法来源于滴滴一篇关于 HBase 性能优化的文章。

文章中介绍了 ZGC 的性能测评,以及他们团队内部的 HBase 对于 ZGC 的需求与实践,以及一些 HBase 方面的其他性能优化手段。

摘取 jdk15 编译 HBase 的简单流程,以此作为参考,也开始我们的编译之路。

这里我也选择 hbase-1.4.8 的源码进行修改和编译,当然,理论上更高版本的 hbase 代码与 JDK15 的兼容性应该更好,编译起来也更轻松,既然滴滴选择了 1.4.8,那就说明 1.4.8 的编译是可操作的。

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
didi-hbase

4.2 准备工作

  • 社区版 hbase-1.4.8源码包一份,请移步至官网下载
  • AdoptOpenJDK15 请自行搜索该 JDK 的下载页面,下载对应操作系统的安装包
  • maven-3.5.0 别的版本没有试过,不知道是否有坑
  • IDEA-2020.3 付费版更好,社区版也够用,下载最新版的 IDEA,主要为了可以在上面选 jdk15
  • Mac OS,其他操作系统没有尝试,估计坑会更多

附件

maven 配置文件所需配置,加速依赖下载

 <mirrors>
     <mirror>
        <id>aliyun</id>
        <mirrorOf>*,!cloudera</mirrorOf>
        <name>Nexus Release Repository</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public</url>
    </mirror>
     <mirror>
            <id>central</id>
            <name>Maven Repository Switchboard</name>
            <url>https://repo1.maven.org/maven2/</url>
            <mirrorOf>central</mirrorOf>
        </mirror>
        <!-- 中央仓库在中国的镜像 -->
        <mirror>
            <id>maven.net.cn</id>
            <name>oneof the central mirrors in china</name>
            <url>http://maven.net.cn/content/groups/public/</url>
            <mirrorOf>central</mirrorOf>
        </mirror>
  </mirrors>

4.3 项目配置

用 IDEA 打开 hbase 源码的根路径,导入成 maven 项目。

配置你的 JDK15

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
JDK-15

配置为每一个 hbase 项目的模块让其加载 jdk15

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
jdk15-load
HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
jdk15-compiler

当然,上述操作你都可以手动进行操作,但是,一旦你更新项目的 pom 文件,上述手动进行设置的配置,都会恢复原样。所以,为了避免每次都需要手动配置一次,我们来修改下 pom 文件中mavenn-compiler-plugin下的配置。

<!--<maven.compiler.version>3.6.1</maven.compiler.version>-->
<!--提高下该插件的版本-->
<maven.compiler.version>3.8.1</maven.compiler.version>
<!--<compileSource>1.7</compileSource>-->
<!--compileSource修改为15,原来的1.7是指编译该版本JDK的最小版本是jdk1.7-->
<compileSource>15</compileSource>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>${maven.compiler.version}</version>
          <configuration>
            <source>${compileSource}</source>
            <target>${compileSource}</target>
            <showWarnings>true</showWarnings>
            <showDeprecation>false</showDeprecation>
            <compilerArgs>
              <arg>--add-exports=java.base/jdk.internal.access=ALL-UNNAMED</arg>
              <arg>--add-exports=java.base/jdk.internal=ALL-UNNAMED</arg>
              <arg>--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED</arg>
              <arg>--add-exports=java.base/sun.security.pkcs=ALL-UNNAMED</arg>
              <arg>--add-exports=java.base/sun.nio.ch=ALL-UNNAMED</arg>
            </compilerArgs>
          </configuration>
</plugin>
<!--compilerArgs 下文细说-->

上述修改之后,重新加载下 pom 文件,上图中 idea 中 java 编译各个模块的 jdk 版本,会自动变为 15,且 compilerArgs 标签中增加的编译时参数,也会自动传给 idea。见下图

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
compilerArgs

4.4 处理 sun.misc.Unsafe not found 异常

上述项目配置完成之后,尝试运行如下打包命令,或点下 IDEA 中工具栏中绿色的锤子,编译下项目。

# 在项目的根目录下执行
cd /Users/mac/other_project/apache/hbase/hbase-1.4.8
mvn clean package -DskipTests

不出意外的话,你一定会遇到这个异常。

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
error
org.apache.hadoop.hbase.util.Bytes
org.apache.hadoop.hbase.util.UnsafeAccess

Bytes 和 UnsafeAccess 两个类中的sun.misc.Unsafe替换为jdk.internal.misc.Unsafe

重新执行编译后,继续报错

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
error-2

这个错误就需要用到 maven-compiler-plugin 中的 compilerArgs 配置参数了,参考链接:JDK12 JDK.INTERNAL 包 不可见

https://www.freesion.com/article/992163055/

4.5 替换 javax.xml.ws.http.HTTPException

找不到 javax.xml.ws.http.HTTPException,需要找到替代类

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
HTTPException

项目根 pom 文件中加入如下依赖,注意加在 dependencies 标签下面

<dependencies>
   <dependency>
      <groupId>jakarta.xml.ws</groupId>
      <artifactId>jakarta.xml.ws-api</artifactId>
      <version>2.3.3</version>
    </dependency>
</dependencies>

4.6 程序包 javax.annotation 不存在

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
javax.annotation

项目根 pom 文件中加入如下依赖,注意加在 dependencies 标签下面

<dependencies>
   <dependency>
       <groupId>javax.annotation</groupId>
       <artifactId>javax.annotation-api</artifactId>
       <version>1.3.1</version>
    </dependency>
</dependencies>

4.7 程序包 com.sun.javadoc 不存在

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
com.sun.javadoc

systemPath 请指向你的 JAVA_HOME,jdk1.8 也行

<dependencies>
   <dependency>
      <groupId>jdk.tools</groupId>
      <artifactId>jdk.tools</artifactId>
      <version>1.7</version>
      <scope>system</scope>
      <systemPath>/Library/Java/JavaVirtualMachines/jdk1.7.0_60.jdk/Contents/Home/lib/tools.jar</systemPath>
    </dependency>
</dependencies>

4.8 升级 jetty

hbase-serverhbase-thrifthbase-rest三个模块依赖 jetty 来编译 JSP 等 web 组件,项目中原有 jetty 为 org.mortbay.jetty,而并非现在主流的 org.eclipse.jetty,所以需要把原来 jetty 的版本升级为 eclipse 的。jetty 不升级直接报如下异常,实在无法在原有 jetty 版本上解决这个错误。

错误日志大概是:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-antrun-plugin:1.6:run (generate) on project hbase-server: An Ant BuildException has occured: java.util.MissingResourceException: Can't find com.sun.common.util.logging.LogStrings bundle from  -> [Help 1]

而滴滴原文中只是简单介绍了需要升级 jetty,并未交代具体实现细节。没办法,只能灵机一动,直接参考hbase-2.2.3中的 jetty 依赖。社区 3.x 及 2.3.x 版本开始支持 JDK11,那么这俩大版本中的代码实现应该是最接近 jdk15 的。所以直接参考 hbase-2.2.3 中,这三个模块中 jetty 的依赖。

在根 pom 中增加高版本 jetty 组件,所做的改动如下:

<!--    <jetty.version>6.1.26</jetty.version>
    <jetty.jspapi.version>6.1.14</jetty.jspapi.version>-->

<jetty.version>9.3.28.v20191105</jetty.version>

 <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-server</artifactId>
        <version>${jetty.version}</version>
      </dependency>
      <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-servlet</artifactId>
        <version>${jetty.version}</version>
        <exclusions>
          <exclusion>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>servlet-api</artifactId>
          </exclusion>
        </exclusions>
      </dependency>
      <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-security</artifactId>
        <version>${jetty.version}</version>
      </dependency>
      <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-http</artifactId>
        <version>${jetty.version}</version>
      </dependency>
      <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-util</artifactId>
        <version>${jetty.version}</version>
      </dependency>
      <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-io</artifactId>
        <version>${jetty.version}</version>
      </dependency>
      <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-jmx</artifactId>
        <version>${jetty.version}</version>
      </dependency>
      <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-webapp</artifactId>
        <version>${jetty.version}</version>
      </dependency>
       <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-util-ajax</artifactId>
        <version>${jetty.version}</version>
      </dependency>

       <dependency>
        <!--This lib has JspC in it. Needed precompiling jsps in hbase-rest, etc.-->
         <!-- 这个很重要,用来编译jsp的-->
        <groupId>org.glassfish.web</groupId>
        <artifactId>javax.servlet.jsp</artifactId>
        <version>2.3.2</version>
      </dependency>
      <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
      </dependency>

   </dependencies>
</dependencyManagement>

在 hbase-server 模块中,对 pom 所做改动如下:

  <!--加入新jetty依赖-->
    <dependency>
      <!--For JspC used in ant task-->
      <groupId>org.glassfish.web</groupId>
      <artifactId>javax.servlet.jsp</artifactId>
    </dependency>
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-server</artifactId>
    </dependency>
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-servlet</artifactId>
    </dependency>
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-http</artifactId>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
    </dependency>
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-util</artifactId>
    </dependency>

<!--注释旧依赖-->
<!-- <dependency>
      <groupId>org.mortbay.jetty</groupId>
      <artifactId>jetty</artifactId>
    </dependency>
    <dependency>
      <groupId>org.mortbay.jetty</groupId>
      <artifactId>jetty-util</artifactId>
    </dependency>
    <dependency>
      <groupId>org.mortbay.jetty</groupId>
      <artifactId>jetty-sslengine</artifactId>
    </dependency>-->

    <!--<dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-jsp-2.1</artifactId>
      <scope>compile</scope>
    </dependency>-->

   <!-- <dependency>
      <groupId>org.mortbay.jetty</groupId>
      <artifactId>jsp-2.1</artifactId>
    </dependency>
    <dependency>
      <groupId>org.mortbay.jetty</groupId>
      <artifactId>jsp-api-2.1</artifactId>
    </dependency>
    <dependency>
      <groupId>org.mortbay.jetty</groupId>
      <artifactId>servlet-api-2.5</artifactId>
    </dependency>-->

剩余其他模块操作类似。

备注,maven-antrun-plugin 这个模块就是用来编译 JSP、自动生成 java jsp 代码等 WEB 资源的,是个大坑,但是捋顺了就踩过去了。

 <plugin>
        <artifactId>maven-antrun-plugin</artifactId>
        <executions>
          <!-- Generate web app sources -->
          <execution>
            <id>generate</id>
            <phase>generate-sources</phase>
            <configuration>
              <target>
                <property name="build.webapps" location="${project.build.directory}/hbase-webapps"/>
                <property name="src.webapps" location="${basedir}/src/main/resources/hbase-webapps"/>
                <property name="generated.sources" location="${project.build.directory}/generated-sources"/>
                <mkdir dir="${build.webapps}"/>
                <copy todir="${build.webapps}">
                  <fileset dir="${src.webapps}">
                    <exclude name="**/*.jsp"/>
                    <exclude name="**/.*"/>
                    <exclude name="**/*~"/>
                  </fileset>
                </copy>
                <!--The compile.classpath is passed in by maven -->
                <taskdef classname="org.apache.jasper.JspC" name="jspcompiler" classpathref="maven.compile.classpath"/>
                <mkdir dir="${build.webapps}/master/WEB-INF"/>
                <jspcompiler uriroot="${src.webapps}/master" outputdir="${generated.sources}/java" package="org.apache.hadoop.hbase.generated.master" webxml="${build.webapps}/master/WEB-INF/web.xml"/>
                <mkdir dir="${build.webapps}/regionserver/WEB-INF"/>
                <jspcompiler uriroot="${src.webapps}/regionserver" outputdir="${generated.sources}/java" package="org.apache.hadoop.hbase.generated.regionserver" webxml="${build.webapps}/regionserver/WEB-INF/web.xml"/>
              </target>
            </configuration>
            <goals>
              <goal>run</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

上述依赖修改完成之后,重新编译,个别类会出现报错,需要修改两处源码,但是代码修改也很简单,这里就不赘述了。最终,编译顺利通过,web 代码以及静态资源可以正常生成。

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
compiler-web

4.9 提升一些 maven 插件的版本

maven-shade-plugin、extra-enforcer-rules 升级至新版,以应对一些莫名其妙的错误。

4.10 Jruby 组件版本升级

Jruby 编译组件的版本升级至高版本,影响的模块也只有hbase-shell,升级之后需要修改些 rb 代码,也很简单,思路还是直接抄hbase-2.2.3源码。

<!--    <jruby.version>1.6.8</jruby.version>-->
    <jruby.version>9.1.17.0</jruby.version>

4.11 编译时 jdk 忘记切换至 jdk15

忘记切换 jdk15 就运行 mvn 编译命令的报错如下:

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
error
# -X编译参数打印DEBUG日志
mvn clean package -DskipTests -X
HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
error-detail

切换 jdk15。

4.12 license 受检异常

编译过程中会报 license 检查异常,需要配置编译时跳过 license 检查。

<execution>
            <id>check-aggregate-license</id>
            <!-- must check after LICENSE is built at 'generate-resources' -->
            <phase>process-resources</phase>
            <goals>
              <goal>enforce</goal>
            </goals>
            <configuration>
              <rules>
                <evaluateBeanshell>
                  <condition>
                    File license = new File("${license.aggregate.path}");

                    // Beanshell does not support try-with-resources,
                    // so we must close this scanner manually
                    Scanner scanner = new Scanner(license);

                    while (scanner.hasNextLine()) {
                      if (scanner.nextLine().startsWith("ERROR:")) {
                        scanner.close();
                        return false;
                      }
                    }
                    scanner.close();
                    return true;
                  </condition>
                  <message>
                    License errors detected, for more detail find ERROR in
                    ${license.aggregate.path}
                  </message>
                </evaluateBeanshell>
              </rules>
<!--           直接设置skip为true    <skip>${skip.license.check}</skip>-->
              <skip>true</skip>

            </configuration>
          </execution>

至此,源码正式编译打包前的修改工作已经完成。

5. 为 HBase 源码打补丁

这里也顺势记录下为 HBase 源码打补丁吧,我们在使用 HBase 的过程中,可能会发现一些 BUG,并修改源码,经过社区大佬审核和确认之后,就可以生成一个 patch 文件了,patch 文件其实就是 git 的一些文件增删记录,打完 patch 之后,对源码的修改会自动体验在原来的代码上,主要是为了避免你自己手动复制粘贴后再出 BUG。

这里也为 hbase-1.4.8 打一个滴滴大佬提供的 patch,该 patch 具体修复的功能是,HBASE-22620 修复 replication znode 积压问题;

当然你也可以选择你感兴趣的 patch。

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
patch

参考链接

搜索 HBASE-22620

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
HBASE-22620

下载对应的 patch 文件,放置 hbase 源码根目录,大致看一下 patch 文件的描述内容:

---
 .../regionserver/ReplicationSource.java            |  49 ++++++-
 .../ReplicationSourceWALReaderThread.java          |   5 +
 .../hbase/replication/TestReplicationSource.java   | 143 +++++++++++++++++++--
 3 files changed, 180 insertions(+), 17 deletions(-)

主要对上述三个文件进行了修改。我们只关注 ReplicationSource.java

# 进入项目的根路径下
# 检查patch/diff是否能正常打入
# 这一步相当重要,因为你下载的patch可能并不兼容你当前所使用的版本,如果不检查就打patch,可能会污染你的源代码
# 进入项目根目录,运行
git apply --check  HBASE-22620.branch-1.4.001.patch
# 无输出表示可以继续向下执行,有输出,请看具体的输出信息
# 打入patch
git apply HBASE-22620.branch-1.4.001.patch

patch 打入后,ReplicationSource.java 行数增加了。你还可以查看具体修改了什么样的逻辑,patch 打完后,重新编译源码。

6. IDEA 中 DEBUG 调试源码

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
conf

把 conf 目录移动到这两个模块文件夹中,并设置为源码包,如图显示蓝色。

新增 Application HMaster

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
HMaster
  • 新增一个 Application
  • 设置名称,如:HMaster
  • 设置 Java 版本
  • 设置运行模块,hbase-server
  • 设置启动的 JVM 参数
  • 设置运行主类
  • 设置 main 函数启动参数
  • 设置 working directory 你自己的项目路径

这里具体说明运行时的 JVM 参数:

-Dhbase.home.dir=/Users/mac/other_project/apache/hbase/hbase-1.4.8
-Dhbase.id.str=root
-Dlog4j.configuration=file:///Users/mac/other_project/apache/hbase/hbase-1.4.8/conf/log4j.properties
-Dhbase.log.dir=/Users/mac/other_project/apache/hbase/hbase-1.4.8/logs
-Dhbase.log.file=hbase-root-master.log
-Dhbase.root.logger=INFO,console,DRFA
--add-exports=java.base/jdk.internal.access=ALL-UNNAMED
--add-exports=java.base/jdk.internal=ALL-UNNAMED
--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED
--add-exports=java.base/sun.security.pkcs=ALL-UNNAMED
--add-exports=java.base/sun.nio.ch=ALL-UNNAMED
--add-opens java.base/jdk.internal.misc=ALL-UNNAMED

新增 Application hbase shell

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
hbase-shell

重点关注 JVM 参数,否则 hbase shell 无法运行。

-Dhbase.ruby.sources=/Users/mac/other_project/apache/hbase/hbase-1.4.8/hbase-shell/src/main/ruby
--add-exports=java.base/jdk.internal.access=ALL-UNNAMED
--add-exports=java.base/jdk.internal=ALL-UNNAMED
--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED
--add-exports=java.base/sun.security.pkcs=ALL-UNNAMED
--add-exports=java.base/sun.nio.ch=ALL-UNNAMED
--add-opens
java.base/jdk.internal.misc=ALL-UNNAMED

main 函数传参:

-X+O /Users/mac/other_project/apache/hbase/hbase-1.4.8/bin/hirb.rb

分别启动两个 Application

在 hbase-server/conf/hbase-site.xml 配置文件中新增如下配置:

<configuration>
    <property>
        # 此配置是为了跳过版本检查
        <name>hbase.defaults.for.version.skip</name>
        <value>true</value>
    </property>
    <property>
        <name>hbase.rootdir</name>
        <value>file:///Users/mac/other_project/apache/hbase/hbase-1.4.8/hbase-data/hbase</value>
        <description>hbase本地数据地址</description>
    </property>
    <property>
        <name>hbase.zookeeper.property.dataDir</name>
        <value>/Users/mac/other_project/apache/hbase/hbase-1.4.8/hbase-data/zookeeper-data</value>
        <description>hbase 内置zk数据目录地址</description>
    </property>
</configuration>

启动 HMaster Application

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
success

HMaster 正常启动无报错

启动 hbase shell

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
hbase-shell-success

Hbase shell 正常启动无报错,且命令试用成功

运行测试用例

public class TestQuery {
    @Test
    public void testHBase() {
        Configuration conf = HBaseConfiguration.create();
        try {
            Connection connection = ConnectionFactory.createConnection(conf);
            Admin admin = connection.getAdmin();
            HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf("leo_test"));
            HColumnDescriptor columnDescriptor = new HColumnDescriptor(Bytes.toBytes("info"));
            tableDescriptor.addFamily(columnDescriptor);
            //admin.createTable(tableDescriptor);
            final List<String> tables = Arrays.stream(admin.listTableNames()).map(TableName::getNameAsString).collect(Collectors.toList());
            System.out.println(tables);
            Table table = connection.getTable(TableName.valueOf("leo_test"));
            Put put = new Put(Bytes.toBytes("10001"));
            put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name"), Bytes.toBytes("leo"));
            table.put(put);

            Get get = new Get(Bytes.toBytes("10001"));
            Result result = table.get(get);
            byte[] value = result.getValue(Bytes.toBytes("info"), Bytes.toBytes("name"));
            System.out.println(Bytes.toString(value).toString());
            System.out.println(result);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行时注意 Application 的配置

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
test

注意 JVM 参数

7. 最终打 tar.gz 包

mvn clean package -DskipTests -Dhadoop-two.version=2.7.4 assembly:single

当你看到绿油油的一片时,就证明你成功了。

HBase 源码 | ZGC 初体验-OpenJDK 15编译 HBase 1.4.8
success-package

tar.gz 包就在这里

tar.gz

还是那个熟悉的目录:

dir

8. 总结

至此,JDK15 编译hbase-1.4.8源码的整个流程,便记录完毕,其在 idea 中进行 DEBUG 调试的关键步骤也一并记录在内,方便之后的代码阅读、功能调试、甚至是源码修改。整个过程中可能还有些细枝末节没有阐述到位,但应该很简单就能解决掉。

HBase 源码复杂而宏大, 学习之路漫长而遥远,了解 JVM 的底层,熟悉 GC 的优化,必定是无法绕过的门槛。后续会在测试集群中部署该版本的安装包,对比 G1,解开 ZGC 的神秘面纱,探测 HBase 更巅峰的性能瓶颈。

- END -