HDFS的数据完整性

检验数据是否损坏最常见的措施是:在数据第一次引入系统时计算校验和并在数据通过一个不可靠通道进行传输时再次计算校验和,这样就能发现数据是否被损坏。HDFS会对写入的所有数据计算校验和,并在读取数据时验证校验和。

  1. 客户端写数据:正在写数据的客户端将数据及其校验和发送到由一系列datanode组成的管线,管线中最后一个datanode负责验证校验和。如果检测到错误,客户端会收到一个ChecksumException异常。(datanode负责在收到数据后存储该数据并验证校验和,它在收到客户端的数据或者复制其他datanode的数据时执行这个操作)
  2. 客户端从datanode读数据:验证校验和,将它们与datanode中存储的校验和进行比较。每个datanode中持久保存有一个用于验证校验和的校验日志,它知道每个数据块的最后一次验证时间,客户端成功验证一个数据块后,会告诉datanode,由此更新日志。
  3. 每个datanode也会在后台中运行一个DataBlockScanner,从而定期验证存储在这个datanode上的所有数据块。
  4. 若datanode读取数据时发现数据损坏,首先向namenode报告,再抛出ChecksumException异常,namenode将这个数据块标记为损坏,之后它安排这个数据块的一个复本复制到另一个datanode,如此一来,数据的复本因子回到期望水平,已损坏的复本会被删除。

压缩

压缩的好处:减少存储文件所需要的磁盘空间;加速数据在网络和磁盘上的传输。

mapreduce中为什么不使用gzip格式

由于map以文件的每个切分作为输入,而gzip格式使用DEFLATE算法来存储压缩后的数据,而DEFLATE算法将数据存储在一系列连续的数据块中,需要从每个块的起始位置进行读取,因此不支持切分,而mapreduce需要从数据列的任意位置开始读取,在这种情况下,mapreduce不会尝试切分gzip压缩文件,会将所有数据块全部输入给一个map节点,而大多数数据块并没有存储在执行该map任务的节点,牺牲了数据的本地性。

如何选择压缩格式

按效率从高到低排序:

  1. 使用容器文件格式,如顺序文件、Avro数据文件,它们同时支持压缩和切分。
  2. 使用支持切分的压缩格式,如bzip2(慢)
  3. 将文件切分成块(合理选择块的大小,确保压缩后接近HDFS块的大小),然后用任意方式压缩。
  4. 存储未经压缩的文件
在mapreduce中使用压缩
  1. 对最终输出进行压缩:

    FileOutputFormat.setCompressOutput(job, true);

    FileOutputFormat.setOutputCompressorClass(job, GzipCodec.class);
  2. 对map任务输出进行压缩:

    // vv MaxTemperatureWithMapOutputCompression

    Configuration conf = new Configuration();

    conf.setBoolean(Job.MAP_OUTPUT_COMPRESS, true);

    conf.setClass(Job.MAP_OUTPUT_COMPRESS_CODEC, GzipCodec.class,

    CompressionCodec.class);

    Job job = new Job(conf);

    // ^^ MaxTemperatureWithMapOutputCompression

序列化

序列化在分布式数据处理的两大领域经常出现:进程间通信和永久存储。

通常情况下,序列化格式需要满足:

  1. 紧凑(紧凑格式能充分利用网络带宽)
  2. 快速(分布式系统需要尽量减少序列化和反序列化的性能开销)
  3. 可扩展(能够满足协议变化的需求,在控制客户端和服务器的过程中,可以直接引进相应的协议)
  4. 支持互操作(可以支持不同语言写的客户端和服务器交互)
