一起重新开始学大数据-Hbase篇-day 55 浅谈布隆过滤器、Hbase读写、Hbase的HA和Mapreduce读写Hbase数据 |
浅谈布隆过滤器
概述:
Bloom Filter(布隆过滤器)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
在计算机科学中,我们常常会碰到时间换空间或者空间换时间的情况,即为了达到某一个方面的最优而牺牲另一个方面。Bloom Filter在时间空间这两个因素之外又引入了另一个因素:错误率。在使用Bloom Filter判断一个元素是否属于某个集合时,会有一定的错误率。也就是说,有可能把不属于这个集合的元素误认为属于这个集合(False Positive),但不会把属于这个集合的元素误认为不属于这个集合(False Negative)。在增加了错误率这个因素之后,Bloom Filter通过允许少量的错误来节省大量的存储空间。
它的用法其实是很容易理解的,我们拿个HBase中应用的例子来说下,我们已经知道rowKey存放在HFile中,那么为了从一系列的HFile中查询某个rowkey,我们就可以通过 Bloom Filter 快速判断 rowkey 是否在这个HFile中,从而过滤掉大部分的HFile,减少需要扫描的Block。
图解析:
BloomFilter对于HBase的随机读性能至关重要,对于get操作以及部分scan操作可以剔除掉不会用到的HFile文件,减少实际IO次数,提高随机读性能。在此简单地介绍一下Bloom Filter的工作原理,Bloom Filter使用位数组来实现过滤,初始状态下位数组每一位都为0,如下图所示:
假如此时有一个集合S = {x1, x2, … xn},Bloom Filter使用k个独立的hash函数,分别将集合中的每一个元素映射到{1,…,m}的范围。对于任何一个元素,被映射到的数字作为对应的位数组的索引,该位会被置为1。比如元素x1被hash函数映射到数字8,那么位数组的第8位就会被置为1。下图中集合S只有两个元素x和y,分别被3个hash函数进行映射,映射到的位置分别为(0,3,6)和(4,7,10),对应的位会被置为1:
现在假如要判断另一个元素是否是在此集合中,只需要被这3个hash函数进行映射,查看对应的位置是否有0存在,如果有的话,表示此元素肯定不存在于这个集合,否则有可能存在。下图所示就表示z肯定不在集合{x,y}中:
从上面的内容我们可以得知,Bloom Filter有两个很重要的参数
- 哈希函数个数
- 位数组的大小
布隆过滤器(Bloom Filter)在HBase中的作用
HFile 中和 Bloom Filter 相关的Block:
- Scanned Block Section(扫描HFile时被读取):Bloom Block
- Load-on-open-section(regionServer启动时加载到内存):BloomFilter Meta Block、Bloom Index Block
- Bloom Block:Bloom数据块,存储Bloom的位数组
- Bloom Index Block:Bloom数据块的索引
- BloomFilter Meta Block:从HFile角度看bloom数据块的一些元数据信息,大小个数等等。
HBase中每个HFile都有对应的位数组,KeyValue在写入HFile时会先经过几个hash函数的映射,映射后将对应的数组位改为1,get请求进来之后再进行hash映射,如果在对应数组位上存在0,说明该get请求查询的数据不在该HFile中。
HFile中的Bloom Block中存储的就是上面说得位数组,当HFile很大时,Data Block 就会很多,同时KeyValue也会很多,需要映射入位数组的rowKey也会很多,所以为了保证准确率,位数组就会相应越大,那Bloom Block也会越大,为了解决这个问题就出现了Bloom Index Block,一个HFile中有多个Bloom Block(位数组),根据rowKey拆分,一部分连续的Key使用一个位数组。这样查询rowKey就要先经过Bloom Index Block(在内存中)定位到Bloom Block,再把Bloom Block加载到内存,进行过滤。
Hbase的读写
HBase读写流程:
写流程:
首先由客户端(HBase shell、Java API)发起一个写请求。然后客户端会去连接ZK,在ZK里查找Meta表(记录了每张表的每一个region所储存的rowkey的范围)的位置,比如说在node1上,那么就会去连接node1,然后根据所要写入的数据的rowkey去和meta里的数据进行对比,找到该rowkey需要写入的region所在的regionserver,例如在node2,那么客户端就会去连接node2上的RS,然后将数据(是一个Put对象)写入,先将数据写入RS上的HLOG中,然后再将数据写入Region中的MemStore,当写完memstore后会立即返回(写请求到这就完成了,整个过程不需要HMaster参与:当Memstore中的数据达到128M则会触发Flush刷写操作形成storefile)
读流程:
跟写流程差不多。不管是读或写,都需要根据所写入或读取的数据的Rowkey去结合ZK及Meta表中的数据定位到Rowkey所属的Region所在的RS,例如在node1.那么客户端将会去连接node1上面的RS,首先先从BLOCKCACHE中找,如果没有再去MemStore中找。如果再找不到则会去HFILE中查找如果所查找的数据所在的列簇设置了in_memory=true。则会将查找到的数据放入缓存
Client为了加快读写请求。会在第一次找到Meta的位置时,将其位置缓存
Hbase的HA(高可用)
HmasterHA启动
在node1或node2上再启动一个Hmaster ,cd /usr/local/soft/hbase-1.4.6/bin
执行 ./hbase-daemonsh start master
Mapreduce读写Hbase数据
注意:
若执行代码过程中显示找不到main找不到依赖
在pom.xml中添加标签如下,打包过程连带打包依赖
<build>
<plugins>
<!-- Java Compiler -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!-- 带依赖jar 插件-->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
从Hbase中读取数据到HDFS
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
import org.apache.hadoop.hbase.mapreduce.TableMapper;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
public class MRReadHBase {
// 读取HBase students表数据 并统计每个班级的人数
public static class MyMapper extends TableMapper<Text, IntWritable> {
@Override
protected void map(ImmutableBytesWritable key, Result value, Mapper<ImmutableBytesWritable, Result, Text, IntWritable>.Context context) throws IOException, InterruptedException {
// 进入map任务中的key就是rowkey
String rowkey = Bytes.toString(key.get());
// 进入map任务中的value就是hbase中的一条数据
byte[] row = value.getRow(); // 通过getRow也可以取出rowkey来
String clazz = Bytes.toString(value.getValue("info".getBytes(), "clazz".getBytes()));
context.write(new Text(clazz), new IntWritable(1));
}
}
public static class MyReduce extends Reducer<Text, IntWritable, Text, IntWritable> {
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
int cnt = 0;
for (IntWritable value : values) {
cnt++;
}
context.write(key, new IntWritable(cnt));
}
}
public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
Configuration conf = new Configuration();
conf.set("hbase.zookeeper.quorum","master:2181,node1:2181,node2:2181");
Job job = Job.getInstance(conf);
job.setJobName("MRReadHBase");
job.setJarByClass(MRReadHBase.class);
// 使用TableMapReduceUtil配置Map任务
TableMapReduceUtil.initTableMapperJob("students"
, new Scan()
, MyMapper.class
, Text.class
, IntWritable.class
, job
);
// 配置Reduce任务
job.setReducerClass(MyReduce.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
// 配置输出路径
FileOutputFormat.setOutputPath(job, new Path("/mrHBase01"));
job.waitForCompletion(true);
}
}
从本地HDFS中读取数据到Hbase
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.client.Mutation;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.mapred.TableOutputFormat;
import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
import org.apache.hadoop.hbase.mapreduce.TableReducer;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
// 读取本地score.txt文件 计算每个学生的总分 并将结果写入HBase
public class MRWriteHBase {
public static class MyMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
@Override
protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException {
String[] splits = value.toString().split(",");
String rowkey = splits[0];
int score = Integer.parseInt(splits[2]);
context.write(new Text(rowkey), new IntWritable(score));
}
}
public static class WriteHBase extends TableReducer<Text, IntWritable, NullWritable> {
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, NullWritable, Mutation>.Context context) throws IOException, InterruptedException {
int sum = 0; // 保存总分
for (IntWritable value : values) {
sum += value.get();
}
Put put = new Put(key.getBytes());
put.addColumn("cf1".getBytes(), "ss".getBytes(), (sum + "").getBytes());
context.write(NullWritable.get(), put);
}
}
public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
Configuration conf = new Configuration();
conf.set("hbase.zookeeper.quorum", "master:2181,node1:2181,node2:2181");
Job job = Job.getInstance(conf);
job.setJobName("MRWriteHBase");
job.setJarByClass(MRWriteHBase.class);
// 配置Map任务
job.setMapperClass(MyMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
// 使用TableMapReduceUtil配置Reduce任务
TableMapReduceUtil.initTableReducerJob(
"sum_score"
, WriteHBase.class
, job
);
// 配置输入路径
FileInputFormat.addInputPath(job,new Path("/mrHBaseInput1"));
job.waitForCompletion(true);
}
/**编写代码后执行步骤
* 在HBase中建表:create 'sum_score','cf1'
* 将score.txt 上传到 /mrHBaseInput1
* 打包上传jar包
* hadoop jar HBase-1.0-jar-with-dependencies.jar com.shujia.Demo6MRWriteHBase
*/
}
从Hbase中读取数据到Hbase
package com.tiand7;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
import org.apache.hadoop.hbase.mapreduce.TableMapper;
import org.apache.hadoop.hbase.mapreduce.TableReducer;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import java.io.IOException;
public class MRfromHbase {
public static class Mymap extends TableMapper<Text,Text>{
@Override
protected void map(ImmutableBytesWritable key, Result value, Context context) throws IOException, InterruptedException {
byte[] bytes = key.get();
String rowkey = Bytes.toString(bytes);
String clazz = Bytes.toString(value.getValue("info".getBytes(), "name".getBytes()));
context.write(new Text(rowkey),new Text(clazz));
}
}
public static class MyReduce extends TableReducer<Text,Text,NullWritable>{
@Override
protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
Put put = new Put(key.getBytes());
for (Text value : values) {
put.addColumn("info".getBytes(),"name".getBytes(),value.getBytes());
}
context.write(NullWritable.get(),put);
}
}
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
Configuration conf = new Configuration();
conf.set("hbase.zookeeper.quorum", "master:2181,node1:2181,node2:2181");
Job job = Job.getInstance(conf);
job.setJobName("MRfromHbase");
job.setJarByClass(MRfromHbase.class);
// map
TableMapReduceUtil.initTableMapperJob("students",new Scan(),Mymap.class,Text.class,Text.class,job);
// reduce
TableMapReduceUtil.initTableReducerJob("nametip",MyReduce.class,job);
job.waitForCompletion(true);
}
}
|
|
|
|
上一章-Hbase篇-day 54 Hbase介绍、shell、过滤器
下一章-Hbase篇-day 56 Phoenix
|
|
|
|
|
听说长按大拇指👍会发生神奇的事情呢!好像是下面的画面,听说点过的人🧑一个月内就找到了对象的💑💑💑,第二天买彩票中了大奖💴$$$,考试直接拿满分💯,颜值突然就提升了😎,虽然对你好像也不需要,你说是吧,吴彦祖🤵! |