Hbase详解

来源:互联网 发布:归类通软件 编辑:程序博客网 时间:2024/06/05 04:26

HBase架构图理解

18.png
  1. HMaster链接Zookeeper的目得:HMaster需要知道哪些HRegionServere是活的及HRegionServer所在的位置,然后管理HRegionServer。
  2. HBase内部是通过DFS client把数据写到HDFS上的
  3. 每一个HRegionServer有多个HRegion,每一个HRegion有多个Store,每一个Store对应一个列簇。
  4. HFile是HBase中KeyValue数据的存储格式,HFile是Hadoop的二进制格式文件,StoreFile就是对HFile进行了封装,然后进行数据的存储。
  5. HStore由MemStore和StoreFile组成。
  6. HLog记录数据的所有变更,可以用来做数据恢复。
  7. hdfs对应的目录结构为namespace->table->列簇->列->单元格
    17.png

写数据流程

  1. zookeeper中存储了meta表的region信息,从meta表获取相应region信息,然后找到meta表的数据
  2. 根据namespace、表名和rowkey根据meta表的数据找到写入数据对应的region信息
  3. 找到对应的regionserver
  4. 把数据分别写到HLog和MemStore上一份
  5. MemStore达到一个阈值后则把数据刷成一个StoreFile文件。若MemStore中的数据有丢失,则可以总HLog上恢复
  6. 当多个StoreFile文件达到一定的大小后,会触发Compact合并操作,合并为一个StoreFile,这里同时进行版本的合并和数据删除。
  7. 当Compact后,逐步形成越来越大的StoreFIle后,会触发Split操作,把当前的StoreFile分成两个,这里相当于把一个大的region分割成两个region。如下图:
    19.png

读数据流程

  1. zookeeper中存储了meta表的region信息,所以先从zookeeper中找到meta表region的位置,然后读取meta表中的数据。meta中又存储了用户表的region信息。
  2. 根据namespace、表名和rowkey在meta表中找到对应的region信息
  3. 找到这个region对应的regionserver
  4. 查找对应的region
  5. 先从MemStore找数据,如果没有,再到StoreFile上读(为了读取的效率)。

HBase Java API基本使用

