HBase初识:很脆很能装

HBase数据模型

概述

HBase 的设计理念依据 Google 的 BigTable 论文,论文中对于数据模型的首句介绍。
Bigtable 是一个稀疏的、分布式的、持久的多维排序map。
之后对于映射的解释如下:“
该映射由行键、列键和时间戳索引:映射中的每个值都是一个未解释的字节数组。
最终HBase 关于数据模型和 BigTable 的对应关系如下:“
HBase 使用与 Bigtable 非常相似的数据模型。用户将数据行存储在带标签的表中。数
据行具有可排序的键和任意数量的列。该表存储稀疏,因此如果用户喜欢,同一表中的行可
以具有疯狂变化的列。“
最终理解 HBase 数据模型的关键在于稀疏、分布式、多维、排序的映射。其中映射 map
指代非关系型数据库的 kev-Value 结构。 

HBase是一个领先的 NoSQL 数据库
是一个面向列存储的 NoSQL 数据库
是一个分布式 H ash M ap,底层数据是 Key-Value 格式
基于Google Big Table论文
使用HDFS作为存储并利用其可靠性
HBase 特点
数据访问速度快,响应时间约2-20毫秒
支持 随机读写 ,每个节点20k ~ 100k+ ops/s
可扩展性,可扩展到20,000 + 节点
高并发

HBase分布式环境部署

启动 ZooKeeper
启动Hadoop( HDFS YARN
上传、解压、配置环境变量并修改配置文件
hbase-env.sh
hbase-site.xml
regionservers
启动测试
启动: start-hbase.sh

关闭:stop-hbase.sh

务必先关闭hbase  在关闭zookeeper

HBase的设计

物理架构

Master
主要进程,具体实现类为HMaster,通常部署在namenode上
功能:负责通过ZK监控RecionServer进程状态,同时是所有元数据变化
的接口。内部启动监控执行region的故障转移和拆分的线程。
RegionServer
主要进程,具体实现类为HRegionServer,部署在datanode上
功能:主要负责数据cell的处理。同时在执行区域的拆分和合并的时候
 由RegionServer来实际执行
(如配置高可用则存在backup)

Hdfs集群存储表格数据HBase把表格的数据存储到hdfs上面,按照namespace- >table->region->store的格式划分文件夹存储。在store中存储HFile,内部为对应的cell。

Master

  • 实现类为HMaster,负责监控集群中所有的 RegionServer 实例。主要作用如下: 管理元数据表格 hbase:meta,接收用户对表格创建修改删除的命令并执行
  • 监控 region 是否需要进行负载均衡,故障转移和 region 的拆分。 通过启动多个后台线程监控实现上述功能: DLoadBalancer 负载均衡器 周期性监控 region 分布在 regionServer 上面是否均衡,由参数 hbase.balancer.period 控制周期时间,默认5分钟。CatalogJanitor 元数据管理器、 定期检查和清理hbase:meta中的数据

CatalogJanitor元数据管理器的主要任务是确保这些元数据的准确性和一致性。它会定期检查.META.表中的元数据,查找并清理可能存在的过期、无效或冗余的数据。这种清理过程对于保持HBase集群的健康运行至关重要,可以避免由于元数据不一致或错误导致的各种问题。

具体来说,CatalogJanitor可能会清理的数据包括:

过期或孤立的元数据:当HBase中的表被删除或修改时,相关的元数据可能不再需要。CatalogJanitor会识别并删除这些不再需要的元数据。

冗余的元数据:有时,由于各种原因(如系统错误、重复操作等),.META.表中可能会出现重复的元数据。CatalogJanitor会检测和删除这些冗余数据。

不一致的元数据:如果HBase集群中的元数据出现不一致的情况(例如,某个表的元数据在两个不同的Region中都有记录),CatalogJanitor会尝试修复或删除这些不一致的数据。

MasterProcWAL master 预写日志处理器 把master 需要执行的任务记录到预写日志 WAL中,如果 master 宕机,让 backupMaster 读取日志继续干。

而meta就是专门用来存储和Region相关的信息。

Meat表内具体存放哪些信息: 
rowkey:由四个字段拼接起来,分别是 表名-StratRow-TimeStamp-EncodedName。

数据分为4列:

  • info:regioninfo:EncodedName、RegionName、Region的StartRow、Region的StopRow;
  • info:seqnumDuringOpen:存储Region打开时的sequenceId;
  • info:server:存储Region落在哪个RegionServer上;
  • info:serverstartcode:存储所在的RegionServer启动时间戳;

 Region Server 实现类为 HRegionServer,主要作用如下:

  • 负责数据 cell 的处理,例如写入数据 put,查询数据get 等
  • 拆分并region的实际执行者,有 master 监控,有 regionServer 执行。
  • Zookeeper HBase 通过 Zookeeper 来做 master 的高可用、记录 RegionServer 的部署信息、并且存储 有 meta 表的位置信息。“ HBase 对于数据的读写操作时直接访问 Zokeeper 的,在2.3 版本推出Master Registry 模式,客户端可以直接访问 master。使用此功能,会加大对 master 的压力,减轻对 Zookeeper的压力。

4) HDFS HDFS为Hbase 提供最终的底层数据存储服务,同时为HBase 提供高容错的支持。

 

