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相关的内容。