hbase(二)
一、HBase简介
1.1简介
hbase是bigtable的开源山寨版本。是建立的hdfs之上,提供高可靠性、高性能、列存储、可伸缩、实时读写的数据库系统。
它介于nosql和RDBMS之间,仅能通过主键(row key)和主键的range来检索数据,仅支持单行事务(可通过hive支持来实现多表join等复杂操作)。主要用来存储非结构化和半结构化的松散数据。与hadoop一样,Hbase目标主要依靠横向扩展,通过不断增加廉价的商用服务器,来增加计算和存储能力。
1.2 Hbase与传统数据库的对比
HBase以表的形式存储数据。表有行和列组成。列划分为若干个列族(row family)。
我们可以先来看一下传统的关系型数据库中的表:
然后与HBase的表进行对比,hbase的表结构,与传统的关系型数据库有较大的差别
我们就可以发现很多不同地方:
hbase不支持sql语句,它是一个nosql的一种,如果没有学过nosql或rubey,我们可以用help
1、定义表时不指定字段
2、定义表的时候只要指定列族名,列族数量不限
3、每一行都有一个固定的字段(行键),具有唯一性
4、对值的修改,原来的值是保留着的,每个值可以保留多个版本。默认查询的是最新版本的的值。(默认保留一个版本)
1.3 HBase中的重要概念
列族:hbase表中的每个列,都归属与某个列族。列族是表的chema的一部分(而列不是),必须在使用表之前定义。列名都以列族作为前缀。例如courses:history , courses:math 都属于 courses 这个列族。
访问控制、磁盘和内存的使用统计都是在列族层面进行的。实际应用中,列族上的控制权限能帮助我们管理不同类型的应用:我们允许一些应用可以添加新的基本数据、一些应用可以读取基本数据并创建继承的列族、一些应用则只允许浏览数据(甚至可能因 为隐私的原因不能浏览所有数据)。
时间戳:HBase中通过row和columns确定的为一个存贮单元称为cell。每个 cell都保存着同一份数据的多个版本。版本通过时间戳来索引。时间戳的类型是 64位整型。时间戳可以由hbase(在数据写入时自动 )赋值,此时时间戳是精确到毫秒的当前系统时间。时间戳也可以由客户显式赋值。如果应用程序要避免数据版本冲突,就必须自己生成具有唯一性的时间戳。每个 cell中,不同版本的数据按照时间倒序排序,即最新的数据排在最前面。
为了避免数据存在过多版本造成的的管理 (包括存贮和索引)负担,hbase提供了两种数据版本回收方式。一是保存数据的最后n个版本,二是保存最近一段时间内的版本(比如最近七天)。用户可以针对每个列族进行设置。
Cell:由{row key, column( =<family> + <label>),version} 唯一确定的单元。cell中的数据是没有类型的,全部是字节码形式存贮。
二、HBase体系结构
2、每一个region内部还要一句列族划分为若干个HStore
3、每个HStore中的数据会落地到若干个HFILE文件中
4、region体积会随着数据插入而不断增长,到一定阈值后分裂
5、随着region的分裂,一台regionserver上管理的region会越来越多
6、HMASTER会根据regionserver上管理的region数做负载均衡
7、region中的数据拥有一个内存缓存:memstore,数据的访问优先在memstore中进行
8、memstore中的数据因为空间有限,所以需要定期flush到文件storefile中,每次flush都是生成新的storefile
9、storefile的数量随着时间也会不断增加,regionserver会定期将大量storefile进行合并(merge)
行键的设计对数据查询效率的影响非常大。
hbase可以作为一个线上系统的底层系统的功能。
Hmaster可以做负载均衡,监控到各个节点之间的数据存储情况。
每一个store(列族)会有一个内存缓存,存放的是一些最热的数据(最近访问的),这样的话读取数据的速度会快很多。
文件都是有索引的,所以查起来会比较快的。
region会在storefile定期进行合并操作。
三、HBase shell的使用
create 'user-info',{NAME=>'base_info',VERSIONS=>3},{NAME=>'extra_info'} put 'user-info','rk-100001','base_info:name','huang****' put 'user-info','rk-100001','base_info:age','30' put 'user-info','rk-100001','base_info:address','Xinyang' put 'user-info','rk-100001','base_info:tel','13000000000'
scan 'user-info'
四、eclipse中使用HBase
1 // 与HBase数据库的连接对象 2 Connection conn; 3 @Before 4 public void setUp() throws Exception { 5 6 // 取得一个数据库连接的配置参数对象 7 Configuration conf = HBaseConfiguration.create(); 8 // 设置连接参数:HBase数据库所在的主机IP 9 conf.set("hbase.zookeeper.quorum", "master,node1,node2"); 10 // 设置连接参数:HBase数据库使用的端口 11 conf.set("hbase.zookeeper.property.clientPort", "2181"); 12 13 // 取得一个数据库连接对象 14 conn = ConnectionFactory.createConnection(conf); 15 } 16 17 @Test 18 public void put() throws Exception { 19 20 // 通过连接工厂创建连接对象 21 //conn = ConnectionFactory.createConnection(conf); 22 // 通过连接查询tableName对象 23 TableName tname = TableName.valueOf("ns1:t1"); 24 // 获得table 25 Table table = conn.getTable(tname); 26 27 // 通过bytes工具类创建字节数组(将字符串) 28 byte[] rowid = Bytes.toBytes("row3"); 29 30 // 创建put对象 31 Put put = new Put(rowid); 32 33 byte[] f1 = Bytes.toBytes("f1"); 34 byte[] id = Bytes.toBytes("id"); 35 byte[] value = Bytes.toBytes(102); 36 put.addColumn(f1, id, value); 37 38 // 执行插入 39 table.put(put); 40 } 41 42 @Test 43 public void bigInsert() throws Exception { 44 45 DecimalFormat format = new DecimalFormat(); 46 format.applyPattern("0000"); 47 48 long start = System.currentTimeMillis(); 49 TableName tname = TableName.valueOf("ns1:t1"); 50 HTable table = (HTable) conn.getTable(tname); 51 // 不要自动清理缓冲区 52 table.setAutoFlush(false); 53 54 for (int i = 1; i < 10000; i++) { 55 Put put = new Put(Bytes.toBytes("row" + format.format(i))); 56 // 关闭写前日志 57 put.setWriteToWAL(false); 58 put.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("id"), Bytes.toBytes(i)); 59 put.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("name"), Bytes.toBytes("tom" + i)); 60 put.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("age"), Bytes.toBytes(i % 100)); 61 table.put(put); 62 63 if (i % 2000 == 0) { 64 table.flushCommits(); 65 } 66 } 67 // 68 table.flushCommits(); 69 System.out.println(System.currentTimeMillis() - start); 70 } 71 72 /** 73 * 遍历 74 */ 75 @Test 76 public void scan() throws IOException { 77 TableName tname = TableName.valueOf("ns1:t1"); 78 Table table = conn.getTable(tname); 79 Scan scan = new Scan(); 80 scan.setStartRow(Bytes.toBytes("row5000")); 81 scan.setStopRow(Bytes.toBytes("row8000")); 82 ResultScanner rs = table.getScanner(scan); 83 Iterator<Result> it = rs.iterator(); 84 while (it.hasNext()) { 85 Result r = it.next(); 86 byte[] name = r.getValue(Bytes.toBytes("f1"), Bytes.toBytes("name")); 87 System.out.println(Bytes.toString(name)); 88 } 89 } 90 91 /** 92 * 动态遍历 93 */ 94 @Test 95 public void scan2() throws IOException { 96 //Configuration conf = HBaseConfiguration.create(); 97 //Connection conn = ConnectionFactory.createConnection(conf); 98 TableName tname = TableName.valueOf("ns1:t1"); 99 Table table = conn.getTable(tname); 100 Scan scan = new Scan(); 101 scan.setStartRow(Bytes.toBytes("row5000")); 102 scan.setStopRow(Bytes.toBytes("row8000")); 103 ResultScanner rs = table.getScanner(scan); 104 Iterator<Result> it = rs.iterator(); 105 while (it.hasNext()) { 106 Result r = it.next(); 107 Map<byte[],byte[]> map = r.getFamilyMap(Bytes.toBytes("f1")); 108 for(Map.Entry<byte[],byte[]> entrySet : map.entrySet()){ 109 String col = Bytes.toString(entrySet.getKey()); 110 String val = Bytes.toString(entrySet.getValue()); 111 System.out.print(col + ":" + val + ","); 112 } 113 114 System.out.println(); 115 } 116 }
参考:http://blog.csdn.net/sdksdk0/article/details/51680296
http://blog.csdn.net/u011308691/article/details/51476383