大数据技能之HBase(超级详细)

打印 上一主题 下一主题

主题 871|帖子 871|积分 2613

大数据技能之HBase

第1章 HBase简介

1.1 什么是HBase

HBase的原型是Google的BigTable论文,受到了该论文头脑的启发,现在作为Hadoop的子项目来开发维护,用于支持布局化的数据存储。
官方网站:http://hbase.apache.org
– 2006年Google发表BigTable白皮书
– 2006年开始开发HBase
– 2008年北京成功开奥运会,程序员冷静地将HBase弄成了Hadoop的子项目
– 2010年HBase成为Apache顶级项目
– 现在很多公司二次开发出了很多发行版本,你也开始使用了。
HBase是一个高可靠性、高性能、面向列、可伸缩的分布式存储体系,利用HBASE技能可在廉价PC Server上搭建起大规模布局化存储集群。
HBase的目标是存储并处理大型的数据,更详细来说是仅需使用普通的硬件配置,就能够处来由成千上万的行和列所组成的大型数据。
HBase是Google Bigtable的开源实现,但是也有很多不同之处。比如:Google Bigtable利用GFS作为其文件存储体系,HBase利用Hadoop HDFS作为其文件存储体系;Google运行MAPREDUCE来处理Bigtable中的海量数据,HBase同样利用Hadoop MapReduce来处理HBase中的海量数据;Google Bigtable利用Chubby作为协同服务,HBase利用Zookeeper作为对应。
1.2 HBase特点

1)海量存储
Hbase适合存储PB级别的海量数据,在PB级别的数据以及采用廉价PC存储的情况下,能在几十到百毫秒内返回数据。这与Hbase的极易扩展性息息干系。正式由于Hbase精良的扩展性,才为海量数据的存储提供了便利。
2)列式存储
这里的列式存储其实说的是列族存储,Hbase是根据列族来存储数据的。列族下面可以有非常多的列,列族在创建表的时候就必须指定。
3)极易扩展
Hbase的扩展性重要表现在两个方面,一个是基于上层处理能力(RegionServer)的扩展,一个是基于存储的扩展(HDFS)。
通过横向添加RegionSever的呆板,举行程度扩展,提升Hbase上层的处理能力,提升Hbsae服务更多Region的能力。
备注:RegionServer的作用是管理region、承接业务的访问,这个背面会详细的先容通过横向添加Datanode的呆板,举行存储层扩容,提升Hbase的数据存储能力和提升后端存储的读写能力。
4)高并发
由于现在大部分使用Hbase的架构,都是采用的廉价PC,因此单个IO的耽误其实并不小,一般在几十到上百ms之间。这里说的高并发,重要是在并发的情况下,Hbase的单个IO耽误下降并不多。能获得高并发、低耽误的服务。
5)稀疏
稀疏重要是针对Hbase列的机动性,在列族中,你可以指定任意多的列,在列数据为空的情况下,是不会占用存储空间的。

从图中可以看出Hbase是由Client、Zookeeper、Master、HRegionServer、HDFS等几个组件组成,下面来先容一下几个组件的干系功能:
1)Client
Client包含了访问Hbase的接口,另外Client还维护了对应的cache来加快Hbase的访问,比如cache的.META.元数据的信息。
2)Zookeeper
HBase通过Zookeeper来做master的高可用、RegionServer的监控、元数据的入口以及集群配置的维护等工作。详细工作如下:
通过Zoopkeeper来保证集群中只有1个master在运行,如果master异常,会通过竞争机制产生新的master提供服务
通过Zoopkeeper来监控RegionServer的状态,当RegionSevrer有异常的时候,通过回调的形式关照Master RegionServer上下线的信息
通过Zoopkeeper存储元数据的统一入口地点
3)Hmaster
master节点的重要职责如下:
为RegionServer分配Region
维护整个集群的负载均衡
维护集群的元数据信息
发现失效的Region,并将失效的Region分配到正常的RegionServer上
当RegionSever失效的时候,协调对应Hlog的拆分
4)HregionServer
HregionServer直接对接用户的读写请求,是真正的“干活”的节点。它的功能概括如下:
管理master为其分配的Region
处理来自客户端的读写请求
负责和底层HDFS的交互,存储数据到HDFS
负责Region变大以后的拆分
负责Storefile的归并工作
5)HDFS
HDFS为Hbase提供终极的底层数据存储服务,同时为HBase提供高可用(Hlog存储在HDFS)的支持,详细功能概括如下:
提供元数据和表数据的底层分布式存储服务
数据多副本,保证的高可靠和高可用性
1.3 HBase中的角色

1.3.1 HMaster

功能
1.监控RegionServer
2.处理RegionServer故障转移
3.处理元数据的变更
4.处理region的分配或转移
5.在空闲时间举行数据的负载均衡
6.通过Zookeeper发布自己的位置给客户端
1.3.2 RegionServer
功能:
1.负责存储HBase的实际数据
2.处理分配给它的Region
3.刷新缓存到HDFS
4.维护Hlog
5.实验压缩
6.负责处理Region分片
1.2.3 其他组件

1.Write-Ahead logs
HBase的修改记载,当对HBase读写数据的时候,数据不是直接写进磁盘,它会在内存中保存一段时间(时间以及数据量阈值可以设定)。但把数据生存在内存中大概有更高的概率引起数据丢失,为了办理这个标题,数据会先写在一个叫做Write-Ahead logfile的文件中,然后再写入内存中。以是在体系出现故障的时候,数据可以通过这个日志文件重修。
2.Region
Hbase表的分片,HBase表会根据RowKey值被切分成不同的region存储在RegionServer中,在一个RegionServer中可以有多个不同的region。
3.Store
HFile存储在Store中,一个Store对应HBase表中的一个列族。
4.MemStore
顾名思义,就是内存存储,位于内存中,用来生存当前的数据利用,以是当数据生存在WAL中之后,RegsionServer会在内存中存储键值对。
5.HFile
这是在磁盘上生存原始数据的实际的物理文件,是实际的存储文件。StoreFile是以Hfile的形式存储在HDFS的。
第2章 HBase安装

2.1 Zookeeper正常部署

起首保证Zookeeper集群的正常部署,并启动之:
  1. [atguigu@hadoop102 zookeeper-3.4.10]$ bin/zkServer.sh start
  2. [atguigu@hadoop103 zookeeper-3.4.10]$ bin/zkServer.sh start
  3. [atguigu@hadoop104 zookeeper-3.4.10]$ bin/zkServer.sh start
复制代码
2.2 Hadoop正常部署

Hadoop集群的正常部署并启动:
  1. [atguigu@hadoop102 hadoop-2.7.2]$ sbin/start-dfs.sh
  2. [atguigu@hadoop103 hadoop-2.7.2]$ sbin/start-yarn.sh
复制代码
2.3 HBase的解压

解压HBase到指定目录:
  1. [atguigu@hadoop102 software]$ tar -zxvf hbase-1.3.1-bin.tar.gz -C /opt/module
复制代码
2.4 HBase的配置文件

修改HBase对应的配置文件。
1)hbase-env.sh修改内容:
  1. export JAVA_HOME=/opt/module/jdk1.8.0_144
  2. export HBASE_MANAGES_ZK=false
复制代码
2)hbase-site.xml修改内容:
  1. <configuration>
  2.         <property>     
  3.                 <name>hbase.rootdir</name>     
  4.                 <value>hdfs://hadoop102:9000/hbase</value>   
  5.         </property>
复制代码
  1. <property>   
  2.         <name>hbase.cluster.distributed</name>
  3.         <value>true</value>
  4. </property>
复制代码
  1.    <!-- 0.98后的新变动,之前版本没有.port,默认端口为60000 -->
  2.         <property>
  3.                 <name>hbase.master.port</name>
  4.                 <value>16000</value>
  5.         </property>
复制代码
  1. <property>   
  2.                 <name>hbase.zookeeper.quorum</name>
  3.          <value>hadoop102:2181,hadoop103:2181,hadoop104:2181</value>
  4.         </property
复制代码
  1. <property>   
  2.                 <name>hbase.zookeeper.property.dataDir</name>
  3.              <value>/opt/module/zookeeper-3.4.10/zkData</value>
  4.         </property>
  5. </configuration>
复制代码
3)regionservers:
  1. hadoop102
  2. hadoop103
  3. hadoop104
复制代码
4)软连接hadoop配置文件到hbase:
  1. [atguigu@hadoop102 module]$ ln -s /opt/module/hadoop-2.7.2/etc/hadoop/core-site.xml
  2. /opt/module/hbase/conf/core-site.xml
复制代码
  1. [atguigu@hadoop102 module]$ ln -s /opt/module/hadoop-2.7.2/etc/hadoop/hdfs-site.xml
  2. /opt/module/hbase/conf/hdfs-site.xml
复制代码
2.5 HBase远程发送到其他集群

  1. [atguigu@hadoop102 module]$ xsync hbase/
复制代码
2.6 HBase服务的启动

1.启动方式1
  1. [atguigu@hadoop102 hbase]$ bin/hbase-daemon.sh start master
  2. [atguigu@hadoop102 hbase]$ bin/hbase-daemon.sh start regionserver
复制代码
提示:如果集群之间的节点时间不同步,会导致regionserver无法启动,抛出ClockOutOfSyncException异常。
第3章 HBase Shell利用

