hbase数据模型
概述
hbase 的设计理念依据 google 的 bigtable 论文,论文中对于数据模型的首句介绍。
bigtable 是一个稀疏的、分布式的、持久的多维排序map。
之后对于映射的解释如下:“
该映射由行键、列键和时间戳索引:映射中的每个值都是一个未解释的字节数组。
最终hbase 关于数据模型和 bigtable 的对应关系如下:“
hbase 使用与 bigtable 非常相似的数据模型。用户将数据行存储在带标签的表中。数
据行具有可排序的键和任意数量的列。该表存储稀疏,因此如果用户喜欢,同一表中的行可
以具有疯狂变化的列。“
最终理解 hbase 数据模型的关键在于稀疏、分布式、多维、排序的映射。其中映射 map
指代非关系型数据库的 kev-value 结构。
hbase分布式环境部署
关闭: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 提供高容错的支持。
region和table
region位于不同节点,而按照列族切分为store用于底层存储到不同的文件夹中,便于文件对应。
也就是说横着切 是为了存放不同节点,而竖着切是为了存放在同一节点的不同数据,比较列族可以无限扩张。
逻辑架构 - row
hbase 表中的每行数据都由一个 rowkey 和多个 column (列)组成,数据是按照rowkey的字典顺序存储的,并且查询数据时只能根据 rowkey 进行检索,所以rowkey 的设计十分重要。
hbase所有数据以字节方式存储,每行由以下五列组成
- rowkey(行键) 行号
- 列号 列族+列名
- 时间戳(标记版本)以便更新 使用唯一时间戳维护多个row版本
- type put写入 delete 删除
- value 数据值
hbase元数据管理
hbase应用场景示例
经过以上设计架构了解,可以理解以下场景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底下的相关文件,当然表数据自然全无。
还请细心照料!!!、
发表评论