RegionTable

Region位于不同节点,而按照列族切分为store用于底层存储到不同的文件夹中,便于文件对应。

也就是说横着切  是为了存放不同节点,而竖着切是为了存放在同一节点的不同数据,比较列族可以无限扩张。

逻辑架构 - Row

HBase 表中的每行数据都由一个 RowKey 和多个 Column (列)组成,数据是按照RowKey的字典顺序存储的,并且查询数据时只能根据 RowKey 进行检索,所以RowKey 的设计十分重要。

Hbase所有数据以字节方式存储,每行由以下五列组成

  • Rowkey(行键) 行号
  • 列号  列族+列名 
  • 时间戳(标记版本)以便更新   使用唯一时间戳维护多个Row版本
  • type put写入 delete 删除
  • value 数据值

HBase数据管理

数据管理目录
系统目录表hbase:meta
存储元数据
ZooKeeper 存储 hbase:meta表的位置信息
HBase 实际数据存储在 HDFS

 HBase应用场景示例

经过以上设计架构了解,可以理解以下场景hbase 的应用。

增量数据-时间序列数据
高容量,高速写入
HBase之上有OpenTSDB模块,可以满足时序类场景,比如传感器,系统监控,股票行情监控等

信息交换-消息传递
高容量,高速读写
通信、消息同步的应用构建在HBase之上,比如 email FaceBook
内容服务-Web后端应用程序
高容量,高速读写
头条类、新闻类的的新闻、网页、图片存储在HBase中

 HBase的交互模式shell

[root@centos143 ~]# hbase shell
hbase(main):001:0> version         -- 查看当前hbase版本

hbase(main):002:0> list_namespace   -- 查看所有表空间

hbase(main):003:0> create_namespace 'xxy'  -- 创建表空间

-- 创建表
hbase(main):005:0> create 'xxy:student','baseinfo','schoolinfo'

--查看表详情
hbase(main):008:0> describe 'xxy:student'

启用/禁用
hbase(main):007:0> disable 'xxy:student'
hbase(main):011:0> enable 'xxy:student'
hbase(main):009:0> is_disabled 'xxy:student'
hbase(main):010:0> is_enabled 'xxy:student'

--删除表,必须将要删除的表先禁用
hbase(main):014:0> disable 'xxy:student'
hbase(main):014:0> drop 'xxy:student'

-- 删除表空间前必须将表空间中的所有表全部删除
hbase(main):020:0> drop_namespace 'xxy'

-- 显示指定表空间内所有的表    show tables;
hbase(main):024:0> list_namespace_tables 'xxy'

查看表是否存在
hbase(main):026:0> exists 'xxy:student'

--添加一个列簇
hbase(main):031:0> alter 'xxy:student','teacherinfo'

--删除列簇  teacherinfo
hbase(main):031:0> alter 'xxy:student',{NAME=>'teacherinfo',METHOD=>'delete'}

--改变列簇版本限制
hbase(main):034:0> alter 'xxy:student',{NAME=>'baseinfo',VERSIONS=>3}

--插入数据
hbase(main):036:0> put 'xxy:student','rowkey1','baseinfo:name','tom'
Took 0.0591 seconds                                                                                                   
hbase(main):037:0> put 'xxy:student','rowkey1','baseinfo:birthday','1990-01-09'
Took 0.0046 seconds                                                                                                   
hbase(main):038:0> put 'xxy:student','rowkey1','baseinfo:age','34'
Took 0.0081 seconds                                                                                                   
hbase(main):039:0> put 'xxy:student','rowkey1','schoolinfo:name','njyd'
Took 0.0059 seconds                                                                                                   
hbase(main):040:0> put 'xxy:student','rowkey1','schoolinfo:address','nanjing'

-- get查询
hbase(main):041:0> get 'xxy:student','rowkey1'
查询指定表的指定列簇中的数据
hbase(main):042:0> get 'xxy:student','rowkey1','baseinfo'
hbase(main):043:0> get 'xxy:student','rowkey1','schoolinfo'
查询指定表中的指定列簇中的列
hbase(main):044:0> get 'xxy:student','rowkey1','schoolinfo:address'

hbase(main):045:0> put 'xxy:student','rowkey1','baseinfo:name','xxy'
hbase(main):047:0> put 'xxy:student','rowkey1','baseinfo:name','lijia'

查看历史版本数据,默认只保留当前版本
hbase(main):050:0> get 'xxy:student','rowkey1',{COLUMN=>'baseinfo:name',VERSIONS=>3}

Java Api

// Get client admin

Configuration config = HBaseConfiguration.create();
config.Path("/opt/install/hbase/conf/hbase-site.xml");
config.Path("/opt/install/hadoop/etc/hadoop/conf/core-site.xml");
connect= ConnectionFactory.createConnection(config);
admin =
connect.getAdmin();

// 执行表操作

admin.createTable()

admin.disableTable()

admin.deleteTable()

admin.listTable()

kafka 写入 hbase

附上一个java 将kafka清洗完的生产者数据写入  hbase  events_db:users表的实例

建表语句已在代码中注释

 


import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;

import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;

import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.serialization.StringDeserializer;

import java.io.IOException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Properties;


public class UsersTohb { //38209
    static  long rowNum=0;
    public static void main(String[] args) {
        Properties prop = new Properties();
        prop.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.78.143:9092");
        prop.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        prop.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);

        // 设置是否自动提交, false 手动提交,  true 自动提交
        prop.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false");
        prop.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "500");
        prop.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");

//        配置消费者组
        prop.put(ConsumerConfig.GROUP_ID_CONFIG, "users_group1");
        KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String>(prop);
        consumer.subscribe(Collections.singleton("users")); //取


        //hbase
        Configuration conf = HBaseConfiguration.create();
        conf.set("hbase.zookeeper.quorum", "192.168.78.143");
        conf.set("hbase.zookeeper.property.clientPort", "2181");
        conf.set("hbase.roodir", "hdfs://192.168.78.143:9000/hbase");
        Connection conn = null;
        try {
            conn = ConnectionFactory.createConnection(conf);
//            Table table = conn.getTable(TableName.valueOf("bigdata:teacher"));
            TableName tableName = TableName.valueOf("events_db:users");
            final BufferedMutator.ExceptionListener listener = new BufferedMutator.ExceptionListener() {

                public void onException(RetriesExhaustedWithDetailsException exception, BufferedMutator mutator) throws RetriesExhaustedWithDetailsException {//监听失败
                    int nums = exception.getNumExceptions();
                    for (int i = 0; i < nums; i++) {
                        System.err.println("失败 保存" + exception.getRow(i) + ".");
                    }
                }
            };
            BufferedMutatorParams parms = new BufferedMutatorParams(tableName);
            parms.writeBufferSize(1024 * 1024);
            parms.listener(listener);
            parms.setWriteBufferPeriodicFlushTimeoutMs(2 * 1000);//2s 刷一次

            BufferedMutator mutator = conn.getBufferedMutator(parms);
            ArrayList<Put> list = new ArrayList<>();
            while (true) {
                list.clear();
                ConsumerRecords<String, String> poll =
                        consumer.poll(Duration.ofMillis(100));
                for (ConsumerRecord<String, String> record : poll) {
                    rowNum++;
                    String[] user = record.value().split(",");
                    Put put = new Put(user[0].getBytes());
//                    create 'events_db:users', 'profile', 'region', 'registration'
//                    create 'events_db:user_friend', 'uf'
//                    create 'events_db:events', 'schedule', 'location', 'creator', 'remark'
//                    create 'events_db:event_attendee', 'euat'
//                    create 'events_db:train', 'eu'
                    put.addColumn("region".getBytes(),"locale".getBytes(),user[1].getBytes());
                    put.addColumn("profile".getBytes(),"birthday".getBytes(),user[2].getBytes());
                    put.addColumn("profile".getBytes(),"gender".getBytes(),user[3].getBytes());
                    if(user.length>4){
                        put.addColumn("registration".getBytes(),"joinAt".getBytes(),user[4].getBytes());
                    }
                    if(user.length>5){
                        put.addColumn("region".getBytes(),"location".getBytes(),user[5].getBytes());
                    }
                    if(user.length>6){
                        put.addColumn("region".getBytes(),"timezone".getBytes(),user[6].getBytes());
                    }
                    list.add(put);
                  
                }
                if(list.size()>0)
                mutator.mutate(list);
            }
            //Thread.sleep(1000);
            
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


    }
}

scan表中数据如下

为什么说hbase很脆呢,因为笔者在学习过程中真的玩坏了很多次,请每次学习结束后务必关闭hbase后再挂起(先关闭啥再关啥想清楚),其他东西不一定坏,hbase是真的脆

尝试用线程池 向hbase 写入模拟的几百万条数据 写崩过好几次,后来乖乖单线程 慢慢等。

坏了之后修需 删掉hbase 跟 zookeeper cli底下的相关文件,当然表数据自然全无。

还请细心照料!!!、

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值