3.1 根本利用

1.进入HBase客户端命令行
  1. [atguigu@hadoop102 hbase]$ bin/hbase shell
复制代码
2.查察资助命令
  1. hbase(main):001:0> help
复制代码
3.查察当前数据库中有哪些表
  1. hbase(main):002:0> list
复制代码
3.2 表的利用
1.创建表
  1. hbase(main):002:0> create 'student','info'
复制代码
2.插入数据到表
  1. hbase(main):003:0> put 'student','1001','info:sex','male'
  2. hbase(main):004:0> put 'student','1001','info:age','18'
  3. hbase(main):005:0> put 'student','1002','info:name','Janna'
  4. hbase(main):006:0> put 'student','1002','info:sex','female'
  5. hbase(main):007:0> put 'student','1002','info:age','20'
复制代码
3.扫描查察表数据
  1. hbase(main):008:0> scan 'student'
复制代码
  1. hbase(main):009:0> scan 'student',{STARTROW => '1001', STOPROW  => '1001'}
复制代码
  1. hbase(main):010:0> scan 'student',{STARTROW => '1001'}
复制代码
4.查察表布局
  1. hbase(main):011:0> describe ‘student’
复制代码
5.更新指定字段的数据
  1. hbase(main):012:0> put 'student','1001','info:name','Nick'
  2. hbase(main):013:0> put 'student','1001','info:age','100'
复制代码
6.查察“指定行”或“指定列族:列”的数据
  1. hbase(main):014:0> get 'student','1001'
  2. hbase(main):015:0> get 'student','1001','info:name'
复制代码
7.统计表数据行数
  1. hbase(main):021:0> count 'student'
复制代码
8.删除数据
删除某rowkey的全部数据:
  1. hbase(main):016:0> deleteall 'student','1001'
复制代码
删除某rowkey的某一列数据:
  1. hbase(main):017:0> delete 'student','1002','info:sex'
复制代码
9.清空表数据
  1. hbase(main):018:0> truncate 'student'
复制代码
提示:清空表的利用顺序为先disable,然后再truncate。
10.删除表
起首需要先让该表为disable状态:
  1. hbase(main):019:0> disable 'student'
复制代码
然后才气drop这个表:
hbase(main):020:0> drop 'student'
提示:如果直接drop表,会报错:ERROR: Table student is enabled. Disable it first.
11.变更表信息
将info列族中的数据存放3个版本:
  1. hbase(main):022:0> alter 'student',{NAME=>'info',VERSIONS=>3}
复制代码
  1. hbase(main):022:0> get 'student','1001',{COLUMN=>'info:name',VERSIONS=>3}
复制代码
第4章 HBase数据布局

4.1 RowKey

与nosql数据库们一样,RowKey是用来检索记载的主键。访问HBASE table中的行,只有三种方式:
1.通过单个RowKey访问
2.通过RowKey的range(正则)
3.全表扫描
RowKey行键 (RowKey)可以是任意字符串(最大长度是64KB,实际应用中长度一般为 10-100bytes),在HBASE内部,RowKey生存为字节数组。存储时,数据按照RowKey的字典序(byte order)排序存储。设计RowKey时,要充分排序存储这个特性,将常常一起读取的行存储放到一起。(位置干系性)
4.2 Column Family

列族:HBASE表中的每个列,都归属于某个列族。列族是表的schema的一部 分(而列不是),必须在使用表之前界说。列名都以列族作为前缀。例如 courses:history,courses:math都属于courses 这个列族。
4.3 Cell

由{rowkey, column Family:columu, version} 唯一确定的单位。cell中的数据是没有范例的,全部是字节码形式存贮。
关键字:无范例、字节码
4.4 Time Stamp

HBASE 中通过rowkey和columns确定的为一个存贮单位称为cell。每个 cell都生存 着同一份数据的多个版本。版本通过期间戳来索引。时间戳的范例是 64位整型。时间戳可以由HBASE(在数据写入时自动 )赋值,此时时间戳是精确到毫秒 的当前体系时间。时间戳也可以由客户显式赋值。如果应用程序要避免数据版 本辩论,就必须自己天生具有唯一性的时间戳。每个 cell中,不同版本的数据按照时间倒序排序,即最新的数据排在最前面。
为了避免数据存在过多版本造成的的管理 (包括存贮和索引)负担,HBASE提供 了两种数据版本回收方式。一是生存数据的最后n个版本,二是生存最近一段 时间内的版本(比如最近七天)。用户可以针对每个列族举行设置。
4.5 命名空间

命名空间的布局:


  • Table:表,所有的表都是命名空间的成员,即表必属于某个命名空间,如果没有指定,则在default默认的命名空间中。
  • RegionServer group:一个命名空间包含了默认的RegionServer Group。
  • Permission:权限,命名空间能够让我们来界说访问控制列表ACL(Access Control List)。例如,创建表,读取表,删除,更新等等利用。
  • Quota:限额,可以逼迫一个命名空间可包含的region的数量。
第5章 HBase原理

5.1 读流程

HBase读数据流程如图3所示

1)Client先访问zookeeper,从meta表读取region的位置,然后读取meta表中的数据。meta中又存储了用户表的region信息;
2)根据namespace、表名和rowkey在meta表中找到对应的region信息;
3)找到这个region对应的regionserver;
4)查找对应的region;
5)先从MemStore找数据,如果没有,再到BlockCache内里读;
6)BlockCache还没有,再到StoreFile上读(为了读取的效率);
7)如果是从StoreFile内里读取的数据,不是直接返回给客户端,而是先写入BlockCache,再返回给客户端。
5.2 写流程

Hbase写流程如图2所示

1)Client向HregionServer发送写请求;
2)HregionServer将数据写到HLog(write ahead log)。为了数据的持久化和恢复;
3)HregionServer将数据写到内存(MemStore);
4)反馈Client写成功。
5.3 数据Flush过程
1)当MemStore数据到达阈值(默认是128M,老版本是64M),将数据刷到硬盘,将内存中的数据删除,同时删除HLog中的历史数据;
2)并将数据存储到HDFS中;
3)在HLog中做标记点。
5.4 数据归并过程
1)当数据块到达4块,Hmaster触发归并利用,Region将数据块加载到当地,举行归并;
2)当归并的数据凌驾256M,举行拆分,将拆分后的Region分配给不同的HregionServer管理;
3)当HregionServer宕机后,将HregionServer上的hlog拆分,然后分配给不同的HregionServer加载,修改.META.;
4)注意:HLog会同步到HDFS。
第6章 HBase API利用

6.1 情况准备

新建项目后在pom.xml中添加依赖:
  1. <dependency>
  2.     <groupId>org.apache.hbase</groupId>
  3.     <artifactId>hbase-server</artifactId>
  4.     <version>1.3.1</version>
  5. </dependency>
  6. <dependency>
  7.     <groupId>org.apache.hbase</groupId>
  8.     <artifactId>hbase-client</artifactId>
  9.     <version>1.3.1</version>
  10. </dependency>
  11. <dependency>
  12.         <groupId>jdk.tools</groupId>
  13.         <artifactId>jdk.tools</artifactId>
  14.         <version>1.8</version>
  15.         <scope>system</scope>
  16.         <systemPath>${JAVA_HOME}/lib/tools.jar</systemPath>
  17. </dependency>
复制代码
6.2 HBaseAPI

6.2.1 获取Configuration对象

  1. public static Configuration conf;
  2. static{
  3.         //使用HBaseConfiguration的单例方法实例化
  4.         conf = HBaseConfiguration.create();
  5. conf.set("hbase.zookeeper.quorum", "192.168.9.102");
  6. conf.set("hbase.zookeeper.property.clientPort", "2181");
  7. }
复制代码
6.2.2 判定表是否存在

  1. public static boolean isTableExist(String tableName) throws MasterNotRunningException,
  2. ZooKeeperConnectionException, IOException{
  3.         //在HBase中管理、访问表需要先创建HBaseAdmin对象
  4. //Connection connection = ConnectionFactory.createConnection(conf);
  5. //HBaseAdmin admin = (HBaseAdmin) connection.getAdmin();
  6.         HBaseAdmin admin = new HBaseAdmin(conf);
  7.         return admin.tableExists(tableName);
  8. }
  9. 6.2.3 创建表
  10. public static void createTable(String tableName, String... columnFamily) throws
  11. MasterNotRunningException, ZooKeeperConnectionException, IOException{
  12.         HBaseAdmin admin = new HBaseAdmin(conf);
  13.         //判断表是否存在
  14.         if(isTableExist(tableName)){
  15.                 System.out.println("表" + tableName + "已存在");
  16.                 //System.exit(0);
  17.         }else{
  18.                 //创建表属性对象,表名需要转字节
  19.                 HTableDescriptor descriptor = new HTableDescriptor(TableName.valueOf(tableName));
  20.                 //创建多个列族
  21.                 for(String cf : columnFamily){
  22.                         descriptor.addFamily(new HColumnDescriptor(cf));
  23.                 }
  24.                 //根据对表的配置,创建表
  25.                 admin.createTable(descriptor);
  26.                 System.out.println("表" + tableName + "创建成功!");
  27.         }
  28. }
