关于hbase
一、客户端类
HTable 和 HTablePool: (1)、HTable用于一个线程创建一个HTable;最好只创建唯一一个HTable对象;因为每次创建HTable实例都需要付出代价;检查meta.表对应的表是否存在,是否可用以及其他
的一些操作;对性能的损耗不可忽视的;同时HBase所有的修改操作都是保证行级别的原子性;
(2)、若是需要多个HTable对象,则考虑使用HTablePool类;操作同一行的记录 最好使用batch操作;以减少单独操作该行的次数
二、CRUD操作
(1)、put方法
1、void put(Put put) throws IOException;将一个put或者存储在列表中的一组put作为输入参数
注:构建Put对象
Put(byte[] row);
Put(byte[] row, RowLock rowlock);
Put(byte[] row, long ts);
Put(byte[] long ts, RowLock rowLock);
参数说明:RowKey---》row 提供唯一的行键 RowLock--》行级锁 ts---》时间戳
2、byte转换类 Bytes
static byte[] toBytes(ByteBuffer bb);
static byte[] toBytes(String s);
static byte[] toBytes(boolean b);
static byte[] toBytes(long val);
static byte[] toBytes(float f);
static byte[] toBytes(int val);
3、put的add方法
Put add(byte[] family, byte[] qualifier,byte[] value);
Put add(byte[] family,byte[] qualifier,long ts, byte[] value);
Put add(KeyValue kv) throws IOException;
可以通过行键+列族+列限定符+时间戳定位具体的内容
关于ts参数,在通过add进行数据添加时,不指定ts参数内容时,则使用构造函数的ts对应的内容;若是在
构造实例也没有指定ts参数,则有region机器指定
(1)、KeyValue = 行键+列族+列限定符+时间戳
List<KeyValue> get(byte[] family,byte[] qualifier);
Map<byte[],List<KeyValue>> getFamilyMap();
(2)、检查单元格是否存在
boolean has(byte[] family,byte[] qualifier);
boolean has(byte[] family,byte[] qualifier, long ts);
boolean has(byte[] family,byte[] qualifier,byte[] value);
boolean has(byte[] family,byte[] qualifier,long ts,byte[]);
4、HBase使用
// 1、创建所需配置
Configuration conf = HBaseConfiguration.create();
// 2、实例化客户端
HTable table = new HTable(conf,"table name");
// 3、创建put存放数据记录
// 创建row key
Put put = new Put(Bytes.toBytes("row_key"));
// 创建column family
put.add(Bytes.toBytes("colfam1"),Bytes.toBytes("qual1"));
put.add(Bytes.toBytes("colfam2"),Bytes.toBytes("qual2"));
// 4、添加记录到指定的表
table.put(put);
以上代码Configuration对应HBase的hbase-site.xml文件(默认情况下程序会从classpath下直接尝试读取
hbase-default.xml 和 hbase-site.xml)再程序获取到Configuration一般是默认+用户自定义参数合并之后的结果
5、说明
(a)、关于hbase中的时间戳
在hbase中有一个特殊的功能,同一个列单元格(特定类的值)可以存在多个版本。就是通过使用时间戳按照降序来存储的,单位为毫秒;该参数可以通过客户端api进行指定,也可以忽略
让服务器端来完成。主要根据实际情况来完成的。这样获取指定的数据时,根据执行的参数可以获取多个。默认情况下只显示最新的那个版本
(b)、RowLock类
在构造Put实例时会存在一个RowLock参数,特别在某一行记录需要频繁修改时,可以在客户端创建RowLock实例防止用户的修改该行
(c)、KeyValue类
数据和坐标都是以byte[]形式存储;目的主要是为了允许存储任意类型的数据,并有效存储所需的字节,保证最少的
内部结构开销;并且每一个字节数据组都有一个offset和length参数,允许用户提交存在的字节数据,并进行高效率的
字节操作。
KeyValue(byte[] row,int offset,int rlength, -------RowKey
byte[] family, int foffset,int flength, ----Column Family
byte[] qualifier , int qoffset,int qlength,--Qualifier Column
long timestamp,Type type, -- Version
byte[] value,int voffset, int vlength) -- Value
byte[] getRow()
byte[] getKey() 行---》行键 键---指的是单元格的坐标
三、客户端write buffer
由于每一个put操作就是RPC操作;将client数据传输到server后返回,只适合小量数据操作;因而减少RPC调用就需要限制往返时间(round-trip time);也即是
client发送一个request到server,然后server进行网络response的时间。同时消息大小也会影响rpc性能;尽量使用批量处理,减少请求次数。
(1)、开启客户端的写缓冲区
void setAutoFlush(boolean autoFlush);
boolean isAutoFlush();
默认客户端缓存区是禁用的,可以通过设定为false开启缓冲区;不过一旦开启客户端缓冲区,数据进行写入时,需要手动执行
void flushCommits() throws IOException;
同时客户端可以手动调整缓冲区;不过更多是通过hbase-site.xml
<property>
<name>hbase.client.write.buffer</name>
<value>20971520</value>
</property>
缓冲区刷写
1、显示刷写 flushCommits
2、隐式刷写 通过将当前的缓冲区大小和用户配置大小作比较;若是超出限制则会调用flushCommits方法;若是禁用则需通过setAutoFlush(true)来开启
注:close方法也会触发隐式刷写
一旦客户端关闭自动刷写;没有手动执行flushCommits那么通过put操作的内容就不会被提交到server端
ArrayList<Put> getWriteBuffer() 获取添加到缓冲区中的Put实例列表;该列表在HTable不是线程安全的;
不能在程序运行期终止程序,否则会导致尚未刷写的数据丢失,
(2)、put 列表
// 1、put list
List<Put> puts = new ArrayList<Put>();
// 2、create put
Put put1 = new Put(Bytes.toBytes("ROW1"));
put1.add(Bytes.toBytes("Column1"),Bytes.toBytes("qual1"),Bytes.toBytes("val1"));
// 3、add put to put list
puts.add(put1);
Put put2 = new Put(Bytes.toBytes("ROW2"));
put1.add(Bytes.toBytes("Column1"),Bytes.toBytes("qual1"),Bytes.toBytes("val2"));
puts.add(put2);
// 4、执行put操作
table.put(puts);
原子性操作 compare-and-set(CAS)
boolean checkAndPut(byte[] row, byte[] family, byte[] qualifier,byte[] value,Put put)
throws IOException;
五、Scan的使用
类似RDBMS的游标
(1)、创建Scan及应用
// 创建Scan
Scan scan = new Scan();
// 指定扫描范围
scan.addColumn(Bytes.toBytes("colfam1"),
Bytes.toBytes("col-5").addColumn(Bytes.toBytes("colfam1"))
Bytes.toBytes("col-33").setStartRow(Bytes.toBytes("row-11")).setStopRow(Bytes.toBytes("row-20"))
);
// 获取ResultScanner
ResultScanner scanner = table.getScanner(scan);
// 迭代变量scanner
for(Result result : scanner){
System.out.println(result);
}
// scanner关闭
scanner.close();
注:获取的内容进行匹配的时候都是按照字典顺序排序的
六、缓存与批量处理
1、设定scanner的缓存
hbase-site.xml配置
<property>
<name>hbase.client.scanner.caching</name>
<value>10</value>
</property>
程序配置
void setCaching(int caching);
int getCaching();
缓存针对的行级的操作
批量是面向列级的操作
RPC请求次数 = (行数 * 每行的列数) / Min(每行列数,批量大小) / 扫描缓存次数(额外加上打开和关闭scanner)