0. 说明

  数据倾斜及解决方法的介绍与代码实现


1. 介绍

  【1.1 数据倾斜的含义】

  大量数据发送到同一个节点进行处理,造成此节点繁忙甚至瘫痪,而其他节点资源空闲

  【1.2 解决数据倾斜的方式】

  重新设计 Key(配合二次 MR 使用)

  

  随机分区

    伪代码如下:

RandomPartition extends Partitioner{
return r.nextInt()
}

2. 重新设计 Key 代码编写

  [2.1 WCMapper.java]

package hadoop.mr.dataskew;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper; import java.io.IOException;
import java.util.Random; /**
* Mapper 程序
* 重新设计 Key
*/
public class WCMapper extends Mapper<LongWritable, Text, Text, IntWritable> { Random r = new Random();
int i; @Override
protected void setup(Context context) throws IOException, InterruptedException {
// 获取 reduce 的个数
i = context.getNumReduceTasks();
} /**
* map 函数,被调用过程是通过 while 循环每行调用一次
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
// 将 value 变为 String 格式
String line = value.toString();
// 将一行文本进行截串
String[] arr = line.split(" "); for (String word : arr) { String newWord = word + "_" + r.nextInt(i); context.write(new Text(newWord), new IntWritable(1));
} }
}

  [2.2 WCReducer.java]

package hadoop.mr.dataskew;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer; import java.io.IOException; /**
* Reducer 类
*/
public class WCReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
/**
* 通过迭代所有的 key 进行聚合
*/
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
int sum = 0; for (IntWritable value : values) {
sum += value.get();
} context.write(key,new IntWritable(sum));
}
}

  [2.3 WCMapper2.java]

package hadoop.mr.dataskew;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper; import java.io.IOException; /**
* Mapper 程序2
* 重新设计 Key
*/
public class WCMapper2 extends Mapper<LongWritable, Text, Text, IntWritable> {
/**
* map 函数,被调用过程是通过 while 循环每行调用一次
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
// 将 value 变为 String 格式
String line = value.toString();
// 切割一行文本分为 key 和 value
String[] arr = line.split("\t"); String word = arr[0]; Integer count = Integer.parseInt(arr[1]); // 重新设计 Key
String newWord = word.split("_")[0]; context.write(new Text(newWord), new IntWritable(count)); }
}

  [2.4 WCReducer2.java]

package hadoop.mr.dataskew;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer; import java.io.IOException; /**
* Reducer 类2
*/
public class WCReducer2 extends Reducer<Text, IntWritable, Text, IntWritable> {
/**
* 通过迭代所有的 key 进行聚合
*/
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
int sum = 0; for (IntWritable value : values) {
sum += value.get();
} context.write(key,new IntWritable(sum));
}
}

  [2.5 WCApp.java]

