HBase读数据流程
- HRegionServer保存着.META.的这样一张表以及表数据,要访问表数据,首先Client先去访问zookeeper,从zookeeper里面找到.META.表所在的位置信息,即找到这个.META.表在哪个HRegionServer上保存着。
- 接着Client通过刚才获取到的HRegionServer的IP来访问.META.表所在的HRegionServer,从而读取到.META.,进而获取到.META.表中存放的元数据。
- Client通过元数据中存储的信息,访问对应的HRegionServer,然后扫描(scan)所在HRegionServer的Memstore和Storefile来查询数据。
HBase写数据流程
- Client也是先访问zookeeper,找到-ROOT-表,进而找到.META.表,并获取.META.表信息。
- 确定当前将要写入的数据所对应的RegionServer服务器和Region。
- Client向该RegionServer服务器发起写入数据请求,然后RegionServer收到请求并响应。
- Client先把数据写入到HLog,以防止数据丢失。
- 然后将数据写入到Memstore。
- 如果Hlog和Memstore均写入成功,则这条数据写入成功。在此过程中,如果Memstore达到阈值,会把Memstore中的数据flush到StoreFile中。
- 当Storefile越来越多,会触发Compact合并操作,把过多的Storefile合并成一个大的Storefile。当Storefile越来越大,Region也会越来越大,达到阈值后,会触发Split操作,将Region一分为二。
提示:因为内存空间是有限的,所以说溢写过程必定伴随着大量的小文件产生。
HBase API
首先需要获取Configuration对象:
1 | public static Configuration conf; |
2 | |
3 | static{ |
4 | //使用HBaseConfiguration的单例方法实例化 |
5 | conf = HBaseConfiguration.create(); |
6 | conf.set("hbase.zookeeper.quorum", "hadoop001"); |
7 | conf.set("hbase.zookeeper.property.clientPort", "2181"); |
8 | conf.set("zookeeper.znode.parent", "/hbase"); |
9 | } |
判断表是否存在:
1 | public static boolean isTableExist(String tableName) throws MasterNotRunningException, ZooKeeperConnectionException, IOException{ |
2 | //在HBase中管理、访问表需要先创建HBaseAdmin对象 |
3 | Connection connection = ConnectionFactory.createConnection(conf); |
4 | HBaseAdmin admin = (HBaseAdmin) connection.getAdmin(); |
5 | |
6 | //HBaseAdmin admin = new HBaseAdmin(conf); |
7 | return admin.tableExists(tableName); |
8 | } |
创建表:
1 | public static void createTable(String tableName, String... columnFamily) throws MasterNotRunningException, ZooKeeperConnectionException, IOException{ |
2 | HBaseAdmin admin = new HBaseAdmin(conf); |
3 | //判断表是否存在 |
4 | if(isTableExist(tableName)){ |
5 | System.out.println("表" + tableName + "已存在"); |
6 | //System.exit(0); |
7 | }else{ |
8 | //创建表属性对象,表名需要转字节 |
9 | HTableDescriptor descriptor = new HTableDescriptor(TableName.valueOf(tableName)); |
10 | //创建多个列族 |
11 | for(String cf : columnFamily){ |
12 | descriptor.addFamily(new HColumnDescriptor(cf)); |
13 | } |
14 | //根据对表的配置,创建表 |
15 | admin.createTable(descriptor); |
16 | System.out.println("表" + tableName + "创建成功!"); |
17 | } |
18 | } |
删除表:
1 | public static void dropTable(String tableName) throws Exception{ |
2 | HBaseAdmin admin = new HBaseAdmin(conf); |
3 | if(isTableExist(tableName)){ |
4 | admin.disableTable(tableName); |
5 | admin.deleteTable(tableName); |
6 | System.out.println("表" + tableName + "删除成功!"); |
7 | }else{ |
8 | System.out.println("表" + tableName + "不存在!"); |
9 | } |
10 | } |
向表中插入数据:
1 | public static void addRowData(String tableName, String rowKey, String columnFamily, String column, String value) throws Exception{ |
2 | //创建HTable对象 |
3 | HTable hTable = new HTable(conf, tableName); |
4 | //向表中插入数据 |
5 | Put put = new Put(Bytes.toBytes(rowKey)); |
6 | //向Put对象中组装数据 |
7 | put.add(Bytes.toBytes(columnFamily), Bytes.toBytes(column), Bytes.toBytes(value)); |
8 | hTable.put(put); |
9 | hTable.close(); |
10 | System.out.println("插入数据成功"); |
11 | } |
删除多行数据:
1 | public static void deleteMultiRow(String tableName, String... rows) throws IOException{ |
2 | HTable hTable = new HTable(conf, tableName); |
3 | List<Delete> deleteList = new ArrayList<Delete>(); |
4 | for(String row : rows){ |
5 | Delete delete = new Delete(Bytes.toBytes(row)); |
6 | deleteList.add(delete); |
7 | } |
8 | hTable.delete(deleteList); |
9 | hTable.close(); |
10 | } |
得到所有数据:
1 | public static void getAllRows(String tableName) throws IOException{ |
2 | HTable hTable = new HTable(conf, tableName); |
3 | //得到用于扫描region的对象 |
4 | Scan scan = new Scan(); |
5 | //使用HTable得到resultcanner实现类的对象 |
6 | ResultScanner resultScanner = hTable.getScanner(scan); |
7 | for(Result result : resultScanner){ |
8 | Cell[] cells = result.rawCells(); |
9 | for(Cell cell : cells){ |
10 | //得到rowkey |
11 | System.out.println("行键:" + Bytes.toString(CellUtil.cloneRow(cell))); |
12 | //得到列族 |
13 | System.out.println("列族" + Bytes.toString(CellUtil.cloneFamily(cell))); |
14 | System.out.println("列:" + Bytes.toString(CellUtil.cloneQualifier(cell))); |
15 | System.out.println("值:" + Bytes.toString(CellUtil.cloneValue(cell))); |
16 | } |
17 | } |
18 | } |
得到某一行所有数据:
1 | public static void getRow(String tableName, String rowKey) throws IOException{ |
2 | HTable table = new HTable(conf, tableName); |
3 | Get get = new Get(Bytes.toBytes(rowKey)); |
4 | //get.setMaxVersions();显示所有版本 |
5 | //get.setTimeStamp();显示指定时间戳的版本 |
6 | Result result = table.get(get); |
7 | for(Cell cell : result.rawCells()){ |
8 | System.out.println("行键:" + Bytes.toString(result.getRow())); |
9 | System.out.println("列族" + Bytes.toString(CellUtil.cloneFamily(cell))); |
10 | System.out.println("列:" + Bytes.toString(CellUtil.cloneQualifier(cell))); |
11 | System.out.println("值:" + Bytes.toString(CellUtil.cloneValue(cell))); |
12 | System.out.println("时间戳:" + cell.getTimestamp()); |
13 | } |
14 | } |
获取某一行指定列族:列
的数据:
1 | public static void getRowQualifier(String tableName, String rowKey, String family, String qualifier) throws IOException{ |
2 | HTable table = new HTable(conf, tableName); |
3 | Get get = new Get(Bytes.toBytes(rowKey)); |
4 | get.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier)); |
5 | Result result = table.get(get); |
6 | for(Cell cell : result.rawCells()){ |
7 | System.out.println("行键:" + Bytes.toString(result.getRow())); |
8 | System.out.println("列族" + Bytes.toString(CellUtil.cloneFamily(cell))); |
9 | System.out.println("列:" + Bytes.toString(CellUtil.cloneQualifier(cell))); |
10 | System.out.println("值:" + Bytes.toString(CellUtil.cloneValue(cell))); |
11 | } |
12 | } |