Hbase安装与使用

Docker安装Hbase-CSDN博客

项目:lean/Hbase_demo

1.安装docker

2.安装Hbase

bash 复制代码
docker pull harisekhon/hbase

3.配置docker-compose.yml文件

bash 复制代码
version: '3.8'

services:
  hbase:
    image: harisekhon/hbase:latest
    container_name: hbase-standalone
    hostname: hbase
    ports:
      - "2181:2181"   # Zookeeper
      - "16000:16000" # HBase Master
      - "16010:16010" # HBase Master Web UI
      - "16020:16020" # HBase RegionServer
      - "16030:16030" # HBase RegionServer Web UI
    environment:
      - HBASE_CONF_hbase_rootdir=file:///hbase-data
      - HBASE_CONF_hbase_zookeeper_property_dataDir=/zookeeper-data
    volumes:
      - hbase-data:/hbase-data
      - zookeeper-data:/zookeeper-data
    networks:
      - hbase-network
    healthcheck:
      test: ["CMD", "hbase", "shell", "-n", "-e", "status"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 60s

volumes:
  hbase-data:
    driver: local
  zookeeper-data:
    driver: local

networks:
  hbase-network:
    driver: bridge

含义如下

1. - "2181:2181" # Zookeeper

  • 含义 :将容器的 2181 端口映射到你电脑的 2181 端口。
  • 作用 :这是 ZooKeeper 的服务端口。
    • HBase 强依赖 ZooKeeper 来管理集群状态。
    • 你的 Java 代码、HBase Shell 或者其他客户端,都需要通过这个端口连接到 HBase 集群。
    • 注意:这就是你刚才报错的原因!因为你电脑上已经有一个程序(你之前启动的独立 ZK 容器)占用了 2181,所以这扇"窗户"打不开了。

2. - "16000:16000" # HBase Master

  • 含义 :将容器的 16000 端口映射到你电脑的 16000 端口。
  • 作用 :这是 HBase MasterRPC 通信端口
    • 这是 HBase 的"大脑"。RegionServer(干活的节点)会连这个端口汇报工作。
    • 客户端(如 Java 代码)也会连这个端口来获取元数据(比如某张表存在哪个 RegionServer 上)。
    • 通常不需要在浏览器访问,主要是给程序内部通信用的。

3. - "16010:16010" # HBase Master Web UI

  • 含义 :将容器的 16010 端口映射到你电脑的 16010 端口。
  • 作用 :这是 HBase Master 的网页管理界面
    • 最常用! 你可以在浏览器输入 http://localhost:16010 访问它。
    • 在这里你可以看到:集群是否健康、有多少个 RegionServer、有哪些表、每个表的读写负载情况等。
    • 它是可视化的监控面板。

4. - "16020:16020" # HBase RegionServer

  • 含义 :将容器的 16020 端口映射到你电脑的 16020 端口。
  • 作用 :这是 RegionServerRPC 通信端口
    • RegionServer 是 HBase 中真正存储数据和处理读写请求的"工人"。
    • 当你的 Java 代码知道数据在哪个 RegionServer 后,会直接连这个端口进行数据的增删改查(Put/Get/Delete)。
    • 这是数据流量最大的端口。

5. - "16030:16030" # HBase RegionServer Web UI

  • 含义 :将容器的 16030 端口映射到你电脑的 16030 端口。
  • 作用 :这是 RegionServer 的网页管理界面
    • 可以在浏览器输入 http://localhost:16030 访问。
    • 这里主要看单个节点的状态,比如这个节点存了哪些 Region(数据分片)、内存使用情况、具体的日志报错等。
    • 通常用于排查某个具体节点的问题。

注意 :docker运行的Hbase还要修改hosts文件,添加127.0.0.1 hbase

4.GUI web界面

复制代码
- "2181:2181"   # Zookeeper
- "16000:16000" # HBase Master  HBase Master 的 RPC 通信端口。
- "16010:16010" # HBase Master Web UI    HBase Master 的网页管理界面。
- "16020:16020" # HBase RegionServer    RegionServer 的 RPC 通信端口。
- "16030:16030" # HBase RegionServer Web UI  RegionServer 的网页管理界面。
Master: hbase

HBase Region Server: hbase

5.Hbase测试项目

注意 :这里我用的3.3.6版本的hadoop,但是还要下载其他的加入到环境变量里面去

下载h~.dll和w~.exe,然后加入到变量就好了,bin路径

依赖

bash 复制代码
<?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>com.example</groupId>
    <artifactId>hbase-log-demo</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    <name>HBase测试项目</name>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.18</version>
        <relativePath/>
    </parent>

    <properties>
        <java.version>17</java.version>
        <!-- 推荐使用稳定的 2.4.x 版本,兼容性最好 -->
        <hbase.version>2.6.4</hbase.version>
        <!-- 显式指定 Hadoop 版本,避免依赖冲突 -->
        <hadoop.version>3.3.6</hadoop.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- 强制锁定 Hadoop 所有核心组件为 3.3.6 -->
            <dependency>
                <groupId>org.apache.hadoop</groupId>
                <artifactId>hadoop-common</artifactId>
                <version>3.3.6</version>
            </dependency>
            <dependency>
                <groupId>org.apache.hadoop</groupId>
                <artifactId>hadoop-auth</artifactId>
                <version>3.3.6</version>
            </dependency>
<!--            <dependency>-->
<!--                <groupId>org.apache.hadoop</groupId>-->
<!--                <artifactId>hadoop-hdfs</artifactId>-->
<!--                <version>3.3.6</version>-->
<!--            </dependency>-->
<!--            <dependency>-->
<!--                <groupId>org.apache.hadoop</groupId>-->
<!--                <artifactId>hadoop-mapreduce-client-core</artifactId>-->
<!--                <version>3.3.6</version>-->
<!--            </dependency>-->

            <!-- 锁定 HBase 版本 -->
            <dependency>
                <groupId>org.apache.hbase</groupId>
                <artifactId>hbase-client</artifactId>
                <version>2.4.18</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- Spring Boot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Spring Boot Test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- HBase Client -->
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-client</artifactId>
            <version>${hbase.version}</version>
            <!-- 排除旧版日志和可能冲突的组件 -->
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>log4j</groupId>
                    <artifactId>log4j</artifactId>
                </exclusion>
                <!-- 排除 jetty,避免与 Spring Boot 内置 Tomcat 冲突 -->
                <exclusion>
                    <groupId>org.eclipse.jetty</groupId>
                    <artifactId>*</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- HBase Common (显式引入以确保类完整) -->
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-common</artifactId>
            <version>${hbase.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>log4j</groupId>
                    <artifactId>log4j</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!--
           【关键】显式引入 Hadoop Common
           解决 "HADOOP_HOME and hadoop.home.dir are unset" 的关键依赖之一
           必须与 HBase 兼容,3.3.6 是稳定选择
        -->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>${hadoop.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>log4j</groupId>
                    <artifactId>log4j</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.eclipse.jetty</groupId>
                    <artifactId>*</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- Jackson (Spring Boot 已管理版本,通常不需要单独写版本号) -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

配置类

bash 复制代码
package com.yyz.hbase_demo.config;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;

import javax.annotation.PreDestroy;
import java.io.IOException;

/**
 * HBase配置类
 */
@org.springframework.context.annotation.Configuration
public class HBaseConfig {

    @Value("${hbase.config.zk-quorum}")
    private String zkQuorum;

    @Value("${hbase.config.client-port}")
    private String clientPort;

    @Value("${hbase.config.zookeeper-znode-parent}")
    private String znodeParent;

    private Connection connection;

    @Bean
    public Connection hbaseConnection() throws IOException {
        try {
        Configuration config = HBaseConfiguration.create();
        config.set("hbase.zookeeper.quorum", zkQuorum);
        config.set("hbase.zookeeper.property.clientPort", clientPort);
        config.set("zookeeper.znode.parent", znodeParent);
        config.set("hbase.client.write.buffer", "0");
        connection = ConnectionFactory.createConnection(config);
        System.out.println("HBase连接已创建");
        return connection;
        } catch (Exception e) {
            e.printStackTrace();
            // 重要:如果连接失败,不要让它卡住主线程,可以返回 null 或者抛出一个明确的运行时异常
            // 但为了调试,暂时让它抛出,方便你知道错了
            throw new RuntimeException("HBase 连接失败,请检查 HBase 服务及 hosts 配置", e);
        }
    }

    @PreDestroy
    public void closeConnection() throws IOException {
        if (connection != null && !connection.isClosed()) {
            connection.close();
        }
    }
}

控制器

bash 复制代码
package com.yyz.hbase_demo.controller;

import com.yyz.hbase_demo.entity.LogEntry;
import com.yyz.hbase_demo.service.LogService;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.List;

/**
 * 日志控制器
 */
@RestController
@RequestMapping("/api/logs")
public class LogController {

    private final LogService logService;

    public LogController(LogService logService) {
        this.logService = logService;
    }

    @GetMapping
    public String getAllLogs() {
        return "Hello World!";
    }

    @PostMapping
    public String addLog(@RequestBody LogEntry log) {
        try {
            logService.saveLog(log);
            return "Success: Log saved for user " + log.getUserId();
        } catch (IOException e) {
            e.printStackTrace();
            return "Error: " + e.getMessage();
        }
    }

    @GetMapping("/user/{userId}")
    public List<LogEntry> getUserLogs(@PathVariable String userId) {
        try {
            return logService.getUserLogs(userId);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    @GetMapping("/user/{userId}/action/{action}")
    public List<LogEntry> getUserLogsByAction(@PathVariable String userId, @PathVariable String action) {
        try {
            return logService.getUserLogsByAction(userId, action);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

实体

bash 复制代码
package com.yyz.hbase_demo.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 日志实体类
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LogEntry {
    private String userId;
    private String action;      // 例如:CLICK, VIEW, ERROR
    private String pageUrl;
    private long timestamp;
    private String details;     // 额外信息
}

数据层

bash 复制代码
package com.yyz.hbase_demo.repository;

import com.yyz.hbase_demo.entity.LogEntry;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.filter.CompareFilter;
import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
import org.apache.hadoop.hbase.util.Bytes;
import org.springframework.stereotype.Repository;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * HBase数据访问层
 */
@Repository
public class LogRepository {

    private final Connection connection;
    private static final String TABLE_NAME_STR = "user_logs";
    private static final byte[] TABLE_NAME = Bytes.toBytes(TABLE_NAME_STR);
    private static final byte[] CF = Bytes.toBytes("cf");
    private static final byte[] COL_ACTION = Bytes.toBytes("action");
    private static final byte[] COL_URL = Bytes.toBytes("url");
    private static final byte[] COL_DETAILS = Bytes.toBytes("details");
    private static final byte[] COL_TS = Bytes.toBytes("ts");

    public LogRepository(Connection connection) {
        this.connection = connection;
    }

    @PostConstruct
    public void initTable() throws IOException {
        Admin admin = connection.getAdmin();

        // 检查表是否存在,不存在则创建
        if (!admin.tableExists(TableName.valueOf(TABLE_NAME))) {
            System.out.println(">>> Table '" + TABLE_NAME_STR + "' does not exist. Creating...");

            // 1. 创建表描述符建造者
            TableDescriptorBuilder tableBuilder = TableDescriptorBuilder.newBuilder(TableName.valueOf(TABLE_NAME));

            // 2. 【关键修改】创建列族描述符
            // ColumnFamilyDescriptorBuilder.of() 返回的是一个 ModifyableColumnFamilyDescriptor (实现了 ColumnFamilyDescriptor)
            // 所以变量类型必须是 ColumnFamilyDescriptor,不能是 Builder
            ColumnFamilyDescriptor cfDescriptor = ColumnFamilyDescriptorBuilder.of(CF);

            // 3. 设置列族属性 (需要强转为可修改的实现类才能设置setMaxVersions)
            // 注意:of() 返回的对象通常就是 ModifyableColumnFamilyDescriptor
            if (cfDescriptor instanceof ColumnFamilyDescriptorBuilder.ModifyableColumnFamilyDescriptor) {
                ((ColumnFamilyDescriptorBuilder.ModifyableColumnFamilyDescriptor) cfDescriptor).setMaxVersions(5);
            }

            // 4. 将列族描述符加入表建造者
            // 直接传入 cfDescriptor,因为它已经是最终对象了,不需要再 .build()
            tableBuilder.setColumnFamily(cfDescriptor);

            // 5. 构建表描述符并创建表
            admin.createTable(tableBuilder.build());

            System.out.println(">>> Table '" + TABLE_NAME_STR + "' created successfully.");
        } else {
            System.out.println(">>> Table '" + TABLE_NAME_STR + "' already exists.");
        }

        admin.close();
    }

    public void save(LogEntry log) throws IOException {
        Table table = connection.getTable(TableName.valueOf(TABLE_NAME));
        try {
            String rowKeyStr = log.getUserId() + "_" + log.getTimestamp();
            Put put = new Put(Bytes.toBytes(rowKeyStr));

            put.addColumn(CF, COL_ACTION, Bytes.toBytes(log.getAction()));
            put.addColumn(CF, COL_URL, Bytes.toBytes(log.getPageUrl()));
            put.addColumn(CF, COL_DETAILS, Bytes.toBytes(log.getDetails()));
            put.addColumn(CF, COL_TS, Bytes.toBytes(log.getTimestamp()));

            table.put(put);
        } finally {
            table.close();
        }
    }

    public List<LogEntry> findByUserId(String userId) throws IOException {
        List<LogEntry> results = new ArrayList<>();
        Table table = connection.getTable(TableName.valueOf(TABLE_NAME));
        try {
            Scan scan = new Scan();
            byte[] startRow = Bytes.toBytes(userId + "_");
            byte[] stopRow = Bytes.toBytes(userId + "_\uffff");

            scan.withStartRow(startRow);
            scan.withStopRow(stopRow);
//            scan.setReversed(true);

            ResultScanner scanner = table.getScanner(scan);
            for (Result result : scanner) {
                results.add(parseResult(result));
            }
            scanner.close();
        } finally {
            table.close();
        }
        return results;
    }

    public List<LogEntry> findByUserIdAndAction(String userId, String action) throws IOException {
        List<LogEntry> results = new ArrayList<>();
        Table table = connection.getTable(TableName.valueOf(TABLE_NAME));
        try {
            Scan scan = new Scan();
            byte[] startRow = Bytes.toBytes(userId + "_");
            byte[] stopRow = Bytes.toBytes(userId + "_\uffff");
            scan.withStartRow(startRow);
            scan.withStopRow(stopRow);

            SingleColumnValueFilter filter = new SingleColumnValueFilter(
                    CF,
                    COL_ACTION,
                    CompareFilter.CompareOp.EQUAL,
                    Bytes.toBytes(action)
            );
            filter.setFilterIfMissing(true);
            scan.setFilter(filter);

            ResultScanner scanner = table.getScanner(scan);
            for (Result result : scanner) {
                results.add(parseResult(result));
            }
            scanner.close();
        } finally {
            table.close();
        }
        return results;
    }

    private LogEntry parseResult(Result result) {
        String rowKey = Bytes.toString(result.getRow());
        String[] parts = rowKey.split("_");
        String userId = parts[0];
        long ts = Long.parseLong(parts[1]);

        String action = Bytes.toString(result.getValue(CF, COL_ACTION));
        String url = Bytes.toString(result.getValue(CF, COL_URL));
        String details = Bytes.toString(result.getValue(CF, COL_DETAILS));

        return new LogEntry(userId, action, url, ts, details);
    }
}

方法层

bash 复制代码
package com.yyz.hbase_demo.service;

import com.yyz.hbase_demo.entity.LogEntry;
import com.yyz.hbase_demo.repository.LogRepository;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;

/**
 * 日志业务逻辑层
 */
@Service
public class LogService {

    private final LogRepository logRepository;

    public LogService(LogRepository logRepository) {
        this.logRepository = logRepository;
    }

    public void saveLog(LogEntry log) throws IOException {
        if (log.getTimestamp() == 0) {
            log.setTimestamp(System.currentTimeMillis());
        }
        logRepository.save(log);
    }

    public List<LogEntry> getUserLogs(String userId) throws IOException {
        return logRepository.findByUserId(userId);
    }

    public List<LogEntry> getUserLogsByAction(String userId, String action) throws IOException {
        return logRepository.findByUserIdAndAction(userId, action);
    }
}
相关推荐
weiyvyy2 小时前
信息化建设从蓝图到实践-数据体系建设
大数据·人工智能
是梦终空1162 小时前
Python深度学习入门:TensorFlow 2.0/Keras实战
jvm·数据库·python
NineData2 小时前
AI 时代的数据对比:DBA 还需要盯着屏幕看差异吗?
数据库·人工智能·dba·数据库管理工具·数据一致性·数据对比·异构迁移
武子康2 小时前
大数据-248 离线数仓 - 电商分析 Hive 离线数仓维表设计实战:快照表、拉链表与 DIM 增量加载全流程
大数据·后端·apache hive
原来是猿2 小时前
MySQL【基本查询上 - 表的增删改查】
数据库·mysql
scofield_gyb2 小时前
Redis简介、常用命令及优化
数据库·redis·缓存
難釋懷2 小时前
Redis搭建分片集群
数据库·redis·缓存
happymaker06262 小时前
JDBC(MySQL)——DAY04(调用存储过程,存储函数)
java·数据库·mysql
微学AI3 小时前
时序数据库选型:聚焦时间序列数据库Apache IoTDB——为工业物联网与大数据而生
数据库·apache·时序数据库