复制代码
6.2.4 删除表

  1. public static void dropTable(String tableName) throws MasterNotRunningException,
  2. ZooKeeperConnectionException, IOException{
  3.         HBaseAdmin admin = new HBaseAdmin(conf);
  4.         if(isTableExist(tableName)){
  5.                 admin.disableTable(tableName);
  6.                 admin.deleteTable(tableName);
  7.                 System.out.println("表" + tableName + "删除成功!");
  8.         }else{
  9.                 System.out.println("表" + tableName + "不存在!");
  10.         }
  11. }
复制代码
6.2.5 向表中插入数据

  1. public static void addRowData(String tableName, String rowKey, String columnFamily, String
  2. column, String value) throws IOException{
  3.         //创建HTable对象
  4.         HTable hTable = new HTable(conf, tableName);
  5.         //向表中插入数据
  6.         Put put = new Put(Bytes.toBytes(rowKey));
  7.         //向Put对象中组装数据
  8.         put.add(Bytes.toBytes(columnFamily), Bytes.toBytes(column), Bytes.toBytes(value));
  9.         hTable.put(put);
  10.         hTable.close();
  11.         System.out.println("插入数据成功");
  12. }
复制代码
6.2.6 删除多行数据

  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. }
复制代码
6.2.7 获取所有数据

  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. }
复制代码
6.2.8 获取某一行数据

  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. }
复制代码
6.2.9 获取某一行指定“列族:列”的数据

  1. public static void getRowQualifier(String tableName, String rowKey, String family, String
  2. qualifier) throws IOException{
  3.         HTable table = new HTable(conf, tableName);
  4.         Get get = new Get(Bytes.toBytes(rowKey));
  5.         get.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));
  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.         }
  13. }
复制代码
6.3 MapReduce

通过HBase的干系JavaAPI,我们可以实现伴随HBase利用的MapReduce过程,比如使用MapReduce将数据从当地文件体系导入到HBase的表中,比如我们从HBase中读取一些原始数据后使用MapReduce做数据分析。
6.3.1 官方HBase-MapReduce

1.查察HBase的MapReduce任务的实验
  1. $ bin/hbase mapredcp
复制代码
2.情况变量的导入
(1)实验情况变量的导入(暂时生效,在命令行实验下述利用)
  1. $ export HBASE_HOME=/opt/module/hbase-1.3.1
  2. $ export HADOOP_HOME=/opt/module/hadoop-2.7.2
  3. $ export HADOOP_CLASSPATH=`${HBASE_HOME}/bin/hbase mapredcp`
复制代码
(2)永久生效:在/etc/profile配置
  1. export HBASE_HOME=/opt/module/hbase-1.3.1
  2. export HADOOP_HOME=/opt/module/hadoop-2.7.2
