HBase 数据库检索性能优化策略

HBase 数据表介绍

HBase 数据库是一个基于分布式的、面向列的、主要用于非结构化数据存储用途的开源数据库。其设计思路来源于 Google 的非开源数据库”BigTable”。

HDFS 为 HBase 提供底层存储支持,MapReduce 为其提供计算能力,ZooKeeper 为其提供协调服务和 failover(失效转移的备份操作)机制。Pig 和 Hive 为 HBase 提供了高层语言支持,使其可以进行数据统计(可实现多表 join 等),Sqoop 则为其提供 RDBMS 数据导入功能。

HBase 不能支持 where 条件、Order by 查询,只支持按照主键 Rowkey 和主键的 range 来查询,但是可以通过 HBase 提供的 API 进行条件过滤。

HBase 的 Rowkey 是数据行的唯一标识,必须通过它进行数据行访问,目前有三种方式,单行键访问、行键范围访问、全表扫描访问。数据按行键的方式排序存储,依次按位比较,数值较大的排列在后,例如 int 方式的排序:1,10,100,11,12,2,20…,906,…。

ColumnFamily 是“列族”,属于 schema 表,在建表时定义,每个列属于一个列族,列名用列族作为前缀“ColumnFamily:qualifier”,访问控制、磁盘和内存的使用统计都是在列族层面进行的。

Cell 是通过行和列确定的一个存储单元,值以字节码存储,没有类型。

Timestamp 是区分不同版本 Cell 的索引,64 位整型。不同版本的数据按照时间戳倒序排列,最新的数据版本排在最前面。

Hbase 在行方向上水平划分成 N 个 Region,每个表一开始只有一个 Region,数据量增多,Region 自动分裂为两个,不同 Region 分布在不同 Server 上,但同一个不会拆分到不同 Server。

Region 按 ColumnFamily 划分成 Store,Store 为最小存储单元,用于保存一个列族的数据,每个 Store 包括内存中的 memstore 和持久化到 disk 上的 HFile。

图 1 是 HBase 数据表的示例,数据分布在多台节点机器上面。

图 1. HBase 数据表示例(查看大图)HBase 调用 API 示例

类似于操作关系型数据库的 JDBC 库,HBase client 包本身提供了大量可以供操作的 API,帮助用户快速操作 HBase 数据库。提供了诸如创建数据表、删除数据表、增加字段、存入数据、读取数据等等接口。清单 1 提供了一个作者封装的工具类,包括操作数据表、读取数据、存入数据、导出数据等方法。

清单 1.HBase API 操作工具类代码

import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.hbase.HColumnDescriptor;import org.apache.hadoop.hbase.HTableDescriptor;import org.apache.hadoop.hbase.KeyValue;import org.apache.hadoop.hbase.client.Get;import org.apache.hadoop.hbase.client.HBaseAdmin;import org.apache.hadoop.hbase.client.HTable;import org.apache.hadoop.hbase.client.Put;import org.apache.hadoop.hbase.client.Result;import org.apache.hadoop.hbase.client.ResultScanner;import org.apache.hadoop.hbase.client.Scan;import org.apache.hadoop.hbase.util.Bytes;import java.io.IOException;import java.util.ArrayList;import java.util.List;public class HBaseUtil {private Configuration conf = null;private HBaseAdmin admin = null;protected HBaseUtil(Configuration conf) throws IOException { this.conf = conf; this.admin = new HBaseAdmin(conf);}public boolean existsTable(String table) throws IOException { return admin.tableExists(table);}public void createTable(String table, byte[][] splitKeys, String… colfams) throws IOException {HTableDescriptor desc = new HTableDescriptor(table);for (String cf : colfams) {HColumnDescriptor coldef = new HColumnDescriptor(cf);desc.addFamily(coldef); }if (splitKeys != null) {admin.createTable(desc, splitKeys);} else {admin.createTable(desc); }}public void disableTable(String table) throws IOException {admin.disableTable(table);}public void dropTable(String table) throws IOException { if (existsTable(table)) { disableTable(table); admin.deleteTable(table); }}public void fillTable(String table, int startRow, int endRow, int numCols, int pad, boolean setTimestamp, boolean random, String… colfams) throws IOException { HTable tbl = new HTable(conf, table); for (int row = startRow; row <= endRow; row++) { for (int col = 0; col < numCols; col++) { Put put = new Put(Bytes.toBytes("row-")); for (String cf : colfams) { String colName = "col-"; String val = "val-"; if (setTimestamp) { put.add(Bytes.toBytes(cf), Bytes.toBytes(colName), col, Bytes.toBytes(val)); } else { put.add(Bytes.toBytes(cf), Bytes.toBytes(colName), Bytes.toBytes(val)); } } tbl.put(put); } } tbl.close(); }public void put(String table, String row, String fam, String qual, String val) throws IOException { HTable tbl = new HTable(conf, table); Put put = new Put(Bytes.toBytes(row)); put.add(Bytes.toBytes(fam), Bytes.toBytes(qual), Bytes.toBytes(val)); tbl.put(put); tbl.close(); } public void put(String table, String row, String fam, String qual, long ts, String val) throws IOException { HTable tbl = new HTable(conf, table); Put put = new Put(Bytes.toBytes(row)); put.add(Bytes.toBytes(fam), Bytes.toBytes(qual), ts, Bytes.toBytes(val)); tbl.put(put); tbl.close(); } public void put(String table, String[] rows, String[] fams, String[] quals, long[] ts, String[] vals) throws IOException { HTable tbl = new HTable(conf, table); for (String row : rows) { Put put = new Put(Bytes.toBytes(row)); for (String fam : fams) { int v = 0; for (String qual : quals) { String val = vals[v < vals.length ? v : vals.length]; long t = ts[v < ts.length ? v : ts.length – 1]; put.add(Bytes.toBytes(fam), Bytes.toBytes(qual), t, Bytes.toBytes(val)); v++; } } tbl.put(put); } tbl.close(); } public void dump(String table, String[] rows, String[] fams, String[] quals) throws IOException { HTable tbl = new HTable(conf, table); List<Get> gets = new ArrayList<Get>(); for (String row : rows) { Get get = new Get(Bytes.toBytes(row)); get.setMaxVersions(); if (fams != null) { for (String fam : fams) { for (String qual : quals) { get.addColumn(Bytes.toBytes(fam), Bytes.toBytes(qual)); } } } gets.add(get); } Result[] results = tbl.get(gets); for (Result result : results) { for (KeyValue kv : result.raw()) { System.out.println("KV: " + kv + ", Value: " + Bytes.toString(kv.getValue())); } } } private static void scan(int caching, int batch) throws IOException { HTable table = null; final int[] counters = {0, 0}; Scan scan = new Scan(); scan.setCaching(caching); // co ScanCacheBatchExample-1-Set Set caching and batch parameters. scan.setBatch(batch); ResultScanner scanner = table.getScanner(scan); for (Result result : scanner) { counters[1]++; // co ScanCacheBatchExample-2-Count Count the number of Results available. } scanner.close(); System.out.println("Caching: " + caching + ", Batch: " + batch + ", Results: " + counters[1] + ", RPCs: " + counters[0]); }}

操作表的 API 都有 HBaseAdmin 提供,特别讲解一下 Scan 的操作部署。

HBase 的表数据分为多个层次,HRegion->HStore->[HFile,HFile,…,MemStore]。

没有什么可留恋,只有抑制不住的梦想,没有什么可凭仗,

HBase 数据库检索性能优化策略

相关文章:

你感兴趣的文章:

标签云: