IT评测·应用市场-qidao123.com技术社区
标题:
HBase基础知识分享(一)
[打印本页]
作者:
惊雷无声
时间:
2024-11-13 07:43
标题:
HBase基础知识分享(一)
写在前面
今天来学习Hbase部分的知识!
Zookeeper的ZAB协议
ZAB(Zookeeper Atomic Broadcast)协议
是Zookeeper的核心协议之一,用于保证集群中数据的一致性、次序性和容错性。它包括以下几个关键阶段:
Leader选举
:选举出一个Leader节点来协调集群内的操纵。
事务提案
:客户端提交的事务会被提案并传播到集群中。
投票与提交
:集群中的所有节点投票确认事务,然后提交。
ZAB协议的设计灵感来自于Paxos协议,但简化了许多步骤,使其更加适合Zookeeper这种主要用作协调服务的分布式系统。
ZAB协议的特点
保证数据一致性。
通过Leader节点保证次序性。
容错性强,能应对节点故障或网络分区。
为分布式系统提供强一致性,确保高可用性和稳定性。
HBase的特点
大规模
:支持百万级别的列和行,适合存储海量数据。
面向列族
:数据存储按列族进行分组,提供灵活的存储和权限控制。
希罕
:只对有数据的列分配存储空间,节省存储。
无模式(No Schema)
:每行可以有差别的列,不强制列的定义。
数据多版本
:支持多版本数据,每个单元格有多个版本,可以根据时间戳查询差别版本。
数据单一类型
:所有数据都以字节数组存储,无类型区分。
HBase的三维有序结构
HBase的数据按
行键、列族和时间戳
三个维度进行排序:
行键(Row Key)
:数据按行键的字典次序排序,行键是HBase存储的基本粒度。
列族(Column Family)
:数据按列族进行分组,同一个列族内的数据按列名排序。
时间戳(Timestamp)
:同一个单元格内的数据可以有多个版本,按时间戳的次序排序,支持多版本数据。
这个设计使得HBase在处理惩罚大数据时具有高效的查询、存储和写入能力。
如何定位到 HBase 的
Cell
行键(Row Key)
:HBase中的数据按行键次序存储,因此要查询某个
Cell
,需要知道它的行键。通过查询行键,可以定位到包含该行数据的
RegionServer
。
列族(Column Family)和列名(Column Qualifier)
:一旦确定了目的行,下一步是确定目的列。HBase按列族存储数据,每个列族包含多个列,查询时需要指定列族和列名。
时间戳(Timestamp)
:HBase中的每个单元格按时间戳版本排序。每次写入时,HBase会自动为每个单元格分配一个时间戳。假如没有显式指定时间戳,默认利用当前时间戳。
通过
行键、列族、列名和时间戳
,可以精确地查询到一个
Cell
。
什么是
Region
?通过
RK
定位到
Region
Region
是HBase存储数据的最小单元,负责存储一个连续范围的行数据。
Region
根据行键范围划分,HBase会根据行键自动将数据划分到差别的
Region
。
通过
行键(Row Key)
,HBase可以定位到某个
Region
。每个
Region
都有一个行键范围,当查询时,HBase会根据行键判断它所属的Region。
HBase通过
Zookeeper
或
Master节点
来管理Region和RegionServer的分配。查询时,客户端通过行键查询Zookeeper或Master,得到对应的Region和RegionServer信息。
HBase的数据模型
RowKey
:用于唯一标识一行数据,是HBase查询数据的主键。
支持通过单个RowKey、RowKey范围或正则表达式等方式查询。
RowKey按字典次序存储,最大长度64KB,通常应用中为10~100字节。
列簇(Column Family)
:
列簇是表的结构部分,表创建时必须指定至少一个列簇。
列簇内的数据按列名排序。
HBase中的数据存储、权限控制和版本控制都是按列簇进行的。
时间戳
:
每条数据都会记录时间戳,支持多版本数据存储。
按时间戳倒序存储,获取数据时默认返回最新版本。
设置TTL(Time to Live)时,HBase会根据时间戳自动删除逾期数据。
Cell
:
由
RowKey
、
Column(列簇+列名)
和
Version(时间戳)
唯一标识。
HBase中的数据都以字节数组情势存储。
HBase的架构及读写流程
HBase的架构主要包括以下组件:
Client
:提交读写请求。
HMaster
:负责管理Region和RegionServer的分配。
RegionServer
:负责存储和处理惩罚Region数据。
Zookeeper
:协调HBase集群中的节点,维护元数据。
HBase读写流程:
写入流程
:客户端请求写入数据,HBase首先将数据写入
MemStore
,然后异步刷写到HFile中。当数据到达阈值时,会触发Region的分裂。
读取流程
:客户端请求读取数据,HBase根据行键定位到对应的RegionServer,并从MemStore或HFile中读取数据。
常用的HBase比较器与过滤器
比较器(Comparator)
BinaryComparator
:按字节索引次序比较字节数组。
BinaryPrefixComparator
:比较字节数组的前缀是否匹配。
RegexStringComparator
:利用正则表达式比较字符串。
SubstringComparator
:判断一个子串是否存在于目的字符串中。
HBase有哪些常用的过滤器?
单列值过滤器:SingleColumnValueFilter
SingleColumnValueFilter会返回满足条件的cell所在行的所有cell的值(即会返回一行数据)
通过SingleColumnValueFilter与查询文科班所有学生信息
@Test
// 通过SingleColumnValueFilter与查询文科班所有学生信息
public void RegexStringComparatorFilter() throws IOException {
Table students = conn.getTable(TableName.valueOf("students"));
SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(
"info".getBytes(),
"clazz".getBytes(),
CompareFilter.CompareOp.EQUAL,
new RegexStringComparator("^文科.*")
);
Scan scan = new Scan();
scan.setFilter(singleColumnValueFilter);
ResultScanner scanner = students.getScanner(scan);
Result rs = scanner.next();
while (rs != null) {
String id = Bytes.toString(rs.getRow());
String name = Bytes.toString(rs.getValue("info".getBytes(), "name".getBytes()));
int age = Bytes.toInt(rs.getValue("info".getBytes(), "age".getBytes()));
String gender = Bytes.toString(rs.getValue("info".getBytes(), "gender".getBytes()));
String clazz = Bytes.toString(rs.getValue("info".getBytes(), "clazz".getBytes()));
System.out.println(id + "\t" + name + "\t" + age + "\t" + gender + "\t" + clazz + "\t");
rs = scanner.next();
}
}
复制代码
列值清除过滤器:SingleColumnValueExcludeFilter
与SingleColumnValueFilter相反,会清除掉指定的列,其他的列全部返回
通过SingleColumnValueExcludeFilter与BinaryComparator查询文科一班所有学生信息,最终不返回clazz列
@Test
// 通过SingleColumnValueExcludeFilter与BinaryComparator查询文科一班所有学生信息,最终不返回clazz列
public void RegexStringComparatorExcludeFilter() throws IOException {
Table students = conn.getTable(TableName.valueOf("students"));
SingleColumnValueExcludeFilter singleColumnValueExcludeFilter = new SingleColumnValueExcludeFilter(
"info".getBytes(),
"clazz".getBytes(),
CompareFilter.CompareOp.EQUAL,
new BinaryComparator("文科一班".getBytes())
);
Scan scan = new Scan();
scan.setFilter(singleColumnValueExcludeFilter);
ResultScanner scanner = students.getScanner(scan);
Result rs = scanner.next();
while (rs != null) {
String id = Bytes.toString(rs.getRow());
String name = Bytes.toString(rs.getValue("info".getBytes(), "name".getBytes()));
int age = Bytes.toInt(rs.getValue("info".getBytes(), "age".getBytes()));
String gender = Bytes.toString(rs.getValue("info".getBytes(), "gender".getBytes()));
// clazz列为空
String clazz = Bytes.toString(rs.getValue("info".getBytes(), "clazz".getBytes()));
System.out.println(id + "\t" + name + "\t" + age + "\t" + gender + "\t" + clazz + "\t");
rs = scanner.next();
}
}
复制代码
rowkey前缀过滤器:PrefixFilter
通过PrefixFilter查询以150010008开头的所有前缀的rowkey
@Test
// 通过PrefixFilter查询以150010008开头的所有前缀的rowkey
public void PrefixFilterFilter() throws IOException {
Table students = conn.getTable(TableName.valueOf("students"));
PrefixFilter prefixFilter = new PrefixFilter("150010008".getBytes());
Scan scan = new Scan();
scan.setFilter(prefixFilter);
ResultScanner scanner = students.getScanner(scan);
Result rs = scanner.next();
while (rs != null) {
String id = Bytes.toString(rs.getRow());
String name = Bytes.toString(rs.getValue("info".getBytes(), "name".getBytes()));
int age = Bytes.toInt(rs.getValue("info".getBytes(), "age".getBytes()));
String gender = Bytes.toString(rs.getValue("info".getBytes(), "gender".getBytes()));
// clazz列为空
String clazz = Bytes.toString(rs.getValue("info".getBytes(), "clazz".getBytes()));
System.out.println(id + "\t" + name + "\t" + age + "\t" + gender + "\t" + clazz + "\t");
rs = scanner.next();
}
}
复制代码
分页过滤器PageFilter
通过PageFilter查询第三页的数据,每页10条
利用PageFilter分页效率比较低,每次都需要扫描前面的数据,直到扫描到所需要查的数据
可设计一个合理的rowkey来实现分页需求
@Test
// 通过PageFilter查询第三页的数据,每页10条
public void PageFilter() throws IOException {
Table students = conn.getTable(TableName.valueOf("students"));
int PageNum = 3;
int PageSize = 10;
Scan scan = new Scan();
if (PageNum == 1) {
scan.withStartRow("".getBytes());
//使用分页过滤器,实现数据的分页
PageFilter pageFilter = new PageFilter(PageSize);
scan.setFilter(pageFilter);
ResultScanner scanner = students.getScanner(scan);
printRS(scanner);
} else {
String current_page_start_rows = "";
int scanDatas = (PageNum - 1) * PageSize + 1;
PageFilter pageFilter = new PageFilter(scanDatas);
scan.setFilter(pageFilter);
ResultScanner scanner = students.getScanner(scan);
for (Result rs : scanner) {
current_page_start_rows = Bytes.toString(rs.getRow());
}
scan.withStartRow(current_page_start_rows.getBytes());
PageFilter pageFilter1 = new PageFilter(PageSize);
scan.setFilter(pageFilter1);
ResultScanner scanner1 = students.getScanner(scan);
printRS(scanner1);
}
}
复制代码
通过合理的设置rowkey来实现分页功能
@Test
// 通过合理的设置rowkey来实现分页功能,提高效率
public void PageFilterTest2() throws IOException {
Table students = conn.getTable(TableName.valueOf("students"));
int PageSize = 10;
int PageNum = 3;
int baseId = 1500100000;
int start_row = baseId + (PageNum - 1) * PageSize + 1;
int end_row = start_row + PageSize;
Scan scan = new Scan();
scan.withStartRow(String.valueOf(start_row).getBytes());
scan.withStopRow(String.valueOf(end_row).getBytes());
ResultScanner scanner = students.getScanner(scan);
printRS(scanner);
}
复制代码
多过滤器综合查询
查询文科班中的学生中学号以150010008开头并且年龄小于23的学生信息
@Test
// 查询文科班中的学生中学号以150010008开头并且年龄小于23的学生信息
public void FilterListFilter() throws IOException {
Table students = conn.getTable(TableName.valueOf("students"));
Scan scan = new Scan();
SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(
"info".getBytes()
, "clazz".getBytes()
, CompareFilter.CompareOp.EQUAL
, new RegexStringComparator("^文科.*"));
PrefixFilter prefixFilter = new PrefixFilter("150010008".getBytes());
SingleColumnValueFilter singleColumnValueFilter1 = new SingleColumnValueFilter(
"info".getBytes()
, "age".getBytes()
, CompareFilter.CompareOp.LESS
, new BinaryComparator(Bytes.toBytes(23)));
FilterList filterList = new FilterList();
filterList.addFilter(singleColumnValueFilter);
filterList.addFilter(prefixFilter);
filterList.addFilter(singleColumnValueFilter1);
scan.setFilter(filterList);
ResultScanner scanner = students.getScanner(scan);
printRS(scanner);
}
复制代码
今天的分享就到这了,之后会继承分享hbase相关的内容。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/)
Powered by Discuz! X3.4