为什么选择 Spring data hadoop

阅读本文之前,请投票支持这款 全新设计的脚手架 ,让 Java 再次伟大!

Native Api

原生 api 操作繁琐,就像用 JDBC 操作关系型数据库一样,类似 flush、submit、close 的使用让人眼花缭乱。如果碰巧你的应用程序使用 java 开发,那就又多了一条不使用 Native Api 的理由 ------ 在问题周围兜一个圈子再解决才是真正的 java 式设计。

Phoenix

apache 提供的 phoenix 提供了 mybatis-like 的支持,帮你「隐藏」了行键的麻烦,还支持在 mapper 文件中像操作关系型数据库一样,直接创建某个字段的索引,以优化大量数据操作时可能产生的性能问题。

这实在是太「夸张」了。在我有限的认知中不记得 Hbase 原生支持这样的功能。尽管我的目的只是「简单的操作 Hbase」,却还是怀着对 phenix 项目的崇敬,下载了相关依赖导入项目中。

可是结果让我失望。hbase-client.jar、hbase-server.jar、phoenix-core .jar 这三者在导入项目后产生了大量的依赖冲突。在我尝试了各种冲突排查手段都无解正焦头烂额时,先哲的一句话将我从泥潭拉了出来:

当你在一件事情上遇到困难时,就放弃这件事。 ------ 鲁迅

Spring data hadoop

我的目的毕竟只是「简单的操作 Hbase」。而 spring data 使用 Hbase 所需配置不过一行,还没有讨厌的 checked exception,更不会提供某些「夸张」的功能,最重要的是没有依赖冲突!这些特点深深的打动了我。

如何配置 Spring data hadoop

配置 spring data hadoop 分 3 步。

第一步:导入依赖包。

exclusion 选项最好根据你自己的情况来配置,重点注意 hbase-client 相关的版本一定要使用 1.2.0 以上,不然可能会和项目中既存的 guava 包产生冲突。

xml 复制代码
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-hadoop</artifactId>
    <version>2.5.0.RELEASE</version>
    <exclusions>
        <exclusion>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.apache.hbase</groupId>
    <artifactId>hbase-client</artifactId>
    <version>1.3.0</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
        <exclusion>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-x-discovery</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </exclusion>
    </exclusions>
</dependency>

第二步:编写相关配置。

spring 官方文档 Working with HBase 只提供了 xml 配置示例,这让我十分头疼,毕竟不是谁都有心情去看源码的。但考虑到 spring boot 的项目最好还是用 java configuration 为好,所以只好提供一个非官方配置供参考使用。

java 复制代码
public class HbaseConfiguration {
    @Bean
    public HbaseTemplate hbaseTemplate() {
        org.apache.hadoop.conf.Configuration configuration = HBaseConfiguration.create();
        configuration.set("hbase.zookeeper.quorum", "address1:port","address2:port");
        return new HbaseTemplate(configuration);
    }
}

第三步:开始运行。

java 复制代码
public class HbaseTemplateTest extends BaseTest {

    @Autowired
    private HbaseTemplate hbaseTemplate;

    @Test
    public void hbaseTest() {
        hbaseTemplate.put("zl_test", "lch", "lch", "test", "test2".getBytes());
    }
shell 复制代码
hbase(main):006:0> scan 'zl_test'
ROW                                          COLUMN+CELL
 lch                                         column=lch:test, timestamp=1556627058655, value=test2
1 row(s) in 0.2910 seconds

hbase(main):007:0>

Row key 怎么办?

如果说放弃 phoenix 带来了什么麻烦的话,那就是我们得自己考虑行键问题了。

如果你的项目属于「用户消费内容」且不涉及「高并发」,那基本上可以跳过这一小节。 如果你的项目属于「用户生成内容」或涉及「高并发」那就要好好考虑行键设计。

为写优化

管理 hbase 数据的最小逻辑单元 region ,是按照 rowkey 字典顺序来进行分区划分的。当频繁写入某些连续字符时,可能会造成同一 region 下写入数据过多的情况。

比如,在一个「用户生成内容」的应用程序中,常常使用时间戳作为 rowkey,这样就可能造成同一时间段内大量数据被写入到一个 region 下,产生热点效应。

为了使我们的写入平均分配到各 region 中,必须对 rowkey 做出一些处理。一个简便的方式便是利用散列算法与集群数量做加盐处理。

java 复制代码
Long now = LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli();
String saltedInput = String.format("%s|%s", now.hashCode() % 6, now);
System.out.println(saltedInput);

sout:
4|1556729837940

大功告成,现在 0 ~ 9 会平均分配到不同的 region 分区上,避免了热点效应。

为读(扫描)优化

同样以「在一个用户生成内容的应用程序中使用时间戳作为 rowkey 的情况」作为示例。

为读(扫描)优化意味着你最好把所有的数据尽量放到同一个列族与同一个 region 分区中。 另外,使用倒序时间戳作为 rowkey 也是一个不错的选择。hfile 的有序特性使最新的时间戳数据总是保持在文件起始位,这样在读取操作时就避免了过多的硬盘读,也不需要做额外的排序工作。

到底应该为读还是为写?

回顾上面小节的内容,为写优化意味着在读操作上需要付出相应的代价。现在扫描操作不得不在所有的 region 分区上进行遍历了,这大大增加了 IO 开销。

而为读优化,和为写优化的做法背道而驰,容易造成写入时的热点效应。

是的,读与写无法同时兼顾。为了构建出完整的应用程序你需要做出取舍。

结语

虽然最终选择了使用 spring data 来操作 hbase,但这并不代表其他的方式都不好。每种工具都有自己的特点和不足,结合自己的实际情况做出选择才是最明智的做法。

相关推荐
canonical_entropy7 分钟前
集成NopReport动态生成复杂Word表格
后端·低代码
Raners_11 分钟前
【Java代码审计(2)】MyBatis XML 注入审计
xml·java·安全·网络安全·mybatis
BillKu19 分钟前
Java读取Excel日期内容
java·开发语言·excel
ai小鬼头24 分钟前
如何重装旁路由系统并优化AIStarter部署:一步步教程
java·css·github
come1123433 分钟前
Go 包管理工具详解:安装与使用指南
开发语言·后端·golang
绝无仅有39 分钟前
OSS文件上传解析失败,错误:文件下载失败的排查与解决
后端·面试·架构
笑衬人心。39 分钟前
Hashtable 与 HashMap 的区别笔记
java·数据结构·笔记
金心靖晨42 分钟前
消息中间件优化高手笔记
java·数据库·笔记
LaoZhangAI1 小时前
Kiro vs Cursor:2025年AI编程IDE深度对比
前端·后端