Hadoop

HDFS存储数据

hdfs操作指令(Linux) hadoop fs

1.查看文件
hadoop fs -ls / 或hdfs dfs -ls /
2.创建文件夹
hadoop fs -mkdir /hdfs01
3.移动或重命名
hadoop fs -mv /data /hadf01
hadoop fs -mv /data /data_blk
4.复制
cp [-p] …
hadoop fs -cp -p /data /hdfs01文件夹
5.删除
[-rm [-f] [-r|-R] [-skipTrash] …]
hadoop fs -rm -r /data 文件夹
生产上一般开启回收站 回收站有效期至少七天以上 fs.trash.interval 10080
stop-dfs.sh
vim core-site.xml

fs.trash.interval
10080

start-dfs.sh
6.上传
hadoop fs -put ./wc.data /
hadoop fs -copyFromLocal ./wc.data /
7.下载
hadoop fs -get /data ./
hadoop fs -copyToLocal /data ./
8.修改权限
hadoop fs -chmod 664 /1.log
9.修改拥有者
hadoop fs -chown uzi:DL2262 /1.log
10.查看文件内容
hadoop fs -cat /1.log
补充:
查看hdfs上的文件:
hadoop fs -ls hdfs://bigdata13:9000/1.log
hadoop fs -ls /1.log
查看Linux文件:
hadoop fs -ls file:home/hadoop/1.log

hdfs指令(java)

建idea项目时在pom.xml上添加

<dependency>
  <groupId>org.apache.hadoop</groupId>
  <artifactId>hadoop-client</artifactId>
  <version>3.3.4</version>
</dependency>
    @Test
    public void mkdir() throws Exception {
        // 创建文件夹
        Configuration conf = new Configuration();
        // 获取程序入口
        conf.set("fs.defaultFS","hdfs://bigdata13:9000");
        System.setProperty("HADOOP_USER_NAME","hadoop");
        FileSystem fs = FileSystem.get(conf);
        Path path = new Path("/hdfsapi01");
        boolean mkdirs = fs.mkdirs(path);
        Assert.assertEquals(true,mkdirs);
    }
    @Test
    public void put() throws Exception{
        // 上传
        Configuration conf = new Configuration();
        conf.set("fs.defaultFS","hdfs://bigdata13:9000");
        System.setProperty("HADOOP_USER_NAME","hadoop");
        FileSystem fs = FileSystem.get(conf);
        Path src = new Path("data/wc.data");
        Path dst = new Path("/");
        // 上传并删除上传文件 允许覆盖
        fs.copyFromLocalFile(true,true,src,dst);
    }
    FileSystem fs = null;
    @Before
    public void setup() throws Exception{
        Configuration conf = new Configuration();
        conf.set("fs.defaultFS","hdfs://bigdata13:9000");
        System.setProperty("HADOOP_USER_NAME","hadoop");
        fs = FileSystem.get(conf);
    }
    @After
    public void teardown() throws Exception{
        if (fs != null){
            fs.close();
        }
    }
    @Test
    public void pull() throws Exception{
        // 下载
        Path src = new Path("/data");
        Path dst = new Path("data");
        fs.copyToLocalFile(src,dst);
    }
    @Test
    public void mv() throws Exception{
        // 移动
        Path src = new Path("/wc.data");
        Path dst = new Path("/hdfsapi01");
        fs.rename(src,dst);
    }
    @Test
    public void mv01() throws Exception{
        // 改名
        Path src = new Path("/hdfsapi01/wc.data");
        Path dst = new Path("/hdfsapi01/wc.data_blk");
        fs.rename(src,dst);
    }
    @Test
    public void rm() throws Exception{
        // 递归删除
        Path src = new Path("/hdfsapi01/wc.data_blk");
        fs.delete(src,true);
    }
    @Test
    public void cp() throws Exception{
        Path src = new Path("/data/wc.data");
        FSDataInputStream inputstream = fs.open(src);
        Path dst = new Path("/data/wc_blk.data");
        FSDataOutputStream outputstream = fs.create(dst);
        IOUtils.copyBytes(inputstream,outputstream,4096);
        IOUtils.closeStream(outputstream);
        IOUtils.closeStream(inputstream);
    }
    @Test
    public void ls() throws Exception{
        Path path = new Path("/");
        RemoteIterator<LocatedFileStatus> listfile = fs.listFiles(path, true);
        while (listfile.hasNext()){
            LocatedFileStatus filestatus = listfile.next();
            String filename = filestatus.getPath().getName();
            long len = filestatus.getLen();
            FsPermission permission = filestatus.getPermission();
            String owner = filestatus.getOwner();
            String group = filestatus.getGroup();
            long modificationTime = filestatus.getModificationTime();
            System.out.println(filename + '\t' + len + '\t' + permission +'\t' + owner +'\t' + group + '\t' + modificationTime);
        }
    }

参数设置的优先级

1.默认配置文件
	core-default.xml
	hdfs-default.xml
	mapred-default.xml
	yarn-default.xml
2.生产配置文件
	core-site.xml
	hdfs-site.xml
	mapred-site.xml
	yarn-site.xml
3.代码里面设置的参数
	 Configuration
优先级排序:代码里面设置的参数 > 生产配置文件 > 默认配置文件

例题