package hadoop.mr.dataskew;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
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.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; /**
* 解决数据倾斜
*/
public class WCApp {
public static void main(String[] args) throws Exception {
// 初始化配置文件
Configuration conf = new Configuration(); // 仅在本地开发时使用
conf.set("fs.defaultFS", "file:///"); // 初始化文件系统
FileSystem fs = FileSystem.get(conf); // 通过配置文件初始化 job
Job job = Job.getInstance(conf); // 设置 job 名称
job.setJobName("data skew"); // job 入口函数类
job.setJarByClass(WCApp.class); // 设置 mapper 类
job.setMapperClass(WCMapper.class); // 设置 reducer 类
job.setReducerClass(WCReducer.class); // 设置分区数量
job.setNumReduceTasks(3); // 设置 map 的输出 K-V 类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class); // 设置 reduce 的输出 K-V 类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class); // 设置输入路径和输出路径
Path pin = new Path("E:/test/wc/dataskew.txt");
Path pout = new Path("E:/test/wc/out");
// Path pin = new Path(args[0]);
// Path pout = new Path(args[1]);
FileInputFormat.addInputPath(job, pin);
FileOutputFormat.setOutputPath(job, pout); // 判断输出路径是否已经存在,若存在则删除
if (fs.exists(pout)) {
fs.delete(pout, true);
} // 执行 job
boolean b = job.waitForCompletion(true); if (b) {
// 通过配置文件初始化 job
Job job2 = Job.getInstance(conf); // 设置 job 名称
job2.setJobName("data skew2"); // job 入口函数类
job2.setJarByClass(WCApp.class); // 设置 mapper 类
job2.setMapperClass(WCMapper2.class); // 设置 reducer 类
job2.setReducerClass(WCReducer2.class); // 设置分区数量
// job2.setNumReduceTasks(3); // 设置 map 的输出 K-V 类型
job2.setMapOutputKeyClass(Text.class);
job2.setMapOutputValueClass(IntWritable.class); // 设置 reduce 的输出 K-V 类型
job2.setOutputKeyClass(Text.class);
job2.setOutputValueClass(IntWritable.class); // 设置输入路径和输出路径
Path pin2 = new Path("E:/test/wc/out");
Path pout2 = new Path("E:/test/wc/out2");
// Path pin = new Path(args[0]);
// Path pout = new Path(args[1]);
FileInputFormat.addInputPath(job2, pin2);
FileOutputFormat.setOutputPath(job2, pout2); // 判断输出路径是否已经存在,若存在则删除
if (fs.exists(pout2)) {
fs.delete(pout2, true);
} // 执行 job
job2.waitForCompletion(true);
}
}
}

3. 随机分区代码编写

  [3.1 WCMapper.java]

package hadoop.mr.dataskew2;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper; import java.io.IOException; /**
* Mapper 程序
* 重新设计 Key
*/
public class WCMapper extends Mapper<LongWritable, Text, Text, IntWritable> { /**
* map 函数,被调用过程是通过 while 循环每行调用一次
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
// 将 value 变为 String 格式
String line = value.toString(); // 将一行文本进行截串
String[] arr = line.split(" "); for (String word : arr) {
context.write(new Text(word), new IntWritable(1));
} }
}

  [3.2 WCReducer.java]

package hadoop.mr.dataskew2;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer; import java.io.IOException; /**
* Reducer 类
*/
public class WCReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
/**
* 通过迭代所有的 key 进行聚合
*/
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
int sum = 0; for (IntWritable value : values) {
sum += value.get();
} context.write(key, new IntWritable(sum));
}
}

  [3.3 WCMapper2.java]

package hadoop.mr.dataskew2;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper; import java.io.IOException; /**
* Mapper 程序2
* 重新设计 Key
*/
public class WCMapper2 extends Mapper<LongWritable, Text, Text, IntWritable> {
/**
* map 函数,被调用过程是通过 while 循环每行调用一次
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
// 将 value 变为 String 格式
String line = value.toString();
// 切割一行文本分为 key 和 value
String[] arr = line.split("\t"); String word = arr[0]; Integer count = Integer.parseInt(arr[1]); context.write(new Text(word), new IntWritable(count)); }
}

  [3.4 RandomPartitioner.java]

package hadoop.mr.dataskew2;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner; import java.util.Random; /**
* 随机分区类
*/
public class RandomPartitioner extends Partitioner<Text, IntWritable> { Random r = new Random(); @Override
public int getPartition(Text text, IntWritable intWritable, int numPartitions) {
return r.nextInt(numPartitions);
}
}

