Day01 12-09
数据(本身没有价值)—》信息(挖掘)—》价值
概念
Cluster 集群 hadoop、多台机器(共同完成同一个工作)、多人游戏的队伍
DIC 数据密集型 数据量大但是计算过程相对简单 √
CIC 计算密集型 数据量相对小但是计算过程复杂
Scale—Up 向上扩展 提高计算机性能的方式
Scale—Out 向外扩展 提高计算机性能的方式(集群)
Machine 机器学习 预测未来 (函数、模型)
Cloud 云计算 整合硬件资源,以虚拟机或程序形式向外提供服务(百度云、阿里云…)
大数据背景
Structured 结构化数据(数据库中数据 以二维表形式存储)------->Semi-structured 半结构化数据(经过简单处理就能转化为二维表)------->Unstructured 非结构化数据(不能转化成二维表 目前大部份数据都为非结构化数据)
大数据定义及特点
为决策问题提供服务的大数据集、大数据技术和大数据应用的总称。
大数据集:决策问题所用到的所有可能的数据,数据量大、来源多样、种类多样
大数据技术:大数据集获取、存储管理、挖掘分析、可视化展现等技术。
大数据应用:大数据集和大数据技术来支持决策活动,是新的决策方法。(一般叫XX引擎–不能单独运行,一般套在其他软件中(汽车引擎较之于汽车))
大数据现有技术
VMware是个重量级的软件,有很多和虚拟机不相关的东西都在里面,所以机子稍微差一点的机子,运行就会很慢,甚至卡死。
Hbase的存四维关系列表(四个参数),Hive(将程序写简单)
KVM虚拟化技术(基于内核的虚拟化技术)
Zookeeper分布式协调服务集群
Hbase集群(非关系型数据库 存放四维表) 关系型:能存放二维表
Hive数据仓库(小工具,来把程序写简单)
Scala程序设计 spark集群
汇编—》c语言—》c++/java—》python—》 SQL
不同的数据处理方案
离线数据分析
又叫批量数据分析,通常指数据产生时间跨度在数十分钟到数小时之间,在我们课程体系内,主要是以hadoop及其生态圈作为技术解决方案
实时数据分析
又叫流式数据分析,通常指数据产生时间跨度在数百毫秒到数秒之间,在我们的课程体系内,主要是以spark及其生态圈作为技术解决方案
day02 12-10
linux 基本命令
day03 12-11
lo回环地址:自己和自己通信 ,只有在给自己装了一个网卡(虚拟网卡)之后才能实现自己和自己通信(同一台电脑的不同软件)。
安装ssh服务端
a. 连网
b. sudo apt-get update
sudo apt-get install open-ssh
sudo service ssh status 可查看是否安装成功 —》绿色 active(running) 则成功
拓展:C/S 客户端是自定义的(自己编程) B/S 客户端是固定的 一个浏览器
ssh是一个web程序(有客户端和服务端的程序)
ssh原理 你是一个客户端, 在你需要远程登录的电脑里需要有一个服务端
ssh 远程登录 控制 ssh briup@ip地址
ssh 远程拷贝 scp 文件名 briup@ip地址:路径
date 查看时间 可以更改时间,需要管理员权限
cal 日历 ;cal 1 2020 查看2020年1月 ; cal 2020 查看全年的日历
grep 内容筛选
grep briup /etc/passwd
ps -ef | grep sshd (ps展示进程信息,-ef详细展示 筛选带有sshd的进程进行显示)
xx | gerp 4040 查看端口占用情况
head 默认展示文件的前五行
tail 默认展示文件的后五行
vi 编辑器
:set nu 在底行模式中 可显示行号
:行号 定位行 ( :8 转到第八行;:$转到最后一行 )
hadoop安装 伪分布式
-
更改机器名
sudo vi /etc/hostname
hadoopPD -
更改ip机器名的映射关系
sudo vi /etc/hosts -
安装ssh服务端
完成上述操作后重启虚拟机
-
压缩包放 家目录下/software 并解压
-
创建软连接,以备之后更新版本
ln -s ~/software/hadoop-3.1.0 ~/software/hadoop -
增加环境变量
gedit ~/.bashrc
倒数第二行插入以下行
export HADOOP_HOME=hadoop软连接路径
在PATH后面追加 : $ HADOOP_HOME/bin:$HADOOP_HOME/sbin
source ~/.bashrc 重新加载配置文件 -
更改hadoop配置文件
~/software/hadoop/etc/hadoop/hadoop-env.sh
54行左右 找到
#export JAVA_HOME=xxxxx
a,解除注释
b,更改jdk路径,路径可以通过which java快速找到
core-site.xml
fs.defaultFS
hdfs-site.xml
a,粘贴配置项,按自己机器实际情况,更改配置项中的机器名和家目录路径
b,创建目录yarn-site.xml
mapred-site.xml -
格式化 ( 初始化 )文件系统
hdfs namenode -format
格式化过程中会给主节点和从节点分配id,多次格式化会造成 id冲突
如果真的想要格式化第二次,需要删除第一次格式化生成的文件。 -
启动集群
hdfs --daemon start namenode
hdfs --daemon start datanodejps
http://192.168.xxx.xxx:9870
http://192.168.xxx.xxx:8088
day04 12-12
Hadoop Programming
HDFS 分布式文件系统
海量数据超过单台计算机的存储能力,对数据分区存储于若干物理主机。
分布式文件系统
- 管理网络中跨多台计算机存储的文件系统
- HDFS就是这样的一个分布式文件系统
特征
-Hardware Failure:
-Large Data Sets: A typical file in HDFS is gigabytes to terabytes in size.
-Streaming Data Access: HDFS is designed more for batch processing rather than
-interactive use by users. The emphasis is on high throughput of data access rather
-than low latency of data access.
-Simple Coherency Model:
-“Moving Computation is Cheaper than Moving Data”
-Portability Across Heterogeneous Hardware and Software Platforms
-不适合低时间延迟的数据访问(数据访问的效率较低,不能做交互式,低延时的数据访问;做低延时数据处理一定是数据库。)
-不适宜大量的小文件
-主从架构(master/slave)
HDFS 层次结构
主节点namenode 主要工作维护元数据 (总览,纲要)
从节点datanode 存放切分后的数据块
元数据metadata
client客户端 一些操作从主节点访问,另一些直接访问从节点
rack机架 机架感知机制 从一个机架复制出来的块(block),会复制到其他机架中防止一些突发状况(停电)
积累一段时间操作,一次性更改目录树(批量操作) 不想频繁刷新内存,不想频繁读写。
edits达到一定程度(手动设置上限)或者主节点比较空闲的时候(cpu没人用)会进行合并。
整个集群规模受制于主节点的内存,因此主节点的内存需要大。
secondarynamenode 辅助主节点
datanode 用来存储和检索数据块
创建移动删除拷贝数据块
周期性的向主节点报告现在有哪些块
HDFS DFS的操作
hdfs和linux里面的路径一致 (从根目录开始一级一级往下)
hdfs 是一种文件系统 都是由命令来操作,这时候看哪个用户在操作hdfs,只需要看用户名。hdfs中其他用户名对某一用户的文件操作时,会没有权限。只要用户名能够匹配上,就可以来操作文件系统。
hadoop中其实存在权限最高的用户,那就是创建者。
hdfs 路径
hdfs中没有相对路径 ,所有路径只能写绝对路径。
需要自己创建家目录; “ . ” 在hdfs中代表家目录 《==》 /user/briup
ps:在使用过mapdeduce程序后,会自动创建家目录(当前用户)
创建目录
hdfs dfs -mkdir /input ——> 创建指定目录
hdfs dfs -mkdir -p /user/input ——> 创建指定目录
查看目录结构
hdfs dfs -ls /input ——>查看指定目录(/input)结构
hdfs dfs -ls -R /input ——>递归查看指定目录(/input)结构
上传文件
hdfs dfs -put ./someWords.txt /user/input
下载文件到本地
hdfs dfs -get hdfs local
查看文件内容
hdfs dfs -rm /user/input/someWords.txt
删除文件
hdfs dfs -rm /user/input/someWords.txt
从本地文件系统复制文件到HDFS
hdfs dfs –copyFromLocal someWords2.txt/user/input
修改文件权限
hdfs dfs –chmod 777 /user/input/someWords.txt
修改属主
hdfs dfs -chown yarn /user/input/someWords.txt
修改属组
hdfs dfs -chgrp yarn /user/input/someWords.txt
eclipse 项目架构工具maven
菜单栏点击window–》Preferences
搜索maven–》installations
Add–》Directory–》选择下载下来的maven–》Finish
设置完成后会在右下角显示进度条 *电脑需要联网
在 pom.xml中配置环境
同样会出现进度条,等进度条加载完成就可以进行编程。
programming
public class ShowContentFromHdfs {
public static void main(String[] args) throws IOException {
//1 获取配置对象
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://192.168.43.139:9000");
//2 获取文件系统 FileSystem
org.apache.hadoop.fs.FileSystem fs = org.apache.hadoop.fs.FileSystem.get(conf);
//3 获取hdfs的输入流
FSDataInputStream in = fs.open(new Path("/passwd"));
//4 执行读取操作 需要包两层 原始字节流--》转化流--》字符流
BufferedReader rd = new BufferedReader((new InputStreamReader(in)));
String line = "";
while((line = rd.readLine())!= null) {
System.out.println(line);
}
//5 关闭资源
fs.close();
}
}
day05 12-13
数据上传
基本流程
//获取配置对象
Configuration conf = new Configuration();
conf.set("fs.defaultFS","");
//获取文件系统
FileSystem fs = FileSystem.get(conf);
//输入流
FileInputStream in = new FileInputStream("");
//输出流
FSDataOutputStream out = fs.create(new Path(""));
//输入流字节拷贝到输出流
IOUtils.copyBytes(in, out, 1024);
//关闭流
in.close();
fs.close();
showFStree 显示文件系统目录树
package shixun_hadoop;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
//展示整个文件系统的目录树 ==》模拟ls -R
//如何获取file元数据
public class ShowFSTree extends Configured implements Tool{ //主方法
FileSystem fs =null;
public static void main(String[] args) throws Exception {
ToolRunner.run(new ShowFSTree(), args);
}
@Override
public int run(String[] arg0) throws Exception {
// TODO Auto-generated method stub
Configuration conf = getConf();
fs = FileSystem.get(conf);
//FileStatus对象 用来获取文件或者目录的元数据
FileStatus[] sts = fs.listStatus(new Path(conf.get("path"))); //包装成 hadoop中 Path类型
//已经获得子目录的元数据
//针对每个file的元数据做操作
//操作--》判断该file是文件还是目录
//如果是目录,先展示 再继续进一步获取下一级file的元数据
//针对下一级的file的元数据,再做如上操作
//如果是文件 直接展示
for (FileStatus st : sts) { //用st来接收sts的值
doOp(st);
}
return 0;
}
private void doOp(FileStatus st) throws FileNotFoundException, IOException {
// TODO Auto-generated method stub
if(st.isDirectory()) {
showinfo(st);
FileStatus[] sts = fs.listStatus(st.getPath()); //获取路径 习惯: 要东西就是get*()
for (FileStatus s : sts) { //用st来接收sts的值
doOp(s);
}
}
else if(st.isFile()) {
showinfo(st);
}
}
private void showinfo(FileStatus st) {
// TODO Auto-generated method stub
System.out.println(
st.getPath().getName()+" "+
st.getOwner()+" "+
st.getLen());
}
}
Upload 上传数据
package shixun_hadoop;
import java.io.File;
import java.io.FileInputStream;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.util.Progressable;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
public class Upload extends Configured implements Tool{
static FSDataOutputStream out = null;
public static void main(String[] args) throws Exception {
ToolRunner.run(new Upload(), args); // ToolRunner来帮我们运行程序,运行Upload()这个程序,目的是为了从命令行传参,参数从args里来,包装给conf配置对象,Tool Runner来包装
//ToolRunner工具类的作用:帮我们运行程序,并且把命令行里面的参数封装到配置对象里面去
}
@Override
public int run(String[] arg0) throws Exception {
// TODO Auto-generated method stub
System.setProperty("HADOOP_USER_NAME", "briup"); //设置临时的用户值
Configuration conf = getConf(); //getconf()从父类中来。 为什么要用getconf()? 传递参数,每个参数前面都有名字,这个名字有conf来传递,
//所以不应由我们来创建而是由Hadoop来创建,Hadoop创建好了之后暴露给我们一个方法让我们调用就行
// 总的来说,通过配置对象传参,所以配置对象不应该由我们自己封装,而是由hadoop来封装。
conf.set("fs.defaultFS", "hdfs://192.168.xx.xxx:9000");
//获取文件系统
FileSystem fs = FileSystem.get(conf);
//输入流
File fl = new File(conf.get("inpath")); //之后要对文件进行操作,需要把文件变成一个对象,这样就可以对文件进行操作(下面是求文件大小)万物皆可对象
//在conf里面找一个value值为‘inpath’的。
FileInputStream in = new FileInputStream(fl);
//输出流
out = fs.create(new Path(conf.get("outpath")),new Progressable() { //匿名内部类(临时创建一个类)
@Override
public void progress() {
// TODO Auto-generated method stub
System.out.println((double)(out.size()/fl.length())); //写出数据的统计/文件的大小(用来显示进度)
}
});
IOUtils.copyBytes(in, out, 1024); //已经将循环的过程封装好了 攒到1024个字节再统一上传
in.close();
fs.close();
return 0;
}
}
//桥接 外网不同 虚拟机ip会改变
//主函数参数的作用
//万物皆可对象
采用 jar 包的形式 ,调用时参数可变
关于eclipse生成 jar包的步骤:
- 点击项目(我这边是shixun_hadoop)–》 右键 --》Run as --》 Maven install
控制台显示 BULID SUCCESS 即成功
- 刷新target文件夹 显示 shixun_hadoop-0.0.1-SNAPSHOT.jar
- 将shixun_hadoop-0.0.1-SNAPSHOT.jar 复制到虚拟机中
输入命令:
hadoop jar /home/briup/Desktop/shixun_hadoop-0.0.1-SNAPSHOT.jar shixun_hadoop.ShowFSTree -D path=/
Day06 12-15
MapReduce
时代背景:
爆炸性增长的Web规模数据量
超大的计算量/计算复杂度
解决之道——并行计算
并行计算:
有一个巨大的二维数据集; 1. 对每一条数据处理一致 ; 2. 数据块之间不存在数据依赖关系
并行计算:逻辑分块
MapReduce是目前业界和学界公认的最为有效和最易于使用的面向海量数据并行处理技术
MapReduce 是一种框架,大部份代码已经写好了,只需填写必要的部分代码。
MapReduce 借鉴了函数式程序设计语言Lisp中的思想,定义了如下的Map和Reduce两个抽象的编程接口
Map:做映射 key->value
摘取需要参与运算的字段
( 面向对象语言中,对象是承载数据的主体,对象用属性承载数据 )
Reduce:做规约(聚合)
实现对专利号被引用次数的统计
package com.briup.mapreduce;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
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.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
public class PatentRefCount extends Configured implements Tool {
public static void main(String[] args) throws Exception {
ToolRunner.run(new PatentRefCount(), args);
}
@Override
public int run(String[] arg0) throws Exception {
// 任务的配置
Configuration conf = getConf();
Job job = Job.getInstance(conf); //获得任务 一个mapreduce就是一个任务
job.setJarByClass(this.getClass()); //由于有两个内部类 指定系统其哪里获得类
job.setJobName("PatentRefCount");
//设置mapper
job.setMapperClass(PRMapper.class); //反射 设置我们写的类里面谁是map的数据
job.setMapOutputKeyClass(Text.class); //设置一下key的类型
job.setMapOutputValueClass(IntWritable.class); //value的类型
//设置reducer
job.setReducerClass(PRReducer.class);
job.setOutputKeyClass(Text.class); //设置输出的类型
job.setOutputValueClass(IntWritable.class); //设置输出的类型
//设置输入输出类型
job.setInputFormatClass(TextInputFormat.class);
job.setOutputFormatClass(TextOutputFormat.class);
//设置输入输出路径
TextInputFormat.addInputPath(job, new Path(conf.get("inpath")));
TextOutputFormat.setOutputPath(job, new Path(conf.get("outpath")));
//提交任务运行
job.waitForCompletion(true); //true 运行过程中打印进度
return 0;
}
//map阶段 泛型,用来约束类中使用的一些元素的类型
public static class PRMapper extends Mapper<LongWritable, Text, Text, IntWritable>{ //静态内部类
@Override
protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context) //输入大部份时间都是固定的LongWritable , Text; 输出部分靠自己定义
throws IOException, InterruptedException { //context 搬运
String[] infos = value.toString().split(",");
//过滤脏数据(这里省略了这步操作)
String id = infos[0];
String rid = infos[1];
context.write(new Text(rid), new IntWritable(1)); //将string类型的 rid包装成Text类型
//将 int 类型的 1 包装成IntWrite类型
}
}
//reduce阶段
public static class PRReducer 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 sum = 0;
for (IntWritable v : values) {
sum += v.get();
}
context.write(key, new IntWritable(sum)); //sum 是 int类型 将其包装成IntWritable类型
}
}
}
Day07 12-16
序列化:把结构化对象转化为二进制数据。 1. 数据持久化保存,2. 数据网络发送 (java对象通过互联网发送到另外的计算机上 等)
反序列化
Map–>Disk 序列化
Disk–>Reduce 反序列化
java语言提供了序列化的模块,如果使用java的包就不用再使用 Text、Writable,但是我们依然选择hadoop。
hadoop弃用java序列化框架的原因:
- java的序列化机制不可扩展,不可定义 。
- java序列化的框架是一个重量级的框架,序列化出来字节数据过大。
hadoop自己开发了一套框架
*核心接口Writeable (继承Writable接口,完成一些功能)
IntWritable LongWritable DoubleWritable Text …
统计不同气象局不同年份的最高温度
yearStation.java
package com.briup.mapreduce;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.WritableComparable;
/**
* @author kail
*
*/
//将年份和地点作为属性写入一个类中 由于这个类需要支持hadoop序列化机制,需要实现一个接口Writable
//同时需要做比较,故WritableComparable
public class yearStation implements WritableComparable<yearStation>{
private IntWritable year = new IntWritable();
private Text statid = new Text();
//无参构造器必须要
public yearStation() {
}
//方便我们去产生对象 (方便使用) 的构造器
//构造器是创建对象的标志, 但不是用来创建对象的
//是使用来为对象的属性赋值的
//(调用构造器之前,对象就已经在内存中存在,new关键字创建对象)
public yearStation(int year,String statid) {
this.year = new IntWritable(year); //new 不然会报空指针异常
this.statid = new Text(statid);
}
//反序列化
public void readFields(DataInput in) throws IOException {
year.readFields(in);
statid.readFields(in);
}
//序列化
public void write(DataOutput out) throws IOException {
year.write(out);
statid.write(out);
}
//1. 判断 key 值(自定义类型) 是否相等
//2. 定义key 值排序规则
public int compareTo(yearStation o) {
return this.year.compareTo(o.year) == 0 ?
this.statid.compareTo(o.statid) : this.year.compareTo(o.year);
}
//很多权限控制都是这样实现的
public IntWritable getYear() {
return year;
}
public void setYear(IntWritable year) {
this.year = new IntWritable(year.get()); // 目的是切断对象之间的联系,
//this.year = year; 会将地址值赋值给this.year
//参数year 改变,属性year也会改变
} //更改之后就是用get把值取出来再设置进去
public Text getStatid() {
return statid;
}
public void setStatid(Text statid) {
this.statid = new Text(statid.toString());
}
@Override
//reduce 输出的时候 key 输出形式
public String toString() {
return year.get()+" "+statid.toString();
}
}
MaxTempByYearStation.java
package com.briup.mapreduce;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
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.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
public class MaxTempByYearStation extends Configured implements Tool{
public static void main(String[] args) throws Exception {
ToolRunner.run(new MaxTempByYearStation(), args);
}
@Override
public int run(String[] arg0) throws Exception {
// 任务的配置
Configuration conf = getConf();
Job job = Job.getInstance(conf); //获得任务 一个mapreduce就是一个任务
job.setJarByClass(this.getClass()); //由于有两个内部类 指定系统其哪里获得类
job.setJobName("MaxTempByYearStation");
//设置mapper
job.setMapperClass(MYSMapper.class); // 设置我们写的类里面谁是map的数据
job.setMapOutputKeyClass(yearStation.class); //设置一下key的类型
job.setMapOutputValueClass(IntWritable.class); //value的类型
//设置reducer
job.setReducerClass(MYSReducer.class);
job.setOutputKeyClass(yearStation.class); //设置输出的类型
job.setOutputValueClass(IntWritable.class); //设置输出的类型
//设置输入输出类型
job.setInputFormatClass(TextInputFormat.class);
job.setOutputFormatClass(TextOutputFormat.class);
//设置输入输出路径
TextInputFormat.addInputPath(job, new Path(conf.get("inpath")));
TextOutputFormat.setOutputPath(job, new Path(conf.get("outpath")));
//提交任务运行
job.waitForCompletion(true); //true 运行过程中打印进度
return 0;
}
public static class MYSMapper extends Mapper<LongWritable, Text, yearStation, IntWritable>{
@Override
protected void map(LongWritable key, Text value,
Mapper<LongWritable, Text, yearStation, IntWritable>.Context context)
throws IOException, InterruptedException {
String line = value.toString();
String stationid =
line.substring(0, 15);
String year =
line.substring(15, 19);
String tmp =
line.substring(87, 92);
String qua =
line.substring(92,93);
if(qua.matches("[01459]")
&&!tmp.equals("+9999")) {
yearStation ys = new yearStation(Integer.parseInt(year),stationid);
context.write(ys, new IntWritable(Integer.parseInt(tmp)));
}
}
}
public static class MYSReducer extends Reducer<yearStation, IntWritable, yearStation, IntWritable>{
@Override
protected void reduce(yearStation key, Iterable<IntWritable> values,
Reducer<yearStation, IntWritable, yearStation, IntWritable>.Context context)
throws IOException, InterruptedException {
int max = 0;
for (IntWritable v : values) {
int cv = v.get();
if (cv > max) {
max = cv;
}
}
context.write(key, new IntWritable(max));
}
}
}
int i =1; int(基本数据类型)不是一个对象
Integer j = new Integer(i);包装成对象
mapreduce自己定义类使得其遵循hadoop序列化机制:
public class student implements Writable{
private int id; ==》 private IntWritable id = new IntWritable();
private String name; ==》
private float height; ==》
}
day08 12-17
Zookeeper
Zookeeper:Hadoop的分布式协调服务框架 (多进程协调 服务框架)
1. 进程状态的监控
2. 多进程之间的数据通信(应用较少)
3. 进程之间的调度,进程之间的同步和互斥运行
异步:两个线程互不干扰
同步:一个线程需要等待另一个线程,再一起运行
编程语言提供线程模块,能够很容易做到同步、互斥运行;进程之间,没有通用的框架,控制困难。
所以Zookeeper对于进程的调度显得非常重要。
Zookeeper为其他集群提供服务就行了,很少进行二次开发。
包含一个简单的原语集(原子操作)。
Zookeeper一般搭成奇数个数的集群,形成集群的目的是为了提高它的健壮性(崩了几台还能提供服务)。
事件驱动
三要素
事件源 事件对象 监听器
监听器一直观察事件源,当事件源发生事件
以一个 js 倒计时来说明
按钮(事件源,被监听)
做任何动作,信息都会被封装发到监听器,但是监听器只看click这个动作
zookeeper的安装以及验证
-
解压zookeeper压缩包
tar -zxvf zookeeper-3.4.10.tar.gz
-
设置软连接
ln -s zookeeper-3.4.10 zookeeper
-
更改配置文件
在这个conf文件夹下创建 zoo.fcg,内容:tickTime=2000 dataDir=/home/briup/software/data/zk/data dataLogDir=/home/briup/software/data/zk/dataLog clientPort=2181
-
为了方便,更改了环境变量,使得能够直接启动zookeeper。否则需要进到其bin目录中才能执行相应命令
重新加载配置文件
source ./bashrc
-
验证zookeeper安装
zkServer.sh start
(这里在bin下启动,如果完成了路径的配置,则可直接zkServer.sh start)jps
zkServer.sh status
谈一谈集群如何运行
rm:resourcemanager
nm:namenode
mr:mapreduce
AM:AppMaster
上述为一个yarn集群,一个主节点(rm),其余六个为nm。
有一个任务(mapreduce)提交过来,经由resource manager。resource manager会专门指派某一个nodemanager,让它变为AppMaster;再从当前的集群调几台出来,专门运行mapreduce。(遵循就近原则)
就近原则:Hdfs集群和yarn集群在物理空间上重叠,所有进程都搭在同一套机器上。mapreduce处理的数据块在哪些Hdfs的节点上,就去看这些节点上有没有对应的nodemanager,如果有,那就调出来进行使用。
mapreduce提交上来后,resourcemanager会找一个作为临时产生集群的主节点(AppMaster),用来监控当前mapreduce的运行情况,通过就近原则挑选出来若干个namenode,在这些namenode中拿取一定的资源(有些namenode所对应的datanode在本次运算中所持有的数据分块比较多,那么在这个namenode上可能会开启两个或多个进程;而对于数据分块较少的,那就在这些namenode上拿取资源比较少)。
图中红色矩形就是Container,代表一定的资源总数(eg:每个Containter拿了多少个Cpu,多少个内存)。
有红框的节点参与本次mapreduce运算,没有的就不参与本次运算。 相当于临时产生了一个子集群,只用来运行当前的mapreduce。
红框中有些运行的是map阶段,有些运行的是reduce阶段(主要靠AppMaster分配,一般运行map的比较多),mapreduce运行完成之后由resourcemanager进行控制,把资源回收。
shuffle 过程
shuffle相当于 map任务结束尾端工作和reduce的开始的工作。
shuffle有三个步骤: 分区、分组、排序。(排序不算单独的步骤,排序参杂在分区和分组中)
分区:决定map输出的结果(键值对)进入到哪一个reduce中进行运算的过程。
分组:每个reduce内部k值相同的小块合并成一个大块。
假设两个数据块,发起两个Map进程读取,读完之后数据输出到localFs(每个Map任务输出的数据在本地,自己的硬盘上)。
map输出的结果进入一块环形缓存,写满后统一刷写到磁盘上(写满了往外写,生成一块文件块,数据一般杂乱无章)。
进行map端的局部聚集,将当前数据块中k值相同的整理成小的数据分块。
用k值计算哈希值,对于reduce的个数取余,余数就代表编号,来决定k值进入哪个reduce。 调用reduce()(方法),排队进入。
最后生成结果文件(每个reduce进程都会生成结果文件)。
排序融合在分区和分组中,一边分区一边排序,一般认为是分区内的排序。即区内排序和组内排序。
集群会在map结束和reduce开始之间设置路障,来控制reduce晚点运行(数据处理有快慢, 需要等待所有map数据处理完之后reduce才能运行);但是在高版本中已经不存在了,我们可以设置域值,假如所有的map数据运行到60%总量,reduce可以开始运行,也不会耽误结果的生成,因为高版本中采用了一些算法,来保证数据正常。
图中map进程和reduce进程(红色边框),就是上上图中的map和reduce
day09 12-18
HBase
nosql数据库 非关系型数据库 (在数据库中 关系就是二维表)
HBase是四维的,即需要四个参数来确定一个值。
特性:
- very large tables – billions of rows X millions of columns
- random, realtime read/write access
- distributed
- non-relational database
- Easy to use Java API for client acces
Hbase操作环境:
- Hbase runs on Hadoop
- Using HDFS as its file storage system
- Using Zookeeper as a collaborative service
范式,决定性的原因就是为了节约空间。
但是Hbase不遵循范式,四维的不需要遵循二维的东西,因此Hbase会将数据直接往行键上写,以此来提高查询速度。
新兴行业中(弹幕,直播等)一般是多种数据库混合使用(关系型数据库,非关系型数据库);传统行业关系型数据库居多。
Hbase
非关系型数据库
面向列族数据库(列祖是重点的操作单位,所以叫面向列族)
面向键值对数据库(本身的结构就是由键值对组成)
Hbase安装
- 解压
tar -zxvf hbase-1.2.6-bin.tar.gz - 创建软链接
ln -s hbase-1.2.6 hbase
- 更改配置文件
vi software/hbase/conf/hbase-site.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!--
/**
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<configuration>
<property>
<name>hbase.rootdir</name>
<value>hdfs://hadoopPD:9000/hbase</value>
</property>
<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>/home/briup/software/data/hbase/zk_data</value>
</property>
<!-- <property>
<name>hbase.unsafe.stream.capability.enforce</name>
<value>false</value>
</property> -->
<property>
<name>hbase.zookeeper.quorum</name>
<value>hadoopPD:2181</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
</configuration>
vi software/hbase/conf/hbase-env.sh
28 export JAVA_HOME=/home/briup/software/jdk1.8.0_181
29 export HBASE_MANAGES_ZK=true
30 #export HBASE_MANAGES_ZK=false
31 export HBASE_LOG_DIR=/home/briup/software/data/hbase/logs
32 export HBASE_PID_DIR=/home/briup/software/data/hbase/pids
*4 vi ~/.bashrc
5. hdfs dfs -mkdir /hbase
6.
hbase-daemon.sh start master
hbase-daemon.sh start regionserver
jps
7. ip:16010
关于 Hbase&Hdfs&zookeeper 之间的关系
当在一台机器上无法存储,会将表按行切成多个region(在变化时:0~512M,稳定后:256M),存放在regionserver,底层对接hdfs。
Hbase集群,存在主从结构,从节点regionserver,主节点Master。(进程名叫Hregionserver、HMaster)
从节点中存放region。
region会通过Hdfs进行存储,于是这些region会按照Hdfs的规则继续被切成小块。region大小和block大小无关,region的大小是逻辑数据,而block中的数据存放的数据块。
帮我们查找数据的关键步骤,由zookeeper决定。
Hbase相关进程作用:
1、协调服务组件Zookeeper
Zookeeper的作用如下:
1. 保证任何时候,集群中只有一个HMaster;
2. 存储所有的HRegion的寻址入口;
3. 实时监控HRegionServer的上线和下线信息,并实时通知给HMaster;
4. 存储HBase的schema和table元数据;
5. Zookeeper Quorum存储-ROOT-文件地址、HMaster地址。
2、主节点HMaster
HMaster的主要功能如下:
1. HMaster没有单节点问题,HBase中可以启动多个HMaster,通过Zookeeper的Master Election机制保证总有一个Master在运行,主要负责Table和Region的管理工作。
2. 管理用户对表的增删改查操作;DML
3. 管理HRegionServer的负载均衡,调整Region分布(在命令行里面有一个tools,tools这个分组命令其实全部都是Master做的事情);
4. Region Split后,负责新Region的分布;
5. 在HRegionServer停机后,
负责失效HRegionServer上Region迁移工作。
3、Region节点HRegionServer
HRegionServer的功能如下:
1. 维护HRegion,处理HRegion的IO请求,向HDFS文件系统中读写数据;
2. 负责切分运行过程中变得过大的HRegion;
3. Client访问HBase上数据的过程并不需要Master参与(寻址访问zookeeper和HRegionServer,
数据读写访问HRegionServer)
day10 12-19
hbase shell
$HADOOP_USER_NAME
// 环境变量 hbase和hadoop一样,只看用户名,跟密码无关 命令会首先查找环境变量中的用户名,如果没有,采用当前用户的用户名
#创建命名空间
create_namespace ‘bd1902’
#展示所有命名空间
list_namespace
#删除命名空间,The namespace must be empty.
drop_namespace ‘bd1902’
create ‘t1’, ‘f1’, ‘f2’, ‘f3’ //第一个解析成表名,后面的都解析成列族名
create ‘t1’, {NAME => ‘f1’}, {NAME => ‘f2’}, {NAME => ‘f3’}
#创建一张表,指定列族版本号为3
create ‘bd1902:student’, ‘baseinfo’, ‘extrainfo’
create ‘bd1902:student1’, {NAME => ‘baseinfo’, VERSIONS => 3},{NAME => ‘extrainfo’,VERSIONS => 5}
#查看表结构
describe ‘bigdata:test1’
//查看表结构,一般我们对version进行修改。未修改前是一张三维表,修改version后变为四维表。
hbase 热点问题,数据倾斜
写操作
1 默认分区
2 rowkey递增
如何避免:表进行预分区操作 行键随机产生(hash)
1 预分区 建表
2 随机产生rowkey hash MD5 SHA256
解释一下热点效应:
假如默认设置region 128M,空表中的数据会逐渐增大,增大到接近256M时,找一条中间的行键,region一分为二,上面的region128M,下面的region继续增长。当region增长到256M时,再次一分为二…
这是一种正常的情况,但是在某些特殊情况下,会出现问题:如果以这种默认形式生成region,并且行键(rowkey)递增,意味着所有的写操作都集中在新的region上,region作为存贮单位存储在一台机器上,因此所有的写操作都会集中在一台机器上,如果突然来了大批量的数据进行写入,机器就会崩溃。
#创建表,预定义分区,在rowkey为0<= <10 10<= 20 20<= 30
create ‘bd1902:student2’, {NAME=>‘baseinfo’,VERSIONS=>3}, SPLITS => [‘1000’, ‘2000’, ‘3000’, ‘4000’]
//运用后缀进行分区
create ‘bd1902:student2’, {NAME=>‘baseinfo’,VERSIONS=>3}, SPLITS => [‘1000|’, ‘2000|’, ‘3000|’, ‘4000|’]
《==》create ‘bd1902:student2’, {NAME=>‘baseinfo’,VERSIONS=>3}, SPLITS => [‘1000~’, ‘2000~’, ‘3000~’, ‘4000~’]
//运用前缀进行分区(常用)
#创建表,分区标准在文件中,如果rowkey以0001等开头,进行分区使用| 或者 ~ 帮助划分rowkey区域,文件放在进入hbase shell 的目录下
create ‘bd1902:employee4’,‘baseinfo’,{SPLITS_FILE => ‘/home/hbase/sps.txt’}
create ‘bd1902:employee4’, ‘baseinfo’, SPLITS_FILE => ‘sps.txt’
#使用HexStringSplit算法进行分区,分成10个region,适合散列字符不包含中文,适合16进制的rowkey或者前缀是16进制的rowkey //Hex 十六进制
create ‘bd1902:student4’, ‘baseinfo’, {NUMREGIONS => 10, SPLITALGO => ‘HexStringSplit’}
#使用UniformSplit算法进行分区,rowkey可以包含中文,适合随机字节数组rowkey
create ‘bd1902:student5’, ‘baseinfo’, {NUMREGIONS => 5, SPLITALGO => ‘UniformSplit’}
JRuby 变量
#create 返回引用值
t1 = create ‘t1’, ‘f1’
#修改表结构–增加列族
alter ‘bd1902:student’, {NAME => ‘extrainfo’, VERSIONS => 5}, {NAME => ‘secret’, VERSIONS => 5}
#修改表结构–删除列族
alter ‘bd1902:student’, {METHOD => ‘delete’,NAME => ‘baseinfo’}
#插入数据 更新
Cell
put ‘ns:t’,‘r’,‘cf:q’,‘v’[,‘t’]
put ‘bd1902:student1’,‘3001’,‘baseinfo:name’,‘Larry’
put ‘bd1902:student1’,‘3001’,‘baseinfo:gender’,‘male’
put ‘bd1902:student1’,‘3001’,‘baseinfo:age’,‘60’
put ‘bd1902:student1’,‘3001’,‘baseinfo:pos’,‘CEO’
scan ‘bd1902:student1’
put ‘briup:employee3’,‘2000’,‘baseinfo:name’,‘tom’
#插入指定timestamp
put ‘hbase_test:teacher5’,‘100000000’,‘extrainfo:salary’,‘5000’,1488888888888
get scan
get 单行数据
scan 多行数据 条件=过滤器
#获得某一个特定值
get ‘t1’, ‘r1’, [‘c1’, ‘c2’]
get ‘bigdata:test1’,‘10’,‘baseinfo:name’
#获得前5个版本的数据
get ‘bd1902:student1’,‘1001’,{COLUMN => ‘baseinfo:name’,VERSIONS => 5}
#获得某个时间段数据,不一定是时间最新的数据
get ‘hbase_test:teacher2’, ‘10001’, {TIMERANGE => [1479371084728, 1479373228331]}
#scan 扫描某张表 select *
scan ‘bd1902:student1’
#scan 扫描 表中某一列
scan ‘test1:student5’,{COLUMNS=>‘baseinfo:name’}
#scan 使用limit 进行行数限制
scan ‘test1:student5’,{COLUMNS=>‘baseinfo:name’,LIMIT=>2,STARTROW=>‘20001’}
//LIMIT一般结合STARTROW,表示从20001行开始显示2行(分页)
#scan 指定从某一行开始扫描
scan ‘hbase_test:teacher2’,{COLUMNS=>‘baseinfo:name’,LIMIT=>2,STARTROW=>‘20001’}
#scan 扫描所有版本
scan ‘bd1902:student1’,{VERSIONS => 5}
#在hbase 对于hfile没有进行过合并操作之前
#scan 超出版本限制也能访问到
scan ‘briup:employee3’,{VERSIONS=>5,RAW=>true}
#scan 使用过滤器 行健前缀过滤器,只有这一个有属性
scan ‘bd1902:student1’, {ROWPREFIXFILTER => ‘20’}
#scan 使用空值行健过滤器,只返回行健
scan ‘bd1902:student1’,
{FILTER=>‘KeyOnlyFilter()’}
scan ‘bd1902:student1’,{FILTER=>“RowFilter(>,‘binary:2000’)”}
scan ‘bd1902:student1’,{FILTER=>"ColumnPrefixFilter(‘na’) "}
说明文档 hbase/docs/apidocs/index.html
1 数值 数字
2 CompareFilter.CompareOp
比较符 > < >= !=
3 ByteArrayComparable binary:1000 substring:
(binary:1000表示行键值1000)
4 byte[] ‘’
scan ‘bd1902:employee1’,{FILTER=>“RowFilter(>,‘binary:1001’)”}
(行键值大于1001)
#scan 使用行健过滤器,binary: 帮助数据类型转化
scan ‘hbase_test:teacher2’,{FILTER =>“RowFilter(!=,‘binary:10001’)”}
#scan 使用列名过滤器
scan ‘test1:student5’,{FILTER =>“QualifierFilter(>=,‘binary:baseinfo:name’)”}
#scan 使用子串过滤器
scan ‘test1:student5’,{FILTER =>“ValueFilter(=,‘binary:zhao’)”}
#列名前缀过滤器
scan ‘test1:student5’,{FILTER =>“ColumnPrefixFilter(‘name’)”}
#scan 使用多种过滤器进行条件结合
scan ‘hbase_test:teacher2’,{FILTER =>"(ValueFilter(=,‘binary:hello’)) OR (RowFilter (>,‘binary:10’))"}
#scan 使用page过滤器,限制每页展示数量
scan ‘bigdata:test1’,{FILTER =>org.apache.hadoop.hbase.filter.KeyOnlyFilter.new()}
#scan 使用行健过滤器,进行正则表达式的匹配
scan ‘bd1902:student1’, {FILTER => org.apache.hadoop.hbase.filter.RowFilter.new(org.apache.hadoop.hbase.filter.CompareFilter::CompareOp.valueOf(‘EQUAL’),org.apache.hadoop.hbase.filter.RegexStringComparator.new(’.3.’))}
//-----------------------
#删除数据
delete ‘t1’, ‘r1’, ‘c1’, ts1
delete ‘bd1902:student1’,‘2002’,‘baseinfo:name’
truncate ‘t1’
#disable 某张表 //先disable再drop
disable ‘bigdata:test1’
#删除某张表
drop ‘bigdata:test2’
#大合并 hfile
major_compact ‘583b13b5efb36a6ae7794d7e60b4c3a8’
major_compact ‘bigdata:test2’
#小合并
#移动region
move ‘ENCODED_REGIONNAME’, ‘SERVER_NAME’
#第一个参数指的是region最后一部分编号(逗号分隔每部分)
move ‘a39dc69bd00d19e556ae17e4aeb1ebe1’,‘datanode02,16020,1479354142616’
// 行过滤器
// 1 行健范围
ByteArrayComparable com1 = new BinaryComparator(Bytes.toBytes(“briup004”));
RowFilter rf1 = new RowFilter(CompareOp.LESS, com1);
// 2 行健子串范围
ByteArrayComparable com2 = new SubstringComparator(“007”);
RowFilter rf2 = new RowFilter(CompareOp.EQUAL, com2);
// 3 某个列标示符的值范围
SingleColumnValueFilter scf1 = new SingleColumnValueFilter
(Bytes.toBytes(“infos”), Bytes.toBytes(“name”), CompareOp.LESS_OR_EQUAL, Bytes.toBytes(“张三”));
// 4 匹配正则表达式
ByteArrayComparable com3 = new SubstringComparator(“test.”);
SingleColumnValueFilter scf2 = new SingleColumnValueFilter
(Bytes.toBytes(“infos”), Bytes.toBytes(“name”), CompareOp.EQUAL,com3);
// 5 匹配子串 不区分大小写
ByteArrayComparable com4 = new SubstringComparator(“te”);
SingleColumnValueFilter scf3 = new SingleColumnValueFilter
(Bytes.toBytes(“infos”), Bytes.toBytes(“name”), CompareOp.EQUAL,com4);
-----------------------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------------------
左右代表两种不同的操作,客户端不同。
左半边客户端–>zookeeper–>集群 ,一般表示java代码
右半边通过HMaster直接进入 , 一边表示命令行
每一个region内部有多个Store,按列族切(对于我们来说透明,它自己知道)。每一个列族里面都会有一个MemStore(缓存),当这个缓存写满之后就会刷写成StoreFile(也叫HFile,硬盘上的文件),通过DFS Client(HDFS客户端)存放到HDFS中。
查询
数据库越用会越快
查找 blockcache(Hbase内部组织的一种块缓存(内存),存放当前你频繁查询的数据以及这些数据前后几条数据)
查找 memstore, 看一看我要查询的数据是不是刚刚插入的数据
二级寻址