1.使用java api 操作 hdfs在 创建文件夹
/data/dt=20221114
/data/dt=20221115
/data/dt=20221116
2.使用java api 上传本地 wc.txt 到上面三个目录下
3.使用java api 将
/data/dt=20221114/wc.txt
/data/dt=20221115/wc.txt
/data/dt=20221116/wc.txt
目录下的文件移动到 指定目录 并进行改名字
/data/hive/20221114-01.data
/data/hive/20221115-01.data
/data/hive/20221116-01.data

 		String hdfspath = args[0];
        String localpath = args[1];
        String filename = args[2];
        String renamepath = args[3];
        String renameusfname = args[4];
        String dt = args[5];
        // 获取程序入口
        Configuration conf = new Configuration();
        conf.set("fs.defaultFS","hdfs://bigdata13:9000");
        System.setProperty("HADOOP_USER_NAME","hadoop");
        FileSystem fs = FileSystem.get(conf);
        // 创建文件夹
        fs.mkdirs(new Path(hdfspath+dt));
        // 上传
        fs.copyFromLocalFile(new Path(localpath+"/"+filename),new Path(hdfspath+dt));
        // 改名字
        // 判断文件夹是否存在
        if (!fs.exists(new Path(renamepath))){
            fs.mkdirs(new Path(renamepath));
        }
        fs.rename(new Path(hdfspath+dt+"/"+filename),new Path(renamepath+"/"+dt+renameusfname));
        // 关闭资源
        if (fs != null){
            fs.close();
        }

可以在idea里一个一个的添加参数,参数之间用空格进行分隔
在这里插入图片描述
在这里插入图片描述
也可以把程序打成夹包,把夹包拽到xshell里面
在这里插入图片描述
在这里插入图片描述
然后输入hadoop jar /home/hadoop/project/hdfsApi04-1.0.jar com.bigdata.HomeWork01
“/data/dt=” “file:home/hadoop” “1.log” “/data/flink” “-01.data” “20221117” 运行代码
还可以写一个脚本
vim start.sh