复制代码
并在hadoop-env.sh中配置:(注意:在for循环之后配)
  1. export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:/opt/module/hbase/lib/*
复制代码
3.运行官方的MapReduce任务
– 案例一:统计Student表中有多少行数据
  1. $ /opt/module/hadoop-2.7.2/bin/yarn jar lib/hbase-server-1.3.1.jar rowcounter student
复制代码
– 案例二:使用MapReduce将当地数据导入到HBase
1)在当地创建一个tsv格式的文件:fruit.tsv
  1. 1001        Apple        Red
  2. 1002        Pear                Yellow
  3. 1003        Pineapple        Yellow
复制代码
2)创建HBase表
  1. hbase(main):001:0> create 'fruit','info'
复制代码
3)在HDFS中创建input_fruit文件夹并上传fruit.tsv文件
  1. $ /opt/module/hadoop-2.7.2/bin/hdfs dfs -mkdir /input_fruit/
复制代码
  1. $ /opt/module/hadoop-2.7.2/bin/hdfs dfs -put fruit.tsv /input_fruit/
复制代码
4)实验MapReduce到HBase的fruit表中
  1. $ /opt/module/hadoop-2.7.2/bin/yarn jar lib/hbase-server-1.3.1.jar importtsv \
  2. -Dimporttsv.columns=HBASE_ROW_KEY,info:name,info:color fruit \
  3. hdfs://hadoop102:9000/input_fruit
复制代码
5)使用scan命令查察导入后的结果
  1. hbase(main):001:0> scan ‘fruit’
复制代码
6.3.2 自界说HBase-MapReduce1

目标:将fruit表中的一部分数据,通过MR迁入到fruit_mr表中。
分步实现:
1.构建ReadFruitMapper类,用于读取fruit表中的数据
  1. package com.atguigu;
  2. import java.io.IOException;
  3. import org.apache.hadoop.hbase.Cell;
  4. import org.apache.hadoop.hbase.CellUtil;
  5. import org.apache.hadoop.hbase.client.Put;
  6. import org.apache.hadoop.hbase.client.Result;
  7. import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
  8. import org.apache.hadoop.hbase.mapreduce.TableMapper;
  9. import org.apache.hadoop.hbase.util.Bytes;
  10. public class ReadFruitMapper extends TableMapper<ImmutableBytesWritable, Put> {
  11.         @Override
  12.         protected void map(ImmutableBytesWritable key, Result value, Context context)
  13.         throws IOException, InterruptedException {
  14.         //将fruit的name和color提取出来,相当于将每一行数据读取出来放入到Put对象中。
  15.                 Put put = new Put(key.get());
  16.                 //遍历添加column行
  17.                 for(Cell cell: value.rawCells()){
  18.                         //添加/克隆列族:info
  19.                         if("info".equals(Bytes.toString(CellUtil.cloneFamily(cell)))){
  20.                                 //添加/克隆列:name
  21.                                 if("name".equals(Bytes.toString(CellUtil.cloneQualifier(cell)))){
  22.                                         //将该列cell加入到put对象中
  23.                                         put.add(cell);
  24.                                         //添加/克隆列:color
  25.                                 }else if("color".equals(Bytes.toString(CellUtil.cloneQualifier(cell)))){
  26.                                         //向该列cell加入到put对象中
  27.                                         put.add(cell);
  28.                                 }
  29.                         }
  30.                 }
  31.                 //将从fruit读取到的每行数据写入到context中作为map的输出
  32.                 context.write(key, put);
  33.         }
  34. }
复制代码
2. 构建WriteFruitMRReducer类,用于将读取到的fruit表中的数据写入到fruit_mr表中
  1. package com.atguigu.hbase_mr;
  2. import java.io.IOException;
  3. import org.apache.hadoop.hbase.client.Put;
  4. import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
  5. import org.apache.hadoop.hbase.mapreduce.TableReducer;
  6. import org.apache.hadoop.io.NullWritable;
  7. public class WriteFruitMRReducer extends TableReducer<ImmutableBytesWritable, Put, NullWritable> {
  8.         @Override
  9.         protected void reduce(ImmutableBytesWritable key, Iterable<Put> values, Context context)
  10.         throws IOException, InterruptedException {
  11.                 //读出来的每一行数据写入到fruit_mr表中
  12.                 for(Put put: values){
  13.                         context.write(NullWritable.get(), put);
  14.                 }
  15.         }
  16. }
复制代码
3.构建Fruit2FruitMRRunner extends Configured implements Tool用于组装运行Job任务
  1. //组装Job
  2.         public int run(String[] args) throws Exception {
  3.                 //得到Configuration
  4.                 Configuration conf = this.getConf();
  5.                 //创建Job任务
  6.                 Job job = Job.getInstance(conf, this.getClass().getSimpleName());
  7.                 job.setJarByClass(Fruit2FruitMRRunner.class);
  8.                 //配置Job
  9.                 Scan scan = new Scan();
  10.                 scan.setCacheBlocks(false);
  11.                 scan.setCaching(500);
  12.                 //设置Mapper,注意导入的是mapreduce包下的,不是mapred包下的,后者是老版本
  13.                 TableMapReduceUtil.initTableMapperJob(
  14.                 "fruit", //数据源的表名
  15.                 scan, //scan扫描控制器
  16.                 ReadFruitMapper.class,//设置Mapper类
  17.                 ImmutableBytesWritable.class,//设置Mapper输出key类型
  18.                 Put.class,//设置Mapper输出value值类型
  19.                 job//设置给哪个JOB
  20.                 );
  21.                 //设置Reducer
  22.                 TableMapReduceUtil.initTableReducerJob("fruit_mr", WriteFruitMRReducer.class, job);
  23.                 //设置Reduce数量,最少1个
  24.                 job.setNumReduceTasks(1);
  25.                 boolean isSuccess = job.waitForCompletion(true);
  26.                 if(!isSuccess){
  27.                         throw new IOException("Job running with error");
  28.                 }
  29.                 return isSuccess ? 0 : 1;
  30.         }
复制代码
4.主函数中调用运行该Job任务
  1. public static void main( String[] args ) throws Exception{
  2. Configuration conf = HBaseConfiguration.create();
  3. int status = ToolRunner.run(conf, new Fruit2FruitMRRunner(), args);
  4. System.exit(status);
  5. }
复制代码
5.打包运利用命
  1. $ /opt/module/hadoop-2.7.2/bin/yarn jar ~/softwares/jars/hbase-0.0.1-SNAPSHOT.jar
  2. com.z.hbase.mr1.Fruit2FruitMRRunner
复制代码
提示:运利用命前,如果待数据导入的表不存在,则需要提前创建。
提示:maven打包命令:-P local clean package或-P dev clean package install(将第三方jar包一同打包,需要插件:maven-shade-plugin)
6.3.3 自界说HBase-MapReduce2

目标:实现将HDFS中的数据写入到HBase表中。
分步实现:
1.构建ReadFruitFromHDFSMapper于读取HDFS中的文件数据
  1. package com.atguigu;
  2. import java.io.IOException;
  3. import org.apache.hadoop.hbase.client.Put;
  4. import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
  5. import org.apache.hadoop.hbase.util.Bytes;
  6. import org.apache.hadoop.io.LongWritable;
  7. import org.apache.hadoop.io.Text;
  8. import org.apache.hadoop.mapreduce.Mapper;
  9. public class ReadFruitFromHDFSMapper extends Mapper<LongWritable, Text, ImmutableBytesWritable, Put> {
  10.         @Override
  11.         protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
  12.                 //从HDFS中读取的数据
  13.                 String lineValue = value.toString();
  14.                 //读取出来的每行数据使用\t进行分割,存于String数组
  15.                 String[] values = lineValue.split("\t");
  16.                
  17.                 //根据数据中值的含义取值
  18.                 String rowKey = values[0];
  19.                 String name = values[1];
  20.                 String color = values[2];
  21.                
  22.                 //初始化rowKey
  23.                 ImmutableBytesWritable rowKeyWritable = new ImmutableBytesWritable(Bytes.toBytes(rowKey));
  24.                
  25.                 //初始化put对象
  26.                 Put put = new Put(Bytes.toBytes(rowKey));
  27.                
  28.                 //参数分别:列族、列、值  
  29.         put.add(Bytes.toBytes("info"), Bytes.toBytes("name"),  Bytes.toBytes(name));
  30.         put.add(Bytes.toBytes("info"), Bytes.toBytes("color"),  Bytes.toBytes(color));
  31.         
  32.         context.write(rowKeyWritable, put);
  33.         }
  34. }
复制代码
2.构建WriteFruitMRFromTxtReducer类
  1. package com.z.hbase.mr2;
  2. import java.io.IOException;
  3. import org.apache.hadoop.hbase.client.Put;
  4. import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
  5. import org.apache.hadoop.hbase.mapreduce.TableReducer;
  6. import org.apache.hadoop.io.NullWritable;
  7. public class WriteFruitMRFromTxtReducer extends TableReducer<ImmutableBytesWritable, Put, NullWritable> {
  8.         @Override
  9.         protected void reduce(ImmutableBytesWritable key, Iterable<Put> values, Context context) throws IOException, InterruptedException {
  10.                 //读出来的每一行数据写入到fruit_hdfs表中
  11.                 for(Put put: values){
  12.                         context.write(NullWritable.get(), put);
  13.                 }
  14.         }
  15. }
复制代码
3.创建Txt2FruitRunner组装Job
  1. public int run(String[] args) throws Exception {
  2. //得到Configuration
  3. Configuration conf = this.getConf();
  4. //创建Job任务
  5. Job job = Job.getInstance(conf, this.getClass().getSimpleName());
  6. job.setJarByClass(Txt2FruitRunner.class);
  7. Path inPath = new Path("hdfs://hadoop102:9000/input_fruit/fruit.tsv");
  8. FileInputFormat.addInputPath(job, inPath);
  9. //设置Mapper
  10. job.setMapperClass(ReadFruitFromHDFSMapper.class);
  11. job.setMapOutputKeyClass(ImmutableBytesWritable.class);
  12. job.setMapOutputValueClass(Put.class);
  13. //设置Reducer
  14. TableMapReduceUtil.initTableReducerJob("fruit_mr", WriteFruitMRFromTxtReducer.class, job);
  15. //设置Reduce数量,最少1个
  16. job.setNumReduceTasks(1);
  17. boolean isSuccess = job.waitForCompletion(true);
  18. if(!isSuccess){
  19. throw new IOException("Job running with error");
  20. }
  21. return isSuccess ? 0 : 1;
  22. }
复制代码
4.调用实验Job
  1. public static void main(String[] args) throws Exception {
  2.                 Configuration conf = HBaseConfiguration.create();
  3.             int status = ToolRunner.run(conf, new Txt2FruitRunner(), args);
  4.             System.exit(status);
  5. }
复制代码
5.打包运行
  1. $ /opt/module/hadoop-2.7.2/bin/yarn jar hbase-0.0.1-SNAPSHOT.jar com.atguigu.hbase.mr2.Txt2FruitRunner
复制代码
提示:运利用命前,如果待数据导入的表不存在,则需要提前创建之。
提示:maven打包命令:-P local clean package或-P dev clean package install(将第三方jar包一同打包,需要插件:maven-shade-plugin)
6.4 与Hive的集成

6.4.1 HBase与Hive的对比

1.Hive
(1) 数据堆栈
Hive的本质其实就相当于将HDFS中已经存储的文件在Mysql中做了一个双射关系,以方便使用HQL去管理查询。
(2) 用于数据分析、清洗
Hive适用于离线的数据分析和清洗,耽误较高。
(3) 基于HDFS、MapReduce
Hive存储的数据仍然在DataNode上,编写的HQL语句终将是转换为MapReduce代码实验。
2.HBase
(1) 数据库
是一种面向列存储的非关系型数据库。
(2) 用于存储布局化和非布局化的数据
适用于单表非关系型数据的存储,不适合做关联查询,雷同JOIN等利用。
(3) 基于HDFS
数据持久化存储的表现形式是Hfile,存放于DataNode中,被ResionServer以region的形式举行管理。
(4) 耽误较低,接入在线业务使用
面临大量的企业数据,HBase可以直线单表大量数据的存储,同时提供了高效的数据访问速度。
6.4.2 HBase与Hive集成使用

尖叫提示:HBase与Hive的集成在最新的两个版本中无法兼容。以是,我们只能含着泪大胆的重新编译:hive-hbase-handler-1.2.2.jar!!好气!!
情况准备
由于我们后续大概会在利用Hive的同时对HBase也会产生影响,以是Hive需要持有利用HBase的Jar,那么接下来拷贝Hive所依赖的Jar包(或者使用软连接的形式)。
  1. export HBASE_HOME=/opt/module/hbase
  2. export HIVE_HOME=/opt/module/hive
复制代码
  1. ln -s $HBASE_HOME/lib/hbase-common-1.3.1.jar  $HIVE_HOME/lib/hbase-common-1.3.1.jar
  2. ln -s $HBASE_HOME/lib/hbase-server-1.3.1.jar $HIVE_HOME/lib/hbase-server-1.3.1.jar
  3. ln -s $HBASE_HOME/lib/hbase-client-1.3.1.jar $HIVE_HOME/lib/hbase-client-1.3.1.jar
  4. ln -s $HBASE_HOME/lib/hbase-protocol-1.3.1.jar $HIVE_HOME/lib/hbase-protocol-1.3.1.jar
  5. ln -s $HBASE_HOME/lib/hbase-it-1.3.1.jar $HIVE_HOME/lib/hbase-it-1.3.1.jar
  6. ln -s $HBASE_HOME/lib/htrace-core-3.1.0-incubating.jar $HIVE_HOME/lib/htrace-core-3.1.0-incubating.jar
  7. ln -s $HBASE_HOME/lib/hbase-hadoop2-compat-1.3.1.jar $HIVE_HOME/lib/hbase-hadoop2-compat-1.3.1.jar
  8. ln -s $HBASE_HOME/lib/hbase-hadoop-compat-1.3.1.jar $HIVE_HOME/lib/hbase-hadoop-compat-1.3.1.jar
复制代码
同时在hive-site.xml中修改zookeeper的属性,如下:
  1. <property>
  2.   <name>hive.zookeeper.quorum</name>
  3.   <value>hadoop102,hadoop103,hadoop104</value>
  4.   <description>The list of ZooKeeper servers to talk to. This is only needed for read/write locks.</description>
  5. </property>
  6. <property>
  7.   <name>hive.zookeeper.client.port</name>
  8.   <value>2181</value>
  9.   <description>The port of ZooKeeper servers to talk to. This is only needed for read/write locks.</description>
  10. </property>
复制代码
1.案例一
目标:建立Hive表,关联HBase表,插入数据到Hive表的同时能够影响HBase表。
分步实现:
(1) 在Hive中创建表同时关联HBase
  1. CREATE TABLE hive_hbase_emp_table(
  2. empno int,
  3. ename string,
  4. job string,
  5. mgr int,
  6. hiredate string,
  7. sal double,
  8. comm double,
  9. deptno int)
  10. STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
  11. WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:comm,info:deptno")
  12. TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");
复制代码
提示:完成之后,可以分别进入Hive和HBase查察,都天生了对应的表
(2) 在Hive中创建暂时中间表,用于load文件中的数据
提示:不能将数据直接load进Hive所关联HBase的那张表中
  1. CREATE TABLE emp(
  2. empno int,
  3. ename string,
  4. job string,
  5. mgr int,
  6. hiredate string,
  7. sal double,
  8. comm double,
  9. deptno int)
  10. row format delimited fields terminated by '\t';
复制代码
(3) 向Hive中间表中load数据
  1. hive> load data local inpath '/home/admin/softwares/data/emp.txt' into table emp;
复制代码
(4) 通过insert命令将中间表中的数据导入到Hive关联HBase的那张表中
  1. hive> insert into table hive_hbase_emp_table select * from emp;
复制代码
(5) 查察Hive以及关联的HBase表中是否已经成功的同步插入了数据
Hive:
  1. hive> select * from hive_hbase_emp_table;
复制代码
HBase:
  1. hbase> scan ‘hbase_emp_table’
复制代码
2.案例二
目标:在HBase中已经存储了某一张表hbase_emp_table,然后在Hive中创建一个外部表来关联HBase中的hbase_emp_table这张表,使之可以借助Hive来分析HBase这张表中的数据。
注:该案例2紧跟案例1的脚步,以是完成此案例前,请先完成案例1。
分步实现:
(1) 在Hive中创建外部表
  1. CREATE EXTERNAL TABLE relevance_hbase_emp(
  2. empno int,
  3. ename string,
  4. job string,
  5. mgr int,
  6. hiredate string,
  7. sal double,
  8. comm double,
  9. deptno int)
  10. STORED BY
  11. 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
  12. WITH SERDEPROPERTIES ("hbase.columns.mapping" =
  13. ":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:comm,info:deptno")
  14. TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");
复制代码
(2) 关联后就可以使用Hive函数举行一些分析利用了
  1. hive (default)> select * from relevance_hbase_emp;
复制代码
第7章 HBase优化

7.1 高可用

在HBase中Hmaster负责监控RegionServer的生命周期,均衡RegionServer的负载,如果Hmaster挂掉了,那么整个HBase集群将陷入不康健的状态,并且此时的工作状态并不会维持太久。以是HBase支持对Hmaster的高可用配置。
1.关闭HBase集群(如果没有开启则跳过此步)
  1. [atguigu@hadoop102 hbase]$ bin/stop-hbase.sh
复制代码
2.在conf目录下创建backup-masters文件
  1. [atguigu@hadoop102 hbase]$ touch conf/backup-masters
复制代码
3.在backup-masters文件中配置高可用HMaster节点
  1. [atguigu@hadoop102 hbase]$ echo hadoop103 > conf/backup-masters
复制代码
4.将整个conf目录scp到其他节点
  1. [atguigu@hadoop102 hbase]$ scp -r conf/ hadoop103:/opt/module/hbase/
复制代码
  1. [atguigu@hadoop102 hbase]$ scp -r conf/ hadoop104:/opt/module/hbase/
复制代码
5.打开页面测试查察
  1. http://hadooo102:16010
复制代码
7.2 预分区

每一个region维护着startRow与endRowKey,如果参加的数据符合某个region维护的rowKey范围,则该数据交给这个region维护。那么依照这个原则,我们可以将数据所要投放的分区提前大致的规划好,以提高HBase性能。
1.手动设定预分区
  1. hbase> create 'staff1','info','partition1',SPLITS => ['1000','2000','3000','4000']
复制代码
2.天生16进制序列预分区
  1. create 'staff2','info','partition2',{NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}
复制代码
3.按照文件中设置的规则预分区
创建splits.txt文件内容如下:
  1. aaaa
  2. bbbb
  3. cccc
  4. dddd
复制代码
然后实验:
  1. create 'staff3','partition3',SPLITS_FILE => 'splits.txt'
复制代码
4.使用JavaAPI创建预分区
//自界说算法,产生一系列Hash散列值存储在二维数组中
byte[][] splitKeys = 某个散列值函数
//创建HBaseAdmin实例
HBaseAdmin hAdmin = new HBaseAdmin(HBaseConfiguration.create());
//创建HTableDescriptor实例
HTableDescriptor tableDesc = new HTableDescriptor(tableName);
//通过HTableDescriptor实例和散列值二维数组创建带有预分区的HBase表
hAdmin.createTable(tableDesc, splitKeys);
7.3 RowKey设计

一条数据的唯一标识就是rowkey,那么这条数据存储于哪个分区,取决于rowkey处于哪个一个预分区的区间内,设计rowkey的重要目标 ,就是让数据匀称的分布于所有的region中,在一定程度上防止数据倾斜。接下来我们就谈一谈rowkey常用的设计方案。
1.天生随机数、hash、散列值
比如:
本来rowKey为1001的,SHA1后酿成:dd01903921ea24941c26a48f2cec24e0bb0e8cc7
本来rowKey为3001的,SHA1后酿成:49042c54de64a1e9bf0b33e00245660ef92dc7bd
本来rowKey为5001的,SHA1后酿成:7b61dec07e02c188790670af43e717f0f46e8913
在做此利用之前,一般我们会选择从数据集中抽取样本,来决定什么样的rowKey来Hash后作为每个分区的临界值。
2.字符串反转
20170524000001转成10000042507102
20170524000002转成20000042507102
如许也可以在一定程度上散列逐步put进来的数据。
3.字符串拼接
20170524000001_a12e
20170524000001_93i7
7.4 内存优化

HBase利用过程中需要大量的内存开销,毕竟Table是可以缓存在内存中的,一般会分配整个可用内存的70%给HBase的Java堆。但是不建议分配非常大的堆内存,由于GC过程持续太久会导致RegionServer处于长期不可用状态,一般16~48G内存就可以了,如果由于框架占用内存过高导致体系内存不足,框架一样会被体系服务拖死。
7.5 底子优化

1.答应在HDFS的文件中追加内容
hdfs-site.xml、hbase-site.xml
属性:dfs.support.append
表明:开启HDFS追加同步,可以优秀的共同HBase的数据同步和持久化。默认值为true。
2.优化DataNode答应的最大文件打开数
hdfs-site.xml
属性:dfs.datanode.max.transfer.threads
表明:HBase一般都会同一时间利用大量的文件,根据集群的数量和规模以及数据动作,设置为4096或者更高。默认值:4096
3.优化耽误高的数据利用的期待时间
hdfs-site.xml
属性:dfs.image.transfer.timeout
表明:如果对于某一次数据利用来讲,耽误非常高,socket需要期待更长的时间,建议把该值设置为更大的值(默认60000毫秒),以确保socket不会被timeout掉。
4.优化数据的写入效率
mapred-site.xml
属性:
mapreduce.map.output.compress
mapreduce.map.output.compress.codec
表明:开启这两个数据可以大大提高文件的写入效率,淘汰写入时间。第一个属性值修改为true,第二个属性值修改为:org.apache.hadoop.io.compress.GzipCodec或者其他压缩方式。
5.设置RPC监听数量
hbase-site.xml
属性:hbase.regionserver.handler.count
表明:默认值为30,用于指定RPC监听的数量,可以根据客户端的请求数举行调整,读写请求较多时,增加此值。
6.优化HStore文件巨细
hbase-site.xml
属性:hbase.hregion.max.filesize
表明:默认值10737418240(10GB),如果需要运行HBase的MR任务,可以减小此值,由于一个region对应一个map任务,如果单个region过大,会导致map任务实验时间过长。该值的意思就是,如果HFile的巨细到达这个数值,则这个region会被切分为两个Hfile。
7.优化hbase客户端缓存
hbase-site.xml
属性:hbase.client.write.buffer
表明:用于指定HBase客户端缓存,增大该值可以淘汰RPC调用次数,但是会斲丧更多内存,反之则反之。一般我们需要设定一定的缓存巨细,以到达淘汰RPC次数的目标。
8.指定scan.next扫描HBase所获取的行数
hbase-site.xml
属性:hbase.client.scanner.caching
表明:用于指定scan.next方法获取的默认行数,值越大,斲丧内存越大。
9.flush、compact、split机制
当MemStore到达阈值,将Memstore中的数据Flush进Storefile;compact机制则是把flush出来的小文件归并成大的Storefile文件。split则是当Region到达阈值,会把过大的Region一分为二。
涉及属性:
即:128M就是Memstore的默认阈值
hbase.hregion.memstore.flush.size:134217728
即:这个参数的作用是当单个HRegion内所有的Memstore巨细总和凌驾指定值时,flush该HRegion的所有memstore。RegionServer的flush是通过将请求添加一个队列,模仿生产消费模型来异步处理的。那这里就有一个标题,当队列来不及消费,产生大量积压请求时,大概会导致内存陡增,最坏的情况是触发OOM。
hbase.regionserver.global.memstore.upperLimit:0.4
hbase.regionserver.global.memstore.lowerLimit:0.38
即:当MemStore使用内存总量到达hbase.regionserver.global.memstore.upperLimit指定值时,将会有多个MemStores flush到文件中,MemStore flush 顺序是按照巨细降序实验的,直到刷新到MemStore使用内存略小于lowerLimit
第8章 HBase实战之谷粒微博

8.1 需求分析


  • 微博内容的浏览,数据库表设计
  • 用户社交表现:关注用户,取关用户
  • 拉取关注的人的微博内容
    8.2 代码实现
    8.2.1 代码设计总览:
  • 创建命名空间以及表名的界说
  • 创建微博内容表
  • 创建用户关系表
  • 创建用户微博内容接收邮件表
  • 发布微博内容
  • 添加关注用户
  • 移除(取关)用户
  • 获取关注的人的微博内容
  • 测试
8.2.2 创建命名空间以及表名的界说

  1. //获取配置conf
  2. private Configuration conf = HBaseConfiguration.create();
  3. //微博内容表的表名
  4. private static final byte[] TABLE_CONTENT = Bytes.toBytes("weibo:content");
  5. //用户关系表的表名
  6. private static final byte[] TABLE_RELATIONS = Bytes.toBytes("weibo:relations");
  7. //微博收件箱表的表名
  8. private static final byte[] TABLE_RECEIVE_CONTENT_EMAIL = Bytes.toBytes("weibo:receive_content_email");
  9. public void initNamespace(){
  10.         HBaseAdmin admin = null;
  11.         try {
  12.                 admin = new HBaseAdmin(conf);
  13.                 //命名空间类似于关系型数据库中的schema,可以想象成文件夹
  14.                 NamespaceDescriptor weibo = NamespaceDescriptor
  15.                                 .create("weibo")
  16.                                 .addConfiguration("creator", "Jinji")
  17.                                 .addConfiguration("create_time", System.currentTimeMillis() + "")
  18.                                 .build();
  19.                 admin.createNamespace(weibo);
  20.         } catch (MasterNotRunningException e) {
  21.                 e.printStackTrace();
  22.         } catch (ZooKeeperConnectionException e) {
  23.                 e.printStackTrace();
  24.         } catch (IOException e) {
  25.                 e.printStackTrace();
  26.         }finally{
  27.                 if(null != admin){
  28.                         try {
  29.                                 admin.close();
  30.                         } catch (IOException e) {
  31.                                 e.printStackTrace();
  32.                         }
  33.                 }
  34.         }
  35. }
复制代码
8.2.3 创建微博内容表

表布局:
方法名 creatTableeContent
Table Name weibo:content
RowKey 用户ID_时间戳
ColumnFamily info
ColumnLabel 标题,内容,图片
Version 1个版本
代码:
  1. /**
  2. * 创建微博内容表
  3. * Table Name:weibo:content
  4. * RowKey:用户ID_时间戳
  5. * ColumnFamily:info
  6. * ColumnLabel:标题        内容                图片URL
  7. * Version:1个版本
  8. */
  9. public void createTableContent(){
  10.         HBaseAdmin admin = null;
  11.         try {
  12.                 admin = new HBaseAdmin(conf);
  13.                 //创建表表述
  14.                 HTableDescriptor content = new HTableDescriptor(TableName.valueOf(TABLE_CONTENT));
  15.                 //创建列族描述
  16.                 HColumnDescriptor info = new HColumnDescriptor(Bytes.toBytes("info"));
  17.                 //设置块缓存
  18.                 info.setBlockCacheEnabled(true);
  19.                 //设置块缓存大小
  20.                 info.setBlocksize(2097152);
  21.                 //设置压缩方式
  22. //                        info.setCompressionType(Algorithm.SNAPPY);
  23.                 //设置版本确界
  24.                 info.setMaxVersions(1);
  25.                 info.setMinVersions(1);
  26.                
  27.                 content.addFamily(info);
  28.                 admin.createTable(content);
  29.                
  30.         } catch (MasterNotRunningException e) {
  31.                 e.printStackTrace();
  32.         } catch (ZooKeeperConnectionException e) {
  33.                 e.printStackTrace();
  34.         } catch (IOException e) {
  35.                 e.printStackTrace();
  36.         }finally{
  37.                 if(null != admin){
  38.                         try {
  39.                                 admin.close();
  40.                         } catch (IOException e) {
  41.                                 e.printStackTrace();
  42.                         }
  43.                 }
  44.         }
  45. }