hadoop自己的序列化格式-----Writable
  1. 定制Writable集合

    public class TextPair implements WritableComparable {

    private Text first;

    private Text second;

    public TextPair() {

    set(new Text(), new Text());

    }

    public TextPair(String first, String second) {

    set(new Text(first), new Text(second));

    }

    public TextPair(Text first, Text second) {

    set(first, second);

    }

    public void set(Text first, Text second) {

    this.first = first;

    this.second = second;

    }

    public Text getFirst() {

    return first;

    }

    public Text getSecond() {

    return second;

    }

    public void write(DataOutput out) throws IOException {

    first.write(out);

    second.write(out);

    }

    public void readFields(DataInput in) throws IOException {

    first.readFields(in);

    second.readFields(in);

    }

    @Override

    public int hashCode() {

    return first.hashCode() * 163 + second.hashCode();

    }

    @Override

    public boolean equals(Object o) {

    if (o instanceof TextPair) {

    TextPair tp = (TextPair) o;

    return first.equals(tp.first) && second.equals(tp.second);

    }

    return false;

    }

    @Override

    public String toString() {

    return first + "\t" + second;

    }

    public int compareTo(TextPair tp) {

    int cmp = first.compareTo(tp.first);

    if (cmp != 0) {

    return cmp;

    }

    return second.compareTo(tp.second);

    }

    }

  2. 定制的comparator-----实现直接比较数据流中的记录

    public static class Comparator extends WritableComparator {

    private static final Text.Comparator TEXT_COMPARATOR = new Text.Comparator();

    public Comparator() {

    super(TextPair.class);

    }

    @Override

    public int compare(byte[] b1, int s1, int l1,

    byte[] b2, int s2, int l2) {

    try {

    int firstL1 = WritableUtils.decodeVIntSize(b1[s1]) + readVInt(b1, s1);

    int firstL2 = WritableUtils.decodeVIntSize(b2[s2]) + readVInt(b2, s2);

    int cmp = TEXT_COMPARATOR.compare(b1, s1, firstL1, b2, s2, firstL2);

    if (cmp != 0) {

    return cmp;

    }

    return TEXT_COMPARATOR.compare(b1, s1 + firstL1, l1 - firstL1,

    b2, s2 + firstL2, l2 - firstL2);

    } catch (IOException e) {

    throw new IllegalArgumentException(e);

    }

    }

    }

// vv TextPairFirstComparator

public static class FirstComparator extends WritableComparator {

private static final Text.Comparator TEXT_COMPARATOR = new Text.Comparator();

public FirstComparator() {
super(TextPair.class);
} @Override
public int compare(byte[] b1, int s1, int l1,
byte[] b2, int s2, int l2) { try {
int firstL1 = WritableUtils.decodeVIntSize(b1[s1]) + readVInt(b1, s1);
int firstL2 = WritableUtils.decodeVIntSize(b2[s2]) + readVInt(b2, s2);
return TEXT_COMPARATOR.compare(b1, s1, firstL1, b2, s2, firstL2);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
} @Override
public int compare(WritableComparable a, WritableComparable b) {
if (a instanceof TextPair && b instanceof TextPair) {
return ((TextPair) a).first.compareTo(((TextPair) b).first);
}
return super.compare(a, b);
}
}

// ^^ TextPairFirstComparator

Avro
  • Avro是个支持多语言的数据序列化框架,支持c,c++,c#,Python,java,php,ruby,java。

    他的诞生主要是为了弥补Writable只支持java语言的缺陷。

  • 很多人会问类似的框架还有Thrift和Protocol,那为什么不使用这些框架,而要重新建一个框架呢,

    或者说Avro有哪些不同。首先,Avro和其他框架一样,数据是用与语言无关的schema描述的,不

    同的是Avro的代码生成是可选的,schema和数据存放在一起,而schema使得整个数据的处理过

    程并不生成代码、静态数据类型等,为了实现这些,需要假设读取数据的时候模式是已知的,这样

    就会产生紧耦合的编码,不再需要用户指定字段标识。

  • Avro的schema是JSON格式的,而编码后的数据是二进制格式(当然还有其他可选项)的,这样对

    于已经拥有JSON库的语言可以容易实现。

  • Avro还支持扩展,写的schema和读的schema不一定要是同一个,也就是说兼容新旧schema和新旧

    客户端的读取,比如新的schema增加了一个字段,新旧客户端都能读旧的数据,新客户端按新的sch

    ema去写数据,当旧的客户端读到新的数据时可以忽略新增的字段。

  • Avro还支持datafile文件,schema写在文件开头的元数据描述符里,Avro datafile支持压缩和分割,这

    就意味着可以做Mapreduce的输入。

Hadoop的I/O操作的更多相关文章

  1. Hadoop之HDFS文件操作常有两种方式(转载)

    摘要:Hadoop之HDFS文件操作常有两种方式,命令行方式和JavaAPI方式.本文介绍如何利用这两种方式对HDFS文件进行操作. 关键词:HDFS文件    命令行     Java API HD ...

  2. Hadoop HDFS文件常用操作及注意事项

    Hadoop HDFS文件常用操作及注意事项 1.Copy a file from the local file system to HDFS The srcFile variable needs t ...

  3. Hadoop系列007-HDFS客户端操作