if [ $# -lt 6 ];then 
	echo "Usage:put file to hdfs"
	echo "Usage:$0 <hdfspath> <localpath> <filename> <renamepath> <suffname> <dt>"
	echo "Usage:<hdfspath> is hdfs path"
	echo "eg:$0 '/data/dt=' 'file:home/hadoop' '1.log' '/data/flink' '-01.data' '20221117'"
	exit;
fi
hadoop jar /home/hadoop/project/hdfsApi04-1.0.jar \
com.bigdata.HomeWork01 \
"${1}" "${2}" "${3}" "${4}" "${5}" "${6}"

chmod u+x start.sh
./start.sh ‘/data/dt=’ ‘file:home/hadoop’ ‘1.log’ ‘/data/flink’ ‘-01.data’ ‘20221117’

HDFS架构设计以及各个角色的作用

hdfs是主从架构主从架构–一个namenode,多个datanode
生产上用两个namenode,高可用设计模式
当一个namenode突然挂掉了,另一个namenode马上顶上去实时切换
snn nn 冷备 因为snn是定期拿镜像文件和编辑日志进行合并备份和推送给nn dfs.namenode.checkpoint.period 3600s 1h 会导致有一个空档期1h,在这个期间,上传文件即使成功了也检查不到,会间接导致文件丢失
dfs.namenode.checkpoint.txns 1000000 100w 每有一百万个文件块产生就会触发snn拿编辑日志和镜像文件进行合并
举例:
11:00 snn nn 存储hdfs上所有文件的元数据是一致的全的
11:30 nn挂了 此时有新增文件上传 编辑日志没有记录 会导致即使文件上传了,但是客户端查不到
12:00 snn进行合并日志 此时nn和snn又保持了一致,但查不到新上传的文件
nn nn 实时热备 一台对外提供服务,一台等待stand by,万一工作的那台namenode挂了,另一台会马上接替它的工作

namenode: 名称节点 nn
1.负责存储metadata元数据–描述数据的数据–文件名称、文件的目录结构、文件的属性、权限、创建时间、副本数据等
2.负责 映射块文件–一个文件被切分成多少个数据块,以及数据块对应在哪些节点上存储 the mapping of blocks to DataNodes
作用:
1.管理文件系统的命名空间–其实就是维护文件系统树的文件和文件夹 manage the file system namespace
是以镜像文件fsimage和编辑日志文件editlogs(已经写好的和正在写的)两种文件永久的保存在本地磁盘上
2.namenode对外提供服务(客户端要访问HDFS上的文件必须经过namenode同意)regulate access to files clients

secondery namenode: 第二名称节点 snn
定期拿取镜像文件和编辑日志文件(正在写的)进行合并,备份并推送给namenode
fsimage216+editlogs217=>fsimage217=>namenode

datanode:数据节点 dn
每个分布式都有datanode
serve read and write request from the file system’s clients负责文件的读写(具体干活)
1.存储数据块 store in datanodes和数据块的校验(时时刻刻记录文件变化,把发生的变化记录在镜像文件和编辑文件日志里)
作用:
1.每隔三秒发送一次心跳给namenode告诉namenode我还活着 dfs.heartbeat.internal 3s
2.每隔一定时间发送一次块报告
块映射不会永久持久化这个存储
是通过集群启动和运行时,datanode定期发送块报告给namenode来进行动态维护这种映射关系(存在内存中)dfs.blockreport.intervalMsec 21600000ms 6h
dfs.datanode.directoryscan.interval 21600s 6h 每隔6h扫描磁盘和内存中的块进行比较,判断块有没有进行更新
发送块报告的目的:
因为生产上可能会发生文件块丢失或损坏,就是通过datanode每隔6h是扫描判断块是否发生丢失或损坏

hdfs存储时block

block取决于块大小blocksize含有多少个128M和副本数 伪分布式 1
完全分布式 3(大于等于3时)
160M 2个副本 (1)文件在hdfs上存了多少个块?
(2)实际存储到hdfs 存储的大小是多少?
160M:128M => 1 32M => 1
(1)1+1 =2 块 * 2 = 4个块
(2)160M * 2 = 320M

日志级别

日志是一行一行打印的,有时候看见的换行是显示问题
(1)info:这个级别日志多
(2)warn:这个级别日志偏少,但不耽误使用
(3)error:这个级别日志更少,但需要解决

HDFS写流程【面试】

1.客户端调用程序入口FileSystem.create(filrpath)去和namenode通过RPC协议进行通信
namenode会去检查要上传的文件是否已经存在,并且会去检查客户端是否有权限去访问,只有当要上传的文件不存在且客户端有权限访问时,才能创建一个新的文件。但这时还没有写数据,所以是不关联任何block的
namenode会根据客户端要上传文件的大小以及块的大小和副本参数,计算出要上传多少块和块存储在datanode的位置
最终将这些信息以FSDataOutputStream对象返回给客户端
2.拿到信息后,客户端会调用FSDataOutputStream对象的write方法,将文件的第一个块的第一个副本写到第一个datanode节点,第一个副本写完后去第二个datanode节点写第二个副本,第二个副本写完后再去第三个datanode节点写第三个副本,当第三个副本写完时就返回一个ack的确认包给datanode2节点,当datanode2节点接收到这个ack确认包并且自己也写完之后会返回一个ack确认包给datanode1节点,当datanode1节点接收到这个ack确认包并且自己也写完之后会返回给FSDataOutputStream对象一个ack确认包,此时表示第一个块的三个副本写完了。剩余文件块也按照这个方式进行写入。
3.当所有的文件块都写完之后,客户端会调用FSDataOutputStream对象的close方法告知namenode文件已经全部写入完成。

HDFS读流程【面试】

hdfs读写流程对用户操作是无感知的
1.客户端调用程序入口FileSystem.open(filrpath)的open方法和namenode进行RPC通信,namenode会以FSDataInputStream对象返回要读文件部分或全部的块列表(要读取的块具体在哪些datanode上面)
2.客户端通过调用FSDataInputStream对象的read方法,去与第一个块最近的datanode进行读取,读取完成会检查是否读取成功,如果读取成功就关闭与datanode的通信,如果读取失败会记录所读机器的datanode节点和块信息(标记该节点已经挂了),下次就不会从该节点读取信息,并且从第二个节点读取信息,如果读取成功就关闭通道,如果读取失败就从第三个节点读取信息,当第一个块读取成功后,然后会去与第二个块最近的datanode进行读取,以此类推。当块列表读取完成后,文件还没有全部读取时会继续调用FileSystem从namenode获取下一个批次的块列表,以此类推。
3.当全部读取完毕后,客户端会调用FSDataInputStream对象的close方法关闭输入流。

HDFS副本放置策略【面试】【机架】

读写操作会选择datanode节点进行读取
第一副本:放置在客户端上传的datanode节点
当客户端不在datanode节点时,就会随机选择一个datanode节点
第二个副本:放置在与第一个副本不同机架上的某个datanode节点
第三个副本:放置在与第二个副本相同机架上的不同datanode节点
如果副本数设置超过三个,其他副本就随机放置在不同的datanode节点

HDFS安全模式

1.什么时候会发生安全模式?
(1)启动hadoop
(2)HDFS故障【集群文件块大量丢失,说明集群不稳的,会进入安全模式】
(3)我们认为主动进入安全模式:业务场景有关 集群维护
2.进入安全模式对业务有什么影响?
读文件:可以
写文件:不可以
3.相关命令:hdfs dfsadmin -safemode <enter进入安全模式 | leave退出安全模式 | get查看安全模式状态 | wait | forceExit>

Linux kill 杀死进程号 -num pid

kill -9 发送信号给进程 告诉进程 你被终结了 请立刻退出
kill -15 发送信号给进程 告诉进程 你需要被关闭 请自行停止运行并退出
mysql :
查询进程 show processlist;
杀死进程 kill id;
创建数据库时 比如hive 创建一个hive用户
创建数据库流程:
create database dl2262;
grant all privileges on dl2262.* to dl2262 identified by ‘123456’;
flush privileges;

如何查看HDFS块是否丢失?hdfs fsck /

HDFS块丢失该怎么解决?
(1)不用解决 hdfs高容错 多副本情况下 datanode–6h
(2)手动进行恢复丢失的数据块
hdfs debug recoverLease -path [-retries num]

MapReduce数据分析计算

以并行方式(多个task)处理大量数据可以部署在廉价的机器上以容错的方式运行
hdfs容错体现在副本数上,mp容错体现在task上,重试机制,当一个task挂掉时,再重新启动一个task完成刚才挂掉task的任务
适用于离线数据计算,不适用于流式数据计算
mapreduce先从hdfs上获取数据然后经过map阶段和reduce阶段对数据进行处理,最后输出
mapreduce流程:
(input)<k1,v1> -> map-><k2,v2> -> reduce-><k3,v3> (output)<k3,v3>
整个阶段都是对kv进行开发,每个阶段输出都是kv,并且kv数据类型必须要被序列化
把磁盘上的文件读取到内存中的过程叫序列化 把内存上的文件写到磁盘的过程叫反序列化
kv数据类型都要实现了Writable接口,此外key的数据类型还要实现WritableComparable接口
key要实现序列化+排序 value只要实现序列化即可
String:Text
数值:intWritable longWritable flaotWritable doubleWritable等待
Text和intWritable longWritable flaotWritable doubleWritable等待均实现了WritableComparable

以mapreduce为例分析wordcount

input: 文件里面的数据 一行一行的读取 a,a,a,a k是行号
b,b,b,b v是每行数据
map:一一映射 y=f(x) 按照分隔符进行拆分 每个单词赋值为1
(a,1) (a,1) (a,1) (a,1) (b,1) (b,1) (b,1) (b,1)
k表示的是单词 v表示的是次数

reduce:规约、聚合
把相同的key“拉到一起”这个过程就是shuffle “做一些事情”
“拉到一起” shuffle(a,<1,1,1,1>) (b,<1,1,1,1>)
“做一些事情” (a,4) (b,4)

wc案例:mapreduce模板
1.mapper:map阶段代码
2.reducer:reduce阶段代码
3.dirver:定义如何启动map和reduce
map阶段:mapper<KEYIN,VALUEIN,KEYOUT,VALUEOUT>
KEYIN:输入数据key的数据类型
VALUEIN:输入数据value的数据类型
KEYOUT:输出数据key的数据类型
VALUEOUT:输出数据value的数据类型
map阶段的输出作为reduce阶段的输入

// 将待处理或处理好的kv存进集合中
package com.bigdata;
import java.util.HashMap;
import java.util.Map;
public class Context {
    Map cacheMap = new HashMap();
    public void write(Object key,Object value){
            cacheMap.put(key, value);
    }
    public Object get(Object key){
        return cacheMap.get(key);
    }
}
package mapreduce;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
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.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
/**
 * driver阶段
 */
public class WCAPP {
    public static void main(String[] args) throws Exception {
        if (args.length < 2){
                System.err.println("Usage:WCAPP <in> <out>");
                System.exit(2);
        }
        String input = args[0];
        String output = args[1];
        //String input = "src/data/wc.data";
        //String output = "out";
        Configuration conf = new Configuration();
        FileUtils.deletePath(conf,output);
        // 设置作业名称
        Job job = Job.getInstance(conf, "WCAPP");
        // 设置map、reduce代码执行的主类在哪
        job.setJarByClass(WCAPP.class);
        job.setMapperClass(MyMapper.class);
        job.setReducerClass(MyReducer.class);
        // 指定output的kv类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);
        // 设置数据源路径和数据输出路径
        FileInputFormat.addInputPath(job,new Path(input));
        FileOutputFormat.setOutputPath(job,new Path(output));
        // 提交mr作业到yarn上
        // 完成了是0退出 不完成是1报异常
        System.exit(job.waitForCompletion(true) ?0:1);
    }
}
/**
 *map阶段
 */
class MyMapper extends Mapper<Object, Text, Text, IntWritable> {
    @Override
    protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
        String[] words = value.toString().split("\t");
        for (String word : words) {
            context.write(new Text(word), new IntWritable(1));
        }
    }

}