复制代码
8.2.4 创建用户关系表

表布局:
方法名 createTableRelations
Table Name weibo:relations
RowKey 用户ID
ColumnFamily attends、fans
ColumnLabel 关注用户ID,粉丝用户ID
ColumnValue 用户ID
Version 1个版本
代码:
  1. /**
  2. * 用户关系表
  3. * Table Name:weibo:relations
  4. * RowKey:用户ID
  5. * ColumnFamily:attends,fans
  6. * ColumnLabel:关注用户ID,粉丝用户ID
  7. * ColumnValue:用户ID
  8. * Version:1个版本
  9. */
  10. public void createTableRelations(){
  11.         HBaseAdmin admin = null;
  12.         try {
  13.                 admin = new HBaseAdmin(conf);
  14.                 HTableDescriptor relations = new HTableDescriptor(TableName.valueOf(TABLE_RELATIONS));
  15.                
  16.                 //关注的人的列族
  17.                 HColumnDescriptor attends = new HColumnDescriptor(Bytes.toBytes("attends"));
  18.                 //设置块缓存
  19.                 attends.setBlockCacheEnabled(true);
  20.                 //设置块缓存大小
  21.                 attends.setBlocksize(2097152);
  22.                 //设置压缩方式
  23. //                        info.setCompressionType(Algorithm.SNAPPY);
  24.                 //设置版本确界
  25.                 attends.setMaxVersions(1);
  26.                 attends.setMinVersions(1);
  27.                
  28.                 //粉丝列族
  29.                 HColumnDescriptor fans = new HColumnDescriptor(Bytes.toBytes("fans"));
  30.                 fans.setBlockCacheEnabled(true);
  31.                 fans.setBlocksize(2097152);
  32.                 fans.setMaxVersions(1);
  33.                 fans.setMinVersions(1);
  34.                
  35.                
  36.                 relations.addFamily(attends);
  37.                 relations.addFamily(fans);
  38.                 admin.createTable(relations);
  39.                
  40.         } catch (MasterNotRunningException e) {
  41.                 e.printStackTrace();
  42.         } catch (ZooKeeperConnectionException e) {
  43.                 e.printStackTrace();
  44.         } catch (IOException e) {
  45.                 e.printStackTrace();
  46.         }finally{
  47.                 if(null != admin){
  48.                         try {
  49.                                 admin.close();
  50.                         } catch (IOException e) {
  51.                                 e.printStackTrace();
  52.                         }
  53.                 }
  54.         }
  55. }