    title: Hadoop系列007-HDFS客户端操作 date: 2018-12-6 15:52:55 updated: 2018-12-6 15:52:55 categories: Hadoop ...

  4. Hadoop HDFS的Shell操作实例

    本文发表于本人博客. 我们知道HDFS是Hadoop的分布式文件系统,那既然是文件系统那最起码会有管理文件.文件夹之类的功能吧,这个类似我们的Windows操作系统一样的吧,创建.修改.删除.移动.复 ...

  5. Java接口对Hadoop集群的操作

    Java接口对Hadoop集群的操作 首先要有一个配置好的Hadoop集群 这里是我在SSM框架搭建的项目的测试类中实现的 一.windows下配置环境变量 下载文件并解压到C盘或者其他目录. 链接: ...

  6. Hadoop之HDFS文件操作

    摘要:Hadoop之HDFS文件操作常有两种方式.命令行方式和JavaAPI方式.本文介绍怎样利用这两种方式对HDFS文件进行操作. 关键词:HDFS文件    命令行     Java API HD ...

  7. 初识Hadoop二,文件操作

    1.使用hadoop命令查看hdfs下文件 [root@localhost hadoop-2.7.3]# hadoop fs -ls hdfs://192.168.36.134:9000/ 开始在se ...

  8. hadoop的hdfs文件操作实现上传文件到hdfs

    这篇文章主要介绍了使用hadoop的API对HDFS上的文件访问,其中包括上传文件到HDFS上.从HDFS上下载文件和删除HDFS上的文件,需要的朋友可以参考下hdfs文件操作操作示例,包括上传文件到 ...

  9. Docker 安装Hadoop HDFS命令行操作

    网上拉取Docker模板,使用singlarities/hadoop镜像 [root@localhost /]# docker pull singularities/hadoop 查看: [root@ ...

随机推荐

  1. 7 -- Spring的基本用法 -- 7...

    7.7 创建Bean的3种方式 ① 调用构造器创建Bean. ② 调用静态工厂方法创建Bean. ③ 调用实例工厂方法创建Bean. 7.7.1 使用构造器创建Bean实例. 使用构造器来创建Bean ...

  2. Spring事务管理者与Spring事务注解--声明式事务

    1.在Spring的applicationContext.xml中配置事务管理者 PS:具体的说明请看代码中的注释 Xml代码: <!-- 声明式事务管理的配置 --> <!-- 添 ...

  3. OPENGL学习之路(0)--安装

    此次实验目的: 安装并且配置环境. 1 下载 https://www.opengl.org/ https://www.opengl.org/wiki/Getting_Started#Downloadi ...

  4. Yii MySQL修改数据库的数据

    最新学习Yii框架,分享一些学习心得,适合初学者,大神请按ctrl + w //第一种方法 <?php /* * $id 代表主键,可以是一个也可以是一个集合. * $attributes 代表 ...

  5. iOS 视图控制器转场详解

    iOS 视图控制器转场详解 前言的前言 唐巧前辈在微信公众号「iOSDevTips」以及其博客上推送了我的文章后,我的 Github 各项指标有了大幅度的增长,多谢唐巧前辈的推荐.有些人问我相关的问题 ...

  6. 关于makefile

    0 Makefile概述 -------------------------------------------------------------------------------- 什么是mak ...

  7. [转]JAVA虚拟机的生命周期

    JAVA虚拟机体系结构 JAVA虚拟机的生命周期 一个运行时的Java虚拟机实例的天职是:负责运行一个java程序.当启动一个Java程序时,一个虚拟机实例也就诞生了.当该程序关闭退出,这个虚拟机实例 ...

  8. Android AutoLayout全新的适配方式 堪称适配终结者(转)

    一.概述 相信Android的开发者对于设配问题都比较苦恼,Google官方虽然给出了一系列的建议,但是想要单纯使用这些建议将设备很轻松的做好,还是相当困难的.个人也比较关注适配的问题,之前也发了几篇 ...

  9. [Jquery]某宝图片轮播(无缝、带左右切换按钮)

    [效果] 左右移动(非渐隐) [思路] 1.结构与样式 ①最外层div盒子当容器,里面ul宽度无限大并且相对定位(到时候移动其实移的是ul的left) ②按钮的透明度可用background:rgba ...

  10. Spring之JDBC模板jdbcTemplate

    要使用Jdbctemplate 对象来完成jdbc 操作.通常情况下,有三种种方式得到JdbcTemplate 对象.           第一种方式:我们可以在自己定义的DAO 实现类中注入一个Da ...