/**
 * reduce阶段
 */
class MyReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
        int sum = 0;
        for (IntWritable value : values) {
            sum += Integer.parseInt(value.toString());
        }
        context.write(key, new IntWritable(sum));
    }
}

文件加载时切片

数据: 文件FileInputFormat db(数据库)DBInputFormat
mr里面核心类:
input:InputFormat =》如何加载数据
1.getSplits:获取数据的切片数量
2.createRecordReader 读取数据内容
map:Mapper
map
reduce:Reducer
reducer
output:OutputFormat =》指定数据输出

Map task 个数由什么东西决定的?由切片数量决定

数据输入input :
如果是文件:
FileInputFormat:(FileInputFormat默认是TextInputFormat)
TextInputFormat:<LongWritable, Text>
key:读取文件内容的位置
value:一行一行的内容
1.isSplitable =》 判断你的文件是否可以被切分
1.可以被切分
分片数量 等同于 map task的数据
补充: map task数量由数据input的切片数量决定的
2.不可以被切分
切片数量就是1 对应一个map task
一个文件加载的时候会形成几个切片 ?前提 文件可以被切分
split 切片数量取决于splitsize大小
生产上:splitsize等于blocksize=128M
1.文件能被切分
1.文件大小 小于128M
就有一个切片 =》 一个map task
2.文件大小 大于 128M
fileszie/splitsize = num 切片数
filesize剩余的部分和splitsize的百分之十进行比较
如果剩余部分比splitsize的百分之十大 那么就会额外开启一个切片
如果剩余部分比splitsize的百分之十小 那么就不会开启一个新切片 剩余部分会放在上一个切片里进行处理
2.不能切分的文件
某些压缩文件
数据输入input=160M => 2个
128M =》1
32M > 128M*10% => 1
idea 本地环境:splitsize=32M

Reduce task 个数由什么东西决定的?

1.mr 用户自己决定 job.setNumReduceTasks(num)
2.默认reduce task个数是 1
3.reduce task 个数 =》 最终文件输出的时候 就有多少个文件

分区Partition job.setPartitionerClass(xxx.class)

”把相同的key拉倒一起“
key按照某个规则进行划分到 一起
某个规则: 默认 hash
需求:
基于phone结果数据,进行分文件存储
13开头的结果数据 存储到 一个文件中
15开头的结果数据 存储到 一个文件中
其他结果数据 存储到 一个文件中
1.reduce task 3
2.分区需要自定义
总结:
1.reduce task个数 > partitions 会有空文件
2.reduce task个数 < partitions 会报错
3.reduce task个数 = partitions 没问题
4.reduce task个数1 就是默认值 最终会有一个文件产生
map task是几,Mapper里的setup()和clear up()就执行几次