复制代码
8.2.5 创建微博收件箱表

表布局:
方法名 createTableReceiveContentEmails
Table Name weibo:receive_content_email
RowKey 用户ID
ColumnFamily info
ColumnLabel 用户ID
ColumnValue 取微博内容的RowKey
Version 1000
代码:
  1. /**
  2. * 创建微博收件箱表
  3. * Table Name: weibo:receive_content_email
  4. * RowKey:用户ID
  5. * ColumnFamily:info
  6. * ColumnLabel:用户ID-发布微博的人的用户ID
  7. * ColumnValue:关注的人的微博的RowKey
  8. * Version:1000
  9. */
  10. public void createTableReceiveContentEmail(){
  11.         HBaseAdmin admin = null;
  12.         try {
  13.                 admin = new HBaseAdmin(conf);
  14.                 HTableDescriptor receive_content_email = new HTableDescriptor(TableName.valueOf(TABLE_RECEIVE_CONTENT_EMAIL));
  15.                 HColumnDescriptor info = new HColumnDescriptor(Bytes.toBytes("info"));
  16.                
  17.                 info.setBlockCacheEnabled(true);
  18.                 info.setBlocksize(2097152);
  19.                 info.setMaxVersions(1000);
  20.                 info.setMinVersions(1000);
  21.                
  22.                 receive_content_email.addFamily(info);;
  23.                 admin.createTable(receive_content_email);
  24.         } catch (MasterNotRunningException e) {
  25.                 e.printStackTrace();
  26.         } catch (ZooKeeperConnectionException e) {
  27.                 e.printStackTrace();
  28.         } catch (IOException e) {
  29.                 e.printStackTrace();
  30.         }finally{
  31.                 if(null != admin){
  32.                         try {
  33.                                 admin.close();
  34.                         } catch (IOException e) {
  35.                                 e.printStackTrace();
  36.                         }
  37.                 }
  38.         }
  39. }
  40. 8.2.6 发布微博内容
  41. a、微博内容表中添加1条数据
  42. b、微博收件箱表对所有粉丝用户添加数据
  43. 代码:Message.java
  44. package com.atguigu.weibo;
  45. public class Message {
  46.         private String uid;
  47.         private String timestamp;
  48.         private String content;
  49.        
  50.         public String getUid() {
  51.                 return uid;
  52.         }
  53.         public void setUid(String uid) {
  54.                 this.uid = uid;
  55.         }
  56.         public String getTimestamp() {
  57.                 return timestamp;
  58.         }
  59.         public void setTimestamp(String timestamp) {
  60.                 this.timestamp = timestamp;
  61.         }
  62.         public String getContent() {
  63.                 return content;
  64.         }
  65.         public void setContent(String content) {
  66.                 this.content = content;
  67.         }
  68.         @Override
  69.         public String toString() {
  70.                 return "Message [uid=" + uid + ", timestamp=" + timestamp + ", content=" + content + "]";
  71.         }
  72. }
  73. 代码:public void publishContent(String uid, String content)
  74. /**
  75. * 发布微博
  76. * a、微博内容表中数据+1
  77. * b、向微博收件箱表中加入微博的Rowkey
  78. */
  79. public void publishContent(String uid, String content){
  80.         HConnection connection = null;
  81.         try {
  82.                 connection = HConnectionManager.createConnection(conf);
  83.                 //a、微博内容表中添加1条数据,首先获取微博内容表描述
  84.                 HTableInterface contentTBL = connection.getTable(TableName.valueOf(TABLE_CONTENT));
  85.                 //组装Rowkey
  86.                 long timestamp = System.currentTimeMillis();
  87.                 String rowKey = uid + "_" + timestamp;
  88.                
  89.                 Put put = new Put(Bytes.toBytes(rowKey));
  90.                 put.add(Bytes.toBytes("info"), Bytes.toBytes("content"), timestamp, Bytes.toBytes(content));
  91.                
  92.                 contentTBL.put(put);
  93.                
  94.                 //b、向微博收件箱表中加入发布的Rowkey
  95.                 //b.1、查询用户关系表,得到当前用户有哪些粉丝
  96.                 HTableInterface relationsTBL = connection.getTable(TableName.valueOf(TABLE_RELATIONS));
  97.                 //b.2、取出目标数据
  98.                 Get get = new Get(Bytes.toBytes(uid));
  99.                 get.addFamily(Bytes.toBytes("fans"));
  100.                
  101.                 Result result = relationsTBL.get(get);
  102.                 List<byte[]> fans = new ArrayList<byte[]>();
  103.                
  104.                 //遍历取出当前发布微博的用户的所有粉丝数据
  105.                 for(Cell cell : result.rawCells()){
  106.                         fans.add(CellUtil.cloneQualifier(cell));
  107.                 }
  108.                 //如果该用户没有粉丝,则直接return
  109.                 if(fans.size() <= 0) return;
  110.                 //开始操作收件箱表
  111.                 HTableInterface recTBL = connection.getTable(TableName.valueOf(TABLE_RECEIVE_CONTENT_EMAIL));
  112.                 List<Put> puts = new ArrayList<Put>();
  113.                 for(byte[] fan : fans){
  114.                         Put fanPut = new Put(fan);
  115.                         fanPut.add(Bytes.toBytes("info"), Bytes.toBytes(uid), timestamp, Bytes.toBytes(rowKey));
  116.                         puts.add(fanPut);
  117.                 }
  118.                 recTBL.put(puts);
  119.         } catch (IOException e) {
  120.                 e.printStackTrace();
  121.         }finally{
  122.                 if(null != connection){
  123.                         try {
  124.                                 connection.close();
  125.                         } catch (IOException e) {
  126.                                 e.printStackTrace();
  127.                         }
  128.                 }
  129.         }
  130. }
