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. IntelliJ IDEA 修改包名

    1.首先将AndroidManifest的Package Name重命名(快捷键shift+F6或者右键Refctor然后Rename)这时Package Name就改变了,但是Src的文件名还没变2 ...

  2. 向量时钟算法简介——本质类似MVCC

    转自:http://blog.chinaunix.net/uid-27105712-id-5612512.html 一.使用背景 先说一下需要用到向量时钟的场景.我们在写数据时候,经常希望数据不要存储 ...

  3. C#多线程 线程池

    实例1:直接看看微软提供的代码 using System; using System.Threading; public class Example { public static void Main ...

  4. JavaEE SSH框架整合(四) 日志处理Spring结合 log4j、slf4j [转]

    1. 加入log4j和slf4j的jar包 2. web.xml: <context-param> <!--log4j配置地址 --> <param-name>lo ...

  5. Html5实现移动端、PC端 刮刮卡效果

    刚从南方回来就分了一个刮刮卡效果的页面,特么的我在烦恼怎么用H5去实现这个效果呢,好不容易写出来了,产品居然说:“既然你可以写出来这个效果那当然好了,开始我只是打算让你实现点击就出现呢!”… … 尼玛 ...

  6. 网页首页制作总结(div+css+javascript)

    一.对网页整体布局,分几个版块 如下图所示: 确定布局之后,规划好网页,准备素材,按照标准文档流的顺序,从上到下,从左到右写入代码. 以上图为例,分为两部分,红色的主体部分和页脚.主体部分分割为头部. ...

  7. 单例模式(Singleton Pattern)

    动机: 在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性.以及良好的效率. 如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例? 这应该是类设 ...

  8. RSA IOS和Java

    整了三天 终于可以相互加密解密了,今天我给大家讲讲我遇到的大坑. 这篇文章只是做一个整理,帮大家理清一下步骤的而已 在ios端做证书 来实现我们和java的交流 需要4个文件. 一.首先,打开Term ...

  9. UE4 C++ 使用FTimeLine/FTime 实例 Actor moving faster than Timeline

    https://answers.unrealengine.com/questions/313698/timeline-issues.html   https://docs.unrealengine.c ...

  10. 三部曲一(数据结构)-1011-Sorting It All Out

    每次加入一个关系都要进行拓扑排序,不过在排序过程中需要判断是否出现多个入度为0的点,如果出现了就说明不能确定大小关系.不论出不出现多个入度为0的点拓扑排序都要进行到最后来判断是否出现环,因为一旦出现环 ...