// 判断输出文件路径是否存在,存在则递归删除
package mapreduce;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class FileUtils {
    public static void deletePath(Configuration conf,String outpath) throws Exception{
        FileSystem fs = FileSystem.get(conf);
        Path path = new Path(outpath);
        if(fs.exists(path)){
            fs.delete(path,true);
        }
    }
}
package mapreduce02;
import mapreduce.FileUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
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;
public class PhoneAPP {
    public static void main(String[] args) throws Exception {
        String input = "src/data/phone.txt";
        String output = "out/phone";
        Configuration conf = new Configuration();
        FileUtils.deletePath(conf,output);
        Job job = Job.getInstance(conf, "PhoneAPP");
        job.setJarByClass(PhoneAPP.class);
        job.setMapperClass(MyMapper.class);
        job.setReducerClass(MyReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);
        job.setNumReduceTasks(3);
        job.setPartitionerClass(PhonePartitioner.class);
        FileInputFormat.addInputPath(job,new Path(input));
        FileOutputFormat.setOutputPath(job,new Path(output));
        System.exit(job.waitForCompletion(true)?0:1);
    }
}
class MyMapper
        extends Mapper<Object, Text, Text, Text> {
    @Override
    protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
        String[] split = value.toString().split("\t");
        String phone = split[0];
        String up = split[split.length - 3];
        String down = split[split.length - 2];
        context.write(new Text(phone),new Text(up  + "\t" + down));
    }
}
class MyReducer extends Reducer<Text, Text,Text,Text>{
    @Override
    protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
        long sum_up = 0;
        long sum_down = 0;
        long all = 0;
        for (Text value : values) {
            String[] split = value.toString().split("\t");
            String up = split[0];
            String down = split[1];
            sum_up+=Long.parseLong(up);
            sum_down+=Long.parseLong(down);
        }
        all=sum_up+sum_down;
        context.write(key,new Text(sum_up+"\t"+sum_down+"\t"+all));
    }
}
// 设置分区,让特定的输出数据输出特定的文件里
package mapreduce02;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;
public class PhonePartitioner extends Partitioner<Text, Text> {
    @Override
    public int getPartition(Text key, Text value, int numPartitions) {
        String phone = key.toString();
        if (phone.startsWith("13")){
            return 0;
        } else if (phone.startsWith("15")){
            return 1;
        } else{
            return 2;
        }
    }
}

mql底层用mr怎么实现

1.group by => mr
map =>
reduce =>
2.distinct =>group by
3.order by
4. join

// 1.group by
package mapreduce03;
import mapreduce.FileUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
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;
public class GroupAPP {
    public static void main(String[] args) throws Exception {
        String input = "src/data/groupby.txt";
        String output = "out/groupby";
        Configuration conf = new Configuration();
        FileUtils.deletePath(conf,output);
        Job job = Job.getInstance(conf, "GroupAPP");
        job.setJarByClass(GroupAPP.class);
        job.setMapperClass(MyMapper.class);
        job.setReducerClass(MyReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(NullWritable.class);
        FileInputFormat.addInputPath(job,new Path(input));
        FileOutputFormat.setOutputPath(job,new Path(output));
        System.exit(job.waitForCompletion(true)?0:1);
    }
}
class MyMapper
        extends Mapper<Object, Text, Text, NullWritable> {
    @Override
    protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
        String[] names = value.toString().split(",");
        for (String name : names) {
            context.write(new Text(name),NullWritable.get());
        }
    }
}
class MyReducer
        extends Reducer<Text, NullWritable,Text,NullWritable> {
    @Override
    protected void reduce(Text key, Iterable<NullWritable> values, Context context) throws IOException, InterruptedException {
        context.write(key,NullWritable.get());
    }
}
// 2.order by
package mapreduce03;
import mapreduce.FileUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
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;
public class OrderByAPP {
    public static void main(String[] args) throws Exception {
        String input = "out/phone/part-r-00000";
        String output = "out/orderby";
        Configuration conf = new Configuration();
        FileUtils.deletePath(conf,output);
        Job job = Job.getInstance(conf, "OrderByAPP");
        job.setJarByClass(OrderByAPP.class);
        job.setMapperClass(MyMapper01.class);
        job.setReducerClass(MyReducer01.class);
        job.setMapOutputKeyClass(MyIntWriteAble.class);
        job.setMapOutputValueClass(Text.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(NullWritable.class);
        FileInputFormat.addInputPath(job,new Path(input));
        FileOutputFormat.setOutputPath(job,new Path(output));
        System.exit(job.waitForCompletion(true)?0:1);
    }
}
class MyMapper01 extends Mapper<Object, Text, MyIntWriteAble, Text> {
    @Override
    protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
        String[] split = value.toString().split("\t");
        String all = split[3];
        String phone = split[0];
        String up = split[1];
        String down = split[2];
        context.write(new MyIntWriteAble(Integer.parseInt(all)),new Text(phone+"\t"+up+"\t"+down));
    }
}
class MyReducer01 extends Reducer<MyIntWriteAble, Text,Text, NullWritable> {
    @Override
    protected void reduce(MyIntWriteAble key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
        for (Text value : values) {
            context.write(new Text(value+"\t"+key),NullWritable.get());
        }
    }
}
// 重写IntWritable来进行排序
package mapreduce03;
import org.apache.hadoop.io.IntWritable;
public class MyIntWriteAble extends IntWritable {
    public MyIntWriteAble() {
    }
    public MyIntWriteAble(int value) {
        super(value);
    }
    @Override
    public int compareTo(IntWritable o) {
        return super.compareTo(o);
    }
}
// 3.join
package mapreduce03;
import mapreduce.FileUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.InputSplit;
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.input.FileSplit;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
import java.util.ArrayList;
public class JoinAPP {
    public static void main(String[] args) throws Exception {
        String input="";
        String output="";
        Configuration conf = new Configuration();
        //0.todo... 删除目标路径
        FileUtils.deletePath(conf,output);
        //1.设置 作业名称
        Job job = Job.getInstance(conf, "JoinAPP");
        //2.设置map reduce 执行代码的主类
        job.setJarByClass(JoinAPP.class);
        job.setMapperClass(MyMapper02.class);
        job.setReducerClass(MyReducer02.class);
        //3.指定 oupput kv类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(Text.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);
        //4. 设置数据源路径 数据输出路径
        FileInputFormat.addInputPath(job, new Path(input));
        FileOutputFormat.setOutputPath(job, new Path(output));
        //5. 提交mr yarn
        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }
}
class MyMapper02 extends Mapper<Object, Text, Text, Text> {
    String tablename;
    @Override
    protected void setup(Context context) throws IOException, InterruptedException {
        FileSplit inputSplit =(FileSplit)context.getInputSplit();
        tablename = inputSplit.getPath().getName();
    }
    @Override
    protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
        if (tablename.startsWith("dept")){
            String[] split = value.toString().split(",");
            String deptno = split[0];
            String dname = split[1];
            String loc = split[2];
            context.write(new Text(deptno),new Text(dname+"\t"+loc+"dept"));
        } else {
            String[] split = value.toString().split(",");
            String deptno = split[split.length - 1];
            String ename = split[1];
            String job = split[2];
            context.write(new Text(deptno),new Text(ename+"\t"+job+"emp"));
        }
    }
}
class MyReducer02 extends Reducer<Text, Text,Text,Text> {
    String deptTableColumns;
    ArrayList<String> empData = new ArrayList();
    @Override
    protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
        for (Text value : values) {
            String[] split = value.toString().split("\t");
            String table = split[split.length - 1];
            if (table.equals("dept")){
                deptTableColumns=split[0]+"\t"+split[1];
            } else {
                empData.add(split[0]+"\t"+split[1]);
            }
        }
        for (String emp : empData) {
            context.write(new Text(emp),new Text(key+"\t"+deptTableColumns));
        }
    }
}