复制代码
8.2.7 添加关注用户

a、在微博用户关系表中,对当前主动利用的用户添加新关注的好友
b、在微博用户关系表中,对被关注的用户添加新的粉丝
c、微博收件箱表中添加所关注的用户发布的微博
代码实现:
  1. public void addAttends(String uid, String... attends)
  2. /**
  3. * 关注用户逻辑
  4. * a、在微博用户关系表中,对当前主动操作的用户添加新的关注的好友
  5. * b、在微博用户关系表中,对被关注的用户添加粉丝(当前操作的用户)
  6. * c、当前操作用户的微博收件箱添加所关注的用户发布的微博rowkey
  7. */
  8. public void addAttends(String uid, String... attends){
  9.         //参数过滤
  10.         if(attends == null || attends.length <= 0 || uid == null || uid.length() <= 0){
  11.                 return;
  12.         }
  13.         HConnection connection = null;
  14.         try {
  15.                 connection = HConnectionManager.createConnection(conf);
  16.                 //用户关系表操作对象(连接到用户关系表)
  17.                 HTableInterface relationsTBL = connection.getTable(TableName.valueOf(TABLE_RELATIONS));
  18.                 List<Put> puts = new ArrayList<Put>();
  19.                 //a、在微博用户关系表中,添加新关注的好友
  20.                 Put attendPut = new Put(Bytes.toBytes(uid));
  21.                 for(String attend : attends){
  22.                         //为当前用户添加关注的人
  23.                         attendPut.add(Bytes.toBytes("attends"), Bytes.toBytes(attend), Bytes.toBytes(attend));
  24.                         //b、为被关注的人,添加粉丝
  25.                         Put fansPut = new Put(Bytes.toBytes(attend));
  26.                         fansPut.add(Bytes.toBytes("fans"), Bytes.toBytes(uid), Bytes.toBytes(uid));
  27.                         //将所有关注的人一个一个的添加到puts(List)集合中
  28.                         puts.add(fansPut);
  29.                 }
  30.                 puts.add(attendPut);
  31.                 relationsTBL.put(puts);
  32.                
  33.                 //c.1、微博收件箱添加关注的用户发布的微博内容(content)的rowkey
  34.                 HTableInterface contentTBL = connection.getTable(TableName.valueOf(TABLE_CONTENT));
  35.                 Scan scan = new Scan();
  36.                 //用于存放取出来的关注的人所发布的微博的rowkey
  37.                 List<byte[]> rowkeys = new ArrayList<byte[]>();
  38.                
  39.                 for(String attend : attends){
  40.                         //过滤扫描rowkey,即:前置位匹配被关注的人的uid_
  41.                         RowFilter filter = new RowFilter(CompareFilter.CompareOp.EQUAL, new SubstringComparator(attend + "_"));
  42.                         //为扫描对象指定过滤规则
  43.                         scan.setFilter(filter);
  44.                         //通过扫描对象得到scanner
  45.                         ResultScanner result = contentTBL.getScanner(scan);
  46.                         //迭代器遍历扫描出来的结果集
  47.                         Iterator<Result> iterator = result.iterator();
  48.                         while(iterator.hasNext()){
  49.                                 //取出每一个符合扫描结果的那一行数据
  50.                                 Result r = iterator.next();
  51.                                 for(Cell cell : r.rawCells()){
  52.                                         //将得到的rowkey放置于集合容器中
  53.                                         rowkeys.add(CellUtil.cloneRow(cell));
  54.                                 }
  55.                                
  56.                         }
  57.                 }
  58.                
  59.                 //c.2、将取出的微博rowkey放置于当前操作用户的收件箱中
  60.                 if(rowkeys.size() <= 0) return;
  61.                 //得到微博收件箱表的操作对象
  62.                 HTableInterface recTBL = connection.getTable(TableName.valueOf(TABLE_RECEIVE_CONTENT_EMAIL));
  63.                 //用于存放多个关注的用户的发布的多条微博rowkey信息
  64.                 List<Put> recPuts = new ArrayList<Put>();
  65.                 for(byte[] rk : rowkeys){
  66.                         Put put = new Put(Bytes.toBytes(uid));
  67.                         //uid_timestamp
  68.                         String rowKey = Bytes.toString(rk);
  69.                         //借取uid
  70.                         String attendUID = rowKey.substring(0, rowKey.indexOf("_"));
  71.                         long timestamp = Long.parseLong(rowKey.substring(rowKey.indexOf("_") + 1));
  72.                         //将微博rowkey添加到指定单元格中
  73.                         put.add(Bytes.toBytes("info"), Bytes.toBytes(attendUID), timestamp, rk);
  74.                         recPuts.add(put);
  75.                 }
  76.                
  77.                 recTBL.put(recPuts);
  78.                
  79.         } catch (IOException e) {
  80.                 e.printStackTrace();
  81.         }finally{
  82.                 if(null != connection){
  83.                         try {
  84.                                 connection.close();
  85.                         } catch (IOException e) {
  86.                                 // TODO Auto-generated catch block
  87.                                 e.printStackTrace();
  88.                         }
  89.                 }
  90.         }
  91. }
复制代码
8.2.8 移除(取关)用户