  [3.5 WCApp.java]

package hadoop.mr.dataskew2;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
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.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; /**
* 随机分区解决数据倾斜
*/
public class WCApp {
public static void main(String[] args) throws Exception {
// 初始化配置文件
Configuration conf = new Configuration(); // 仅在本地开发时使用
conf.set("fs.defaultFS", "file:///"); // 初始化文件系统
FileSystem fs = FileSystem.get(conf); // 通过配置文件初始化 job
Job job = Job.getInstance(conf); // 设置 job 名称
job.setJobName("data skew"); // job 入口函数类
job.setJarByClass(WCApp.class); // 设置 mapper 类
job.setMapperClass(WCMapper.class); // 设置 reducer 类
job.setReducerClass(WCReducer.class); // 设置 partition 类
job.setPartitionerClass(RandomPartitioner.class); // 设置分区数量
job.setNumReduceTasks(3); // 设置 map 的输出 K-V 类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class); // 设置 reduce 的输出 K-V 类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class); // 设置输入路径和输出路径
Path pin = new Path("E:/test/wc/dataskew.txt");
Path pout = new Path("E:/test/wc/out");
// Path pin = new Path(args[0]);
// Path pout = new Path(args[1]);
FileInputFormat.addInputPath(job, pin);
FileOutputFormat.setOutputPath(job, pout); // 判断输出路径是否已经存在,若存在则删除
if (fs.exists(pout)) {
fs.delete(pout, true);
} // 执行 job
boolean b = job.waitForCompletion(true); if (b) {
// 通过配置文件初始化 job
Job job2 = Job.getInstance(conf); // 设置 job 名称
job2.setJobName("data skew2"); // job 入口函数类
job2.setJarByClass(hadoop.mr.dataskew.WCApp.class); // 设置 mapper 类
job2.setMapperClass(WCMapper2.class); // 设置 reducer 类
job2.setReducerClass(WCReducer.class); // 设置分区数量
// job2.setNumReduceTasks(3); // 设置 map 的输出 K-V 类型
job2.setMapOutputKeyClass(Text.class);
job2.setMapOutputValueClass(IntWritable.class); // 设置 reduce 的输出 K-V 类型
job2.setOutputKeyClass(Text.class);
job2.setOutputValueClass(IntWritable.class); // 设置输入路径和输出路径
Path pin2 = new Path("E:/test/wc/out");
Path pout2 = new Path("E:/test/wc/out2");
// Path pin = new Path(args[0]);
// Path pout = new Path(args[1]);
FileInputFormat.addInputPath(job2, pin2);
FileOutputFormat.setOutputPath(job2, pout2); // 判断输出路径是否已经存在,若存在则删除
if (fs.exists(pout2)) {
fs.delete(pout2, true);
} // 执行 job
job2.waitForCompletion(true);
} }
}

[MapReduce_add_3] MapReduce 通过分区解决数据倾斜的更多相关文章

  1. Hadoop_22_MapReduce map端join实现方式解决数据倾斜(DistributedCache)

    1.Map端Join解决数据倾斜   1.Mapreduce中会将map输出的kv对,按照相同key分组(调用getPartition),然后分发给不同的reducetask 2.Map输出结果的时候 ...

  2. Spark性能调优之解决数据倾斜

    Spark性能调优之解决数据倾斜 数据倾斜七种解决方案 shuffle的过程最容易引起数据倾斜 1.使用Hive ETL预处理数据    • 方案适用场景:如果导致数据倾斜的是Hive表.如果该Hiv ...

  3. MapReduce如何解决数据倾斜?

    数据倾斜是日常大数据查询中隐形的一个BUG,遇不到它时你觉得数据倾斜也就是书本博客上的一个无病呻吟的偶然案例,但当你遇到它是你就会懊悔当初怎么不多了解一下这个赫赫有名的事故. https://www. ...

  4. 【Spark篇】---Spark解决数据倾斜问题

    一.前述 数据倾斜问题是大数据中的头号问题,所以解决数据清洗尤为重要,本文只针对几个常见的应用场景做些分析 . 二.具体方法  1.使用Hive ETL预处理数据 方案适用场景: 如果导致数据倾斜的是 ...

  5. 专访周金可:我们更倾向于Greenplum来解决数据倾斜的问题

    周金可,就职于听云,维护MySQL和GreenPlum的正常运行,以及调研适合听云业务场景的数据库技术方案. 听云周金可 9月24日,周金可将参加在北京举办的线下活动,并做主题为<GreenPl ...

  6. MapReduce分区数据倾斜