Yarn架构:主从架构

1.resourcemanager:负责资源的分配
2.nodemanager:负责资源的供给与隔离
资源调度?resourcemanager将nodemanager上资源分配给task
资源隔离?nodemanager按照要求给task提供资源,保证提供的资源具有独占性
每个container之间相互隔离的
资源:nodemanager指挥分配的资源:container[一定比列cpu和内存]
一个container对应一个task

yarn的架构设计【面试】

1.客户端给ResourceManager的ApplicationsManager发送请求去运行jar包 包含一个作业(app master)
2.ApplicationsManager通知nodemanager分配一个container去运行app master
3.app master向ApplicationsManager去注册作业(完成之后yarn web ui 可以看到作业的运行情况)
4.app master向Resource Scheduler申请资源去运行我的代码
5-6.nodeManager收到Resource Scheduler的通知,会去开启container资源去运行map task和reduce task
7.task会向app master汇报代码的运行情况
8.当代码运行完成后,app master会给ApplicationsManager通知我的作业运行完成了,请求释放资源(container资源)
9.ApplicationsManager收到请求之后,通知客户端,你的代码运行完成了
input: map task个数会决定container 申请的个数
reduce : reduce task个数会决定container 申请的个数
container 申请的个数 =map task个数+reduce task个数

调度器

1.FIFO scheduler : 先进先出 单队列
2.Capacity scheduler 容量调度器:(离线任务,实时任务,临时查询任务)
多队列、每个队列之间 互不影响 先进先出
3.Fair scheduler 公平调度器
多队列、 每个队列之间 job 有影响 不是先进先出 队列间按job的优先级决定
默认调度器:Capacity scheduler 容量调度器 3.x yarn-site.xml
2.x默认是公平调度器
yarn.resourcemanager.scheduler.class =》 CapacityScheduler
yarn web : 可以查看queue Scheduler

yarn资源调优