package com.qh.hbase;import java.io.IOException;import java.util.ArrayList;import java.util.List;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.hbase.Cell;import org.apache.hadoop.hbase.CellUtil;import org.apache.hadoop.hbase.HBaseConfiguration;import org.apache.hadoop.hbase.HColumnDescriptor;import org.apache.hadoop.hbase.HTableDescriptor;import org.apache.hadoop.hbase.TableName;import org.apache.hadoop.hbase.client.Admin;import org.apache.hadoop.hbase.client.Connection;import org.apache.hadoop.hbase.client.ConnectionFactory;import org.apache.hadoop.hbase.client.Get;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.client.Table;import org.apache.hadoop.hbase.filter.BinaryComparator;import org.apache.hadoop.hbase.filter.BinaryPrefixComparator;import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;import org.apache.hadoop.hbase.filter.FilterList;import org.apache.hadoop.hbase.filter.RegexStringComparator;import org.apache.hadoop.hbase.filter.RowFilter;import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;import org.apache.hadoop.hbase.filter.SubstringComparator;import org.apache.hadoop.hbase.util.Bytes;public class HbaseHH {/* * 连接hbase * */private static Connection connection=null;static{Configuration config=HBaseConfiguration.create();// 设置连接参数:HBase数据库所在的主机IPconfig.set("hbase.zookeeper.quorum", "192.168.64.104"); // 设置连接参数:HBase数据库使用的端口 config.set("hbase.zookeeper.property.clientPort", "2181");try {connection=ConnectionFactory.createConnection(config);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}/* * 获取表列表 * */static void List() throws IOException{Admin admin = connection.getAdmin();for(TableName tn:admin.listTableNames()){System.out.println(tn.getNameAsString());}}/** * 创建表 * @param tablename * @param familyNames * */public static boolean create(String tableName,String ...familyNames ) {try {TableName tn = TableName.valueOf(tableName);Admin admin = connection.getAdmin();if(admin.tableExists(tn)) {admin.disableTable(tn);admin.deleteTable(tn);}//创建表的描述对象HTableDescriptor htd = new HTableDescriptor(tn);for(String family:familyNames) {HColumnDescriptor hcd = new HColumnDescriptor(family);htd.addFamily(hcd);}admin.createTable(htd);admin.close();return true;} catch (IOException e) {e.printStackTrace();return false;}}/* *删除表 *@param tablename  * */public static  boolean deletetable(String tablename){TableName tName =TableName.valueOf(tablename);try {Admin admin = connection.getAdmin();admin.disableTable(tName);admin.deleteTable(tName);return true;} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();return false;}}/* *描述表 *@param tablename  * */public static void describe(String tableName) {try {Admin admin = connection.getAdmin();HTableDescriptor htd= admin.getTableDescriptor(TableName.valueOf(tableName));System.out.println("===describe "+tableName+"===");for(HColumnDescriptor hcd:htd.getColumnFamilies()) {System.out.println(hcd.getNameAsString());}System.out.println("=======================");} catch (IOException e) {e.printStackTrace();}}/* * 操作表数据 * @param tablename * @param rowkey * @param kvs * */public static boolean put(String tableName,String rowKey,String[][] kvs) {Table table = null;try {table = connection.getTable(TableName.valueOf(tableName));List<Put> lp = new ArrayList<>();for(String[] kv : kvs) {Put put = new Put(Bytes.toBytes(rowKey));put.addColumn(   Bytes.toBytes(kv[0]), Bytes.toBytes(kv[1]), Bytes.toBytes(kv[2]));lp.add(put);}table.put(lp);table.close();return true;}catch (Exception e) {return false;}}/* * 添加数据 * @param tableName * @param key * @param kvs * @throws IOException */public static void put1(String tableName,String key,String[][] kvs){Table table = null;try {table = connection.getTable(TableName.valueOf(tableName));//List<Put> lp = new ArrayList<Put>();List<Put> lp = new ArrayList<Put>();for (String[] kv : kvs) {Put put = new Put(Bytes.toBytes(key));put.addColumn(Bytes.toBytes(kv[0]),  Bytes.toBytes(kv[1]),  Bytes.toBytes(kv[2]));lp.add(put);}table.put(lp);System.out.println("添加成功");} catch (IOException e) {e.printStackTrace();}finally {if (table!=null) {try {table.close();} catch (IOException e) {e.printStackTrace();}}}}/** * 根据rowKey获取列键的值 * @param tableName * @param rowKey */public static void get(String tableName,String rowKey) {Table table = null;try {table = connection.getTable(TableName.valueOf(tableName));Get get = new Get(Bytes.toBytes(rowKey));Result result= table.get(get);for(Cell cell : result.listCells()) {String family= Bytes.toString(CellUtil.cloneFamily(cell));String qualifier= Bytes.toString(CellUtil.cloneQualifier(cell));String value = Bytes.toString(CellUtil.cloneValue(cell));System.out.println(family+"\t"+qualifier+"\t"+value);}} catch (IOException e) {e.printStackTrace();}finally {try {if(table!=null)table.close();} catch (IOException e) {e.printStackTrace();}}}/* * 扫描表 * @param tablename * */public static void scan(String tableName) {Table table = null;try {table = connection.getTable(TableName.valueOf(tableName));Scan scan = new Scan();//列值过滤器SingleColumnValueFilter scv = new SingleColumnValueFilter(Bytes.toBytes("grade"),Bytes.toBytes("class"), CompareOp.EQUAL,Bytes.toBytes("1"));//scan.setFilter(scv);//行健过滤器RowFilter rowFilter = new RowFilter(CompareOp.EQUAL,new BinaryComparator(Bytes.toBytes("a02")));//scan.setFilter(rowFilter);rowFilter = new RowFilter(CompareOp.EQUAL,new BinaryPrefixComparator("a".getBytes()));//scan.setFilter(rowFilter);rowFilter = new RowFilter(CompareOp.EQUAL,new SubstringComparator("redu"));//scan.setFilter(rowFilter);rowFilter = new RowFilter(CompareOp.EQUAL,new RegexStringComparator(".*rr"));//scan.setFilter(rowFilter);//过滤器链//FilterList.Operator.MUST_PASS_ALL :&&//FilterList.Operator.MUST_PASS_ONE:||FilterList filterList =new FilterList(FilterList.Operator.MUST_PASS_ONE);filterList.addFilter(scv);filterList.addFilter(rowFilter);scan.setFilter(filterList);//设置起止rowkey//scan.setStartRow(Bytes.toBytes("jredu001"));//scan.setStopRow(Bytes.toBytes("jredu002"));ResultScanner rs = table.getScanner(scan);for(Result result:rs) {System.out.println("******************************************");System.out.println(Bytes.toString(result.getRow()));//得到行健for(Cell cell : result.listCells()) {String family= Bytes.toString(CellUtil.cloneFamily(cell));String qualifier= Bytes.toString(CellUtil.cloneQualifier(cell));String value = Bytes.toString(CellUtil.cloneValue(cell));System.out.println(family+"\t"+qualifier+"\t"+value);}System.out.println("******************************************");}} catch (IOException e) {e.printStackTrace();}finally {try {if(table!=null)table.close();} catch (IOException e) {e.printStackTrace();}}}public static void main(String[] args) throws IOException {//boolean cr = deletetable("score");List();/*String tableName="score";String familys="subject";boolean cr = create(tableName, familys);if(cr){System.out.println("创建成功");}else{System.out.println("创建失败");}*///describe("student");// String [][] kvs ={{"grade","class","2"},{"name","name","zhang"}};//put1("student","c02rr",kvs);//get("student", "a01");scan("student");}}

HBase架构中各个模块的功能再次总结

  1. Client
    整个HBase集群的访问入口;
    使用HBase RPC机制与HMaster和HRegionServer进行通信;
    与HMaster进行通信进行管理表的操作;
    与HRegionServer进行数据读写类操作;
    包含访问HBase的接口,并维护cache来加快对HBase的访问
  2. Zookeeper
    保证任何时候,集群中只有一个HMaster;
    存贮所有HRegion的寻址入口;
    实时监控HRegion Server的上线和下线信息,并实时通知给HMaster;
    存储HBase的schema和table元数据;
    Zookeeper Quorum存储表地址、HMaster地址。
  3. HMaster
    HMaster没有单点问题,HBase中可以启动多个HMaster,通过Zookeeper的Master Election机制保证总有一个Master在运行,主负责Table和Region的管理工作。
    管理用户对表的创建、删除等操作;
    管理HRegionServer的负载均衡,调整Region分布;
    Region Split后,负责新Region的分布;
    在HRegionServer停机后,负责失效HRegionServer上Region迁移工作。
  4. HRegion Server
    维护HRegion,处理对这些HRegion的IO请求,向HDFS文件系统中读写数据;
    负责切分在运行过程中变得过大的HRegion。
    Client访问hbase上数据的过程并不需要master参与(寻址访问Zookeeper和HRegion Server,数据读写访问HRegione Server),HMaster仅仅维护这table和Region的元数据信息,负载很低。

hbase与mapreduce的集成

可以把hbase表中的数据作为mapreduce计算框架的输入,或者把mapreduce的计算结果输出到hbase表中。
我们以hbase中自带的mapreduce程序举例

  1. 直接运行会发现报错缺少jar包,所以运行前需引入环境变量
    $ export HBASE_HOME=/opt/modules/hbase-0.98.6-hadoop2 $ export HADOOP_HOME=/opt/modules/hadoop-2.5.0  # $HBASE_HOME/bin/hbase mapredcp可以列出hbase在yarn上运行所需的jar包$ export HADOOP_CLASSPATH=`$HBASE_HOME/bin/hbase mapredcp`
  2. 运行示例
    $ $HADOOP_HOME/bin/yarn jar lib/hbase-server-0.98.6-hadoop2.jar rowcounter  test:tb1

HBase的数据迁移的importsv的使用

HBase数据来源于日志文件或者RDBMS,把数据迁移到HBase表中。常见的有三种方法:(1)使用HBase Put API;(2)使用HBase批量加载工具;(3)自定义MapReduce job实现。
importtsv是HBase官方提供的基于mapreduce的批量数据导入工具,同时也是hbase提供的一个命令行工具,可以将存储在HDFS上的自定义分隔符(默认是\t)的数据文件,通过一条命令方便的导入到HBase中。
测试

  1. 准备数据文件
    [wulei@bigdata-00 datas]$ cat tb1.tsv 10001   zhangsan        2010002   lisi    2210003   wangwu  30
  2. 把数据文件上传到hdsf上
    $ bin/hdfs dfs -put /opt/datas/tb1.tsv /
  3. 在hbase中创建表
    > create 'student','info'
  4. 将HDFS中的数据导入到hbase表中
    $HADOOP_HOME/bin/yarn jar lib/hbase-server-0.98.6-hadoop2.jar importtsv  -Dimporttsv.separator=\t -Dimporttsv.columns=HBASE_ROW_KEY,info:name,info:age  student  /tb1.tsv
    Dimporttsv.columns为指定分隔符
    Dimporttsv.columns指定数据文件中每一列如何对应表中的rowkey和列
    /tb1.tsv为hdfs上的数据文件的路径
  5. 查看执行结果
    hbase(main):010:0> scan 'student'ROW                       COLUMN+CELL                                                              10001                    column=info:age, timestamp=1480123167099, value=20                       10001                    column=info:name, timestamp=1480123167099, value=zhangsan                10002                    column=info:age, timestamp=1480123167099, value=22                       10002                    column=info:name, timestamp=1480123167099, value=lisi                    2 row(s) in 0.8210 seconds


作者:心_的方向
链接:http://www.jianshu.com/p/e2bbf23f1ba2
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
原创粉丝点击