    什么是数据倾斜? 数据不可避免的出现离群值,并导致数据倾斜,数据倾斜会显著的拖慢MR的执行速度 常见数据倾斜有以下几类 1.数据频率倾斜   某一个区域的数据量要远远大于其他区域 2.数据大小倾斜  ...

  7. Hadoop基础-MapReduce的数据倾斜解决方案

    Hadoop基础-MapReduce的数据倾斜解决方案 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.数据倾斜简介 1>.什么是数据倾斜 答:大量数据涌入到某一节点,导致 ...

  8. Spark性能优化之道——解决Spark数据倾斜(Data Skew)的N种姿势

    原创文章,同步首发自作者个人博客转载请务必在文章开头处注明出处. 摘要 本文结合实例详细阐明了Spark数据倾斜的几种场景以及对应的解决方案,包括避免数据源倾斜,调整并行度,使用自定义Partitio ...

  9. 实战 | Hive 数据倾斜问题定位排查及解决

    Hive 数据倾斜怎么发现,怎么定位,怎么解决 多数介绍数据倾斜的文章都是以大篇幅的理论为主,并没有给出具体的数据倾斜案例.当工作中遇到了倾斜问题,这些理论很难直接应用,导致我们面对倾斜时还是不知所措 ...

随机推荐

  1. 根据iPhone6设计稿动态计算rem值

    rem 单位在做移动端的h5开发的时候是最经常使用的单位.为解决自适应的问题,我们需要动态的给文档的更节点添加font-size 值.使用mediaquery 可以解决这个问题,但是每一个文件都引用一 ...

  2. Java工程师学习指南 完结篇

    Java工程师学习指南 完结篇 先声明一点,文章里面不会详细到每一步怎么操作,只会提供大致的思路和方向,给大家以启发,如果真的要一步一步指导操作的话,那至少需要一本书的厚度啦. 因为笔者还只是一名在校 ...

  3. Jfinal文件上传基础路径问题,windows下会以项目根路径为基础路径

    在本地windows下开发测试文件上传 使用com.jfinal.cos进行multipart/form-data请求数据格式的文件上传解析 import com.jfinal.upload.Uplo ...

  4. mac在命令行中打开某个文件夹

    使用 open 命令,如打开 ~/Download/abc open ~/Download/abc

  5. leetcode — valid-parentheses

    import java.util.Stack; /** * Source : https://oj.leetcode.com/problems/valid-parentheses/ * * Creat ...

  6. 使用com.aspose.words将word模板转为PDF乱码解决方案(window下正常)

    最近在做电子签名过程中,需要将合成的电子签名的word文件(正常)转换为pdf文件时,在开发平台window下转换没有问题,中文也不会出现乱码.但是将项目部署到正式服务器(Linux)上,转换出来的p ...

  7. spring-boot-2.0.3源码篇 - filter的注册,值得一看

    前言 开心一刻 过年女婿来岳父家走亲戚,当时小舅子主就问:姐夫,你什么时候能给我姐幸福,让我姐好好享受生活的美好.你们这辈子不准备买一套大点的房子吗?姐夫说:现在没钱啊!不过我有一个美丽可爱的女儿,等 ...

  8. #1 初识Python

    前言 要说现在最时髦的编程语言是什么,那么一定是Python无疑了.让我们来一起来领略其风采吧! 一.Python介绍 Python的创始人为吉多·范罗苏姆(Guido van Rossum),被大家 ...

  9. netty源码解解析(4.0)-1 核心架构

    netty是java开源社区的一个优秀的网络框架.使用netty,我们可以迅速地开发出稳定,高性能,安全的,扩展性良好的服务器应用程序.netty封装简化了在服务器开发领域的一些有挑战性的问题:jdk ...

  10. [HEOI2017] 相逢是问候

    Description 支持以下两个操作: 将第 \(l\) 个数到第 \(r\) 个数 \(a_l,a_{l+1},\dots a_r\) 中的每个数 \(a_i\) 替换为 \(c^{a_i}\) ...