针对集群中 每个节点 对container进行配置
刀片服务器配置: 128G 16物理core
1.刀片服务器 装完系统 消耗1G
2.系统预留 20%内存 [包含 装完系统 消耗1G]128G*%+
为什么系统要预留20%内存?
1.给未来部署组件预留内存空间
2.防止 全部使用 会导致 系统夯住 oom机制(资源不足时会杀死进程)【linux系统】
目前位置 大数据服务资源: 102G
hadoop:Datanode 进程内存 2G
nodemanager 进程内存 4G
102G -2g -4G = 96G => yarn资源 container 一共 96G
container资源划分 : 1.内存 2.cpu 【core】
1.container内存:
总:yarn.nodemanager.resource.memory-mb 96G 【默认值是8G】
最小:yarn.scheduler.minimum-allocation-mb 1g 极限情况下 会有96个container
最大:yarn.scheduler.maximum-allocation-mb 96G 最大不超过32G 极限情况下 会有1个container
注意: container内存会自动增加 默认1g递增
2.container cpu 【虚拟核 vcore =》 设计初衷 考虑不同节点的cpu性能不一样】
第一机器: 强悍 pcore:vcore=1:2 【1core 当成2core使用】
第二机器: 不强悍 pcore:vcore=1:1
16个物理核 : 16vcore
1.虚拟核 和物理核的比例 : yarn.nodemanager.resource.pcores-vcores-multiplier 2
yarn core =》 vcore 162 = 32 vcore
总: yarn.nodemanager.resource.cpu-vcores 32 【默认是8vcore】
最小:yarn.scheduler.minimum-allocation-vcores 1 极限情况下 只有32个container
最大:yarn.scheduler.maximum-allocation-vcores 32 极限情况下 只有1个container
实际开发角度: 1.mem 为主
2.cpu :cloudera 公司推荐 一个contaier 的vcore 最大值最好不要超过5 4
16个物理核 : 16vcore
1.虚拟核 和物理核的比例 :yarn.nodemanager.resource.pcores-vcores-multiplier 2
yarn core =》 vcore 16
2 = 32 vcore
总:yarn.nodemanager.resource.cpu-vcores 32 【默认是8vcore】
最小:yarn.scheduler.minimum-allocation-vcores 1 极限情况下 只有32个container
最大:yarn.scheduler.maximum-allocation-vcores 4 极限情况下 只有8个container
反推内存:

  1. vcore 4 container 8个
    总:yarn.nodemanager.resource.memory-mb 96G 【默认值是8G】
    最小:yarn.scheduler.minimum-allocation-mb 1g 极限情况下 会有96个container
    最大:yarn.scheduler.maximum-allocation-mb 12G 极限情况下 会有8个container
    注意: container内存会自动增加 默认1g递增
    container:
  2. 8-32 个container => task 8-32个
    2.实际上以内存为主
    总:yarn.nodemanager.resource.memory-mb 96G 【默认值是8G】
    最小:yarn.scheduler.minimum-allocation-mb 2G
    最大:yarn.scheduler.maximum-allocation-mb 20G
    20G => container ? 5个container
    2g => container ? 48个container

修改yarn资源

比如单个机器4G 2core
1.内存
总:yarn.nodemanager.resource.memory-mb 4G 【默认值是8G】
最小:yarn.scheduler.minimum-allocation-mb 1g 极限情况下 会有4个container
最大:yarn.scheduler.maximum-allocation-mb 2G 极限情况下 会有2个container
2.cpu 2
1.虚拟核 和物理核的比例 : yarn.nodemanager.resource.pcores-vcores-multiplier 2
总: yarn.nodemanager.resource.cpu-vcores 4 【默认是8vcore】
最小:yarn.scheduler.minimum-allocation-vcores 1 极限情况下 只有4个container
最大:yarn.scheduler.maximum-allocation-vcores 2 极限情况下 只有2个container
vim yarn-site.xml:
内存:

yarn.nodemanager.resource.memory-mb
4096


yarn.scheduler.minimum-allocation-mb
1024


yarn.scheduler.maximum-allocation-mb
2048

cpu:

yarn.nodemanager.resource.pcores-vcores-multiplier
2


yarn.nodemanager.resource.cpu-vcores
4


yarn.scheduler.minimum-allocation-vcores
1


yarn.scheduler.maximum-allocation-vcores
2

xsync yarn-site.xml

mapreduce:map task reduce task 默认申请的container:cpu 内存 分别是多少?

map task:
1.内存 :mapreduce.map.memory.mb 默认是1024
一个map task 申请的内存资源是 1024M
如果map task 实际使用的资源量超过该值 task将会被强制杀死
2.cpu mapreduce.map.cpu.vcores 默认是1
reduce task :
1.内存 mapreduce.reduce.memory.mb 默认是1024
2.cpu mapreduce.reduce.memory.mb 默认是1

jvm调优

mr: 进程级别 运行一个作业会开启很多进程进程,这个进程和yarn和hdfs没关系,它开启的是maptask相关进程可能多个,reduce task相关进程可能多个 =》 jvm (java运行时数据区)
map task :mapreduce.map.java.opts jvm相关调优参数即可
reduce task :mapreduce.reduce.java.opts jvm相关调优参数即可
jvm参数调优:
1.提交mr作业时可以指定 ?当前job生效
hadoop jar xxx.jar xxx参数 指定job运行时资源的参数
2.集群环境里面可以配置:? 全局生效
mapreude-site.xml
3.最常见的 code =》 当前job生效
code Configration设置参数

存储文件进行调优【压缩】