a、在微博用户关系表中,对当前主动利用的用户移除取关的好友(attends)
b、在微博用户关系表中,对被取关的用户移除粉丝
c、微博收件箱中删除取关的用户发布的微博
代码:
  1. public void removeAttends(String uid, String... attends)
  2. /**
  3. * 取消关注(remove)
  4. * a、在微博用户关系表中,对当前主动操作的用户删除对应取关的好友
  5. * b、在微博用户关系表中,对被取消关注的人删除粉丝(当前操作人)
  6. * c、从收件箱中,删除取关的人的微博的rowkey
  7. */
  8. public void removeAttends(String uid, String... attends){
  9.         //过滤数据
  10.         if(uid == null || uid.length() <= 0 || attends == null || attends.length <= 0) return;
  11.         HConnection connection = null;
  12.        
  13.         try {
  14.                 connection = HConnectionManager.createConnection(conf);
  15.                 //a、在微博用户关系表中,删除已关注的好友
  16.                 HTableInterface relationsTBL = connection.getTable(TableName.valueOf(TABLE_RELATIONS));
  17.                
  18.                 //待删除的用户关系表中的所有数据
  19.                 List<Delete> deletes = new ArrayList<Delete>();
  20.                 //当前取关操作者的uid对应的Delete对象
  21.                 Delete attendDelete = new Delete(Bytes.toBytes(uid));
  22.                 //遍历取关,同时每次取关都要将被取关的人的粉丝-1
  23.                 for(String attend : attends){
  24.                         attendDelete.deleteColumn(Bytes.toBytes("attends"), Bytes.toBytes(attend));
  25.                         //b
  26.                         Delete fansDelete = new Delete(Bytes.toBytes(attend));
  27.                         fansDelete.deleteColumn(Bytes.toBytes("fans"), Bytes.toBytes(uid));
  28.                         deletes.add(fansDelete);
  29.                 }
  30.                
  31.                 deletes.add(attendDelete);
  32.                 relationsTBL.delete(deletes);
  33.                
  34.                 //c、删除取关的人的微博rowkey 从 收件箱表中
  35.                 HTableInterface recTBL = connection.getTable(TableName.valueOf(TABLE_RECEIVE_CONTENT_EMAIL));
  36.                
  37.                 Delete recDelete = new Delete(Bytes.toBytes(uid));
  38.                 for(String attend : attends){
  39.                         recDelete.deleteColumn(Bytes.toBytes("info"), Bytes.toBytes(attend));
  40.                 }
  41.                 recTBL.delete(recDelete);
  42.         } catch (IOException e) {
  43.                 e.printStackTrace();
  44.         }
  45. }
  46. 8.2.9 获取关注的人的微博内容
  47. a、从微博收件箱中获取所关注的用户的微博RowKey
  48. b、根据获取的RowKey,得到微博内容
  49. 代码实现:public List<Message> getAttendsContent(String uid)
  50. /**
  51. * 获取微博实际内容
  52. * a、从微博收件箱中获取所有关注的人的发布的微博的rowkey
  53. * b、根据得到的rowkey去微博内容表中得到数据
  54. * c、将得到的数据封装到Message对象中
  55. */
  56. public List<Message> getAttendsContent(String uid){
  57.         HConnection connection = null;
  58.         try {
  59.                 connection = HConnectionManager.createConnection(conf);
  60.                 HTableInterface recTBL = connection.getTable(TableName.valueOf(TABLE_RECEIVE_CONTENT_EMAIL));
  61.                 //a、从收件箱中取得微博rowKey
  62.                 Get get = new Get(Bytes.toBytes(uid));
  63.                 //设置最大版本号
  64.                 get.setMaxVersions(5);
  65.                 List<byte[]> rowkeys = new ArrayList<byte[]>();
  66.                 Result result = recTBL.get(get);
  67.                 for(Cell cell : result.rawCells()){
  68.                         rowkeys.add(CellUtil.cloneValue(cell));
  69.                 }
  70.                 //b、根据取出的所有rowkey去微博内容表中检索数据
  71.                 HTableInterface contentTBL = connection.getTable(TableName.valueOf(TABLE_CONTENT));
  72.                 List<Get> gets = new ArrayList<Get>();
  73.                 //根据rowkey取出对应微博的具体内容
  74.                 for(byte[] rk : rowkeys){
  75.                         Get g = new Get(rk);
  76.                         gets.add(g);
  77.                 }
  78.                 //得到所有的微博内容的result对象
  79.                 Result[] results = contentTBL.get(gets);
  80.                
  81.                 List<Message> messages = new ArrayList<Message>();
  82.                 for(Result res : results){
  83.                         for(Cell cell : res.rawCells()){
  84.                                 Message message = new Message();
  85.                                
  86.                                 String rowKey = Bytes.toString(CellUtil.cloneRow(cell));
  87.                                 String userid = rowKey.substring(0, rowKey.indexOf("_"));
  88.                                 String timestamp = rowKey.substring(rowKey.indexOf("_") + 1);
  89.                                 String content = Bytes.toString(CellUtil.cloneValue(cell));
  90.                                
  91.                                 message.setContent(content);
  92.                                 message.setTimestamp(timestamp);
  93.                                 message.setUid(userid);
  94.                                
  95.                                 messages.add(message);
  96.                         }
  97.                 }
  98.                 return messages;
  99.         } catch (IOException e) {
  100.                 e.printStackTrace();
  101.         }finally{
  102.                 try {
  103.                         connection.close();
  104.                 } catch (IOException e) {
  105.                         e.printStackTrace();
  106.                 }
  107.         }
  108.         return null;
  109. }
复制代码
8.2.10 测试

  1. -- 测试发布微博内容
  2. public void testPublishContent(WeiBo wb)
  3. -- 测试添加关注
  4. public void testAddAttend(WeiBo wb)
  5. -- 测试取消关注
  6. public void testRemoveAttend(WeiBo wb)
  7. -- 测试展示内容
  8. public void testShowMessage(WeiBo wb)       
复制代码
代码:
  1. /**
  2. * 发布微博内容
  3. * 添加关注
  4. * 取消关注
  5. * 展示内容
  6. */
  7. public void testPublishContent(WeiBo wb){
  8.         wb.publishContent("0001", "今天买了一包空气,送了点薯片,非常开心!!");
  9.         wb.publishContent("0001", "今天天气不错。");
  10. }
  11. public void testAddAttend(WeiBo wb){
  12.         wb.publishContent("0008", "准备下课!");
  13.         wb.publishContent("0009", "准备关机!");
  14.         wb.addAttends("0001", "0008", "0009");
  15. }
  16. public void testRemoveAttend(WeiBo wb){
  17.         wb.removeAttends("0001", "0008");
  18. }
  19. public void testShowMessage(WeiBo wb){
  20.         List<Message> messages = wb.getAttendsContent("0001");
  21.         for(Message message : messages){
  22.                 System.out.println(message);
  23.         }
  24. }
复制代码
  1. public static void main(String[] args) {
  2.         WeiBo weibo = new WeiBo();
  3.         weibo.initTable();
  4.         weibo.testPublishContent(weibo);
  5.         weibo.testAddAttend(weibo);
  6.         weibo.testShowMessage(weibo);
  7.         weibo.testRemoveAttend(weibo);
  8.         weibo.testShowMessage(weibo);
  9. }
复制代码
第9章 扩展

9.1 HBase在商业项目中的能力

每天:

  • 消息量:发送和接收的消息数凌驾60亿
  • 将近1000亿条数据的读写
  • 高峰期每秒150万左右利用
  • 团体读取数据占有约55%,写入占有45%
  • 凌驾2PB的数据,涉及冗余共6PB数据
  • 数据每月大概增长300千兆字节。
9.2 布隆过滤器

在日常生活中,包括在设计计算机软件时,我们常常要判定一个元素是否在一个聚集中。比如在字处理软件中,需要检查一个英语单词是否拼写精确(也就是要判定它是否在已知的字典中);在 FBI,一个嫌疑人的名字是否已经在嫌疑名单上;在网络爬虫里,一个网址是否被访问过等等。最直接的方法就是将聚集中全部的元素存在计算机中,碰到一个新元素时,将它和聚集中的元素直接比较即可。一般来讲,计算机中的聚集是用哈希表(hash table)来存储的。它的好处是快速准确,缺点是费存储空间。当聚集比较小时,这个标题不显著,但是当聚集巨大时,哈希表存储效率低的标题就显现出来了。比如说,一个像 Yahoo,Hotmail 和 Gmai 那样的公众电子邮件(email)提供商,总是需要过滤来自发送垃圾邮件的人(spamer)的垃圾邮件。一个办法就是记载下那些发垃圾邮件的 email 地点。由于那些发送者不停地在注册新的地点,全天下少说也有几十亿个发垃圾邮件的地点,将他们都存起来则需要大量的网络服务器。如果用哈希表,每存储一亿个 email 地点, 就需要 1.6GB 的内存(用哈希表实现的详细办法是将每一个 email 地点对应成一个八字节的信息指纹googlechinablog.com/2006/08/blog-post.html,然后将这些信息指纹存入哈希表,由于哈希表的存储效率一般只有 50%,因此一个 email 地点需要占用十六个字节。一亿个地点大约要 1.6GB, 即十六亿字节的内存)。因此存贮几十亿个邮件地点大概需要上百 GB 的内存。除非是超级计算机,一般服务器是无法存储的。
布隆过滤器只需要哈希表 1/8 到 1/4 的巨细就能办理同样的标题。
Bloom Filter是一种空间效率很高的随机数据布局,它利用位数组很简便地表现一个聚集,并能判定一个元素是否属于这个聚集。Bloom Filter的这种高效是有一定代价的:在判定一个元素是否属于某个聚集时,有大概会把不属于这个聚集的元素误以为属于这个聚集(false positive)。因此,Bloom Filter不适合那些“零错误”的应用场合。而在能容忍低错误率的应用场合下,Bloom Filter通过极少的错误调换了存储空间的极大节省。
9.2 HBase2.0新特性

2017年8月22日破晓2点左右,HBase发布了2.0.0 alpha-2,相比于上一个版本,修复了500个补丁,我们来了解一下2.0版本的HBase新特性。
最新文档:
http://hbase.apache.org/book.html#ttl
官方发布主页:
http://mail-archives.apache.org/mod_mbox/www-announce/201708.mbox/<CADcMMgFzmX0xYYso-UAYbU7V8z-Obk1J4pxzbGkRzbP5Hps+iA@mail.gmail.com
举例:

  • region举行了多份冗余
    主region负责读写,从region维护在其他HregionServer中,负责读以及同步主region中的信息,如果同步不及时,是有大概出现client在从region中读到了脏数据(主region还没来得及把memstore中的变动的内容flush)。
  • 更多变动可以去看:
    https://issues.apache.org/jira/secure/ReleaseNote.jspa?version=12340859&styleName=&projectId=12310753&Create=Create&atl_token=A5KQ-2QAV-T4JA-FDED%7Ce6f233490acdf4785b697d4b457f7adb0a72b69f%7Clout
最近有点忙,我发现自己感觉到累的时候,能学到很多,发现很多标题,这个感觉就对了,有压力才有动力,找出标题不停进步。
想起了毛泽东同志的一句名言:“我们的同志要在困难的时候,要看到结果,要看到光明,要提高我们的勇气”。
兄弟们一起加油,一起变强!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

熊熊出没

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表