1.为什么要使用压缩?
1.节省空间 (1file hdfs 3个副本)
2.节省时间(数据发送时间): 网络io 和磁盘io 会减少
1.mapreduce 过程中 map端输出采用压缩
1.经过网络传输的数据量会变少 【减少了网络io】
2.磁盘上数据压缩后,读取到内存的数据量也会变少 【减少磁盘io】
2.使用场景?
1.采用压缩,对机器的cpu要求比较高
2.存储数据的空间不够
3.凡事都有两面性?
1.采用压缩 1.空间 和读取数据和网络传输时间会减少
2.cpu消耗比较大 cpu利用率高 =》 会导致整个mr作业处理数据时间会稍微长一些(发送数据时间的减少不能弥补压缩的时间)
4.如何使用压缩?
1.存储角度
上传到hdfs上的文件直接压缩,压缩普通文件
2.计算角度 mr spark flink
1.input mr 加载压缩文件不用考虑,因为文件已经压缩完了,压缩完的文件通过inputformat(切片)直接对文件进行读取 切片会对压缩格式进行校验 =》 源码里面会判断是否是压缩文件,如果是压缩文件进行强转
2.map out 配置参数即可
3.reduce out 配置参数即可
5.常见的压缩格式
gzip .gz
bzip2 .bz2
LZO .lzo
Snappy .snappy
LZ4 .lzo4
1.压缩比
Bzip2:30% GZIP snappy、lzo:50%
解压速度:
snappy、lzo > GZIP > Bzip2
2.压缩文件是否可以被切分?
1.假设一个 5G文件 不能被切分split意味着 只能使用一个map task去处理 效率不高
map task 处理的数据量是5G
2.假设一个 5G文件 能被切片splits 假如被切分为10个分片,10map task 去并行处理
5*1024 /10 = 一个map task 处理的数据量M
3. 能否被切分 决定了 你的 一个map task处理的数据量有多少,在资源充足的情况下,多并行度处理要比单并行度处理效率高些
3.压缩后的文件是否支持分割?
gzip 不可分割
bzip2 可分割
lzo 带索引的可以分割 (默认是不支持分割的)
snappy 不可分割的
4.mapreduce 每个阶段该如何采用这些算法?
compressed input =>decompressed input=> maps(一个切片对应一个map task) =>map out compressed =>decompressed map out=> reduce => reduce out compressed=> output
input:建议使用压缩,支持分片
1.Bzip2
支持分割 多个map task 进行出
map out:解压速度(网络传输),不用考虑是否能切片,切片是读取数据时要考虑的
1. shuffle 过程 要选择一个压/解 速度快的压缩格式
2.snappy 、lzo
reduce out :高压缩比的目的是节省空间,因为reduce输出的数据将来还有可能作为下一个map的输入,还要考虑能否切片的问题
1.高的压缩比 + 支持分片 =》 节省空间
2.bzip2 、lzo带索引的
reduce out 数据 作为下一个map 的输入咋办?
建议使用bzip2【如果采用压缩的话】
如何进行配置?
1.某个作业 =》 code代码里面添加 【某个job生效】
2.集群所有作业 =》 在配置文件里面加 【全局生效】
mapreduce 压缩配置:input阶段不需要配置
1.配置压缩的codec
2.map reduce 输出配置:
1.先打开压缩的开关
2.配置codec 即可
hadoop集群hdfs 支持哪些压缩?gzip(默认)、snappy、bzip2、lz4
1.命令 hadoop checknative
2.core-site.xml可以配置:配置支持的压缩有哪些
io.compression.codecs 控制
mapred-site.xml里面可以配置:
1.先打开压缩的开关
2.map reduce 输出 压缩算法
补充:
原生 hadoop 默认不支持 lzo的压缩
vim core-site.xml 配置支持的压缩有哪些
bzip2、gzip、snappy

io.compression.codecs
org.apache.hadoop.io.compress.BZip2Codec,
org.apache.hadoop.io.compress.SnappyCodec,
org.apache.hadoop.io.compress.GzipCodec,
org.apache.hadoop.io.compress.DefaultCodec


vim mapred-site.xml:
1.先打开压缩的开关
2.map reduce 输出 压缩算法
reduce: 开关
mapreduce.output.fileoutputformat.compress

mapreduce.output.fileoutputformat.compress
true

mapreduce.output.fileoutputformat.compress.codec

mapreduce.output.fileoutputformat.compress.codec
org.apache.hadoop.io.compress.BZip2Codec这里面的压缩格式可以换

hadoop fs -text 压缩文件 可以查看压缩文件 -text是以mr的方式进行查看文件内容,一定有input阶段,input阶段对压缩文件没有要求,任何压缩文件都可以看到

各个DN节点数据平衡

sbin目录下start-balancer.sh
eg:DN1 存储空间 90%
DN2 存储空间 60%
DN3 存储空间 80%
数据平衡的默认阈值:threshold = 10.0
每个节点的磁盘使用率 - 平均的磁盘使用率 <10%
avg=90 + 80 +60 /3 = 76%
DN1 存储空间 90% -76% = 14% 说明这个节点数据多 往别的节点迁移数据 出
DN2 存储空间 60% -76% = -12% 说明这个节点数据少 别的节点迁移数据 进
DN3 存储空间 80% -76% = 4%
生产上 从现在开始 start-balancer.sh -threshold 10 每天要定时做的
放到业务低谷期去做 数据平衡操作 ,不要在业务高峰期做
数据平衡 数据传输 带宽有关
调优参数 :平衡的网络带宽 w
(3.x)dfs.datanode.balance.bandwidthPerSec 默认是100M 【2.x 默认是10M】
单个DN节点 多块磁盘的数据平衡 nodename有副本数,不要做raid
做raid:备份,把磁盘分成两份,一份读一份写,但是内容是一样的
查看磁盘挂载df -h
1.dn 配置多个磁盘

dfs.datanode.data.dir
/data01,/data02,/data03磁盘

2.为什么要使用多块物理磁盘?
1.存储
2.因为多个磁盘的io也是叠加的
每块磁盘 磁盘io 每秒 100M
三块磁盘 1s 能 300M文件内容
一块磁盘 1s 100M
3./data01,/data02,/data03
做多个磁盘数据均衡
dfs.disk.balancer.enabled true 【3.x有这个功能 cdh 2.x 也有】 apache 2.x 没有这个功能
得通过命令去解决磁盘数据均衡?
hdfs diskbalancer
1.步骤
hdfs diskbalancer -plan bigdata32 => 生成一个 bigdata32.plan.json 文件
hdfs diskbalancer -execute bigdata32.plan.json =》 执行disk 数据均衡计划文件
hdfs diskbalancer -query bigdata32
生产上 当你发现 磁盘写入不均衡 可以做一下 【一般 一个月 半个月 做一次即可】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值