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. CSS3 transform对普通元素的N多渲染影响

    一.一入transform深似海 一个普普通通的元素,如果应用了CSS3 transform变换,即便这个transform属性值不会改变其任何表面的变化(如scale(1), translate(0 ...

  2. 《高级Web应用程序设计》课程学习资料

    任务1:什么是ASP.NET MVC 1.1  ASP.NET MVC简介 1.2 认识ASP.NET MVC项目结构 1.3 ASP.NET MVC生命周期 任务2:初识ASP.NET MVC项目开 ...

  3. Spring知识点

    IOC: Inversion of Control 控制反转 ①自己控制→容器控制 ②控制具体实现→控制抽象(接口) DI:Dependency Injection 依赖注入 依赖于容器注入的对象 注 ...

  4. hdu 1532(最大流)

    Drainage Ditches Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  5. uva 211(dfs)

    211 - The Domino Effect Time limit: 3.000 seconds A standard set of Double Six dominoes contains 28 ...

  6. javascript 特殊的一些知识

    基础知识 1.注释/**/ 块注释,与正则表达式有冲突,不安全. 2.js数字类型只有一个,即为64位的浮动值 3.NaN是一个数值,他不能产生正常结果的运算结果.NaN不等于任何值,包括它自己.is ...

  7. 使用urllib编写python爬虫

    新版python中,urllib和urllib2合并了,统一为urllib (1)简单爬取网页 import urllib content = urllib.request.urlopen(req). ...

  8. 简单json语句转化为map保存

    主要用到了 net.sf.json.JSONObject类 需要用到的jar包 : jar包下载地址 package test; import java.io.BufferedReader; impo ...

  9. Linux驱动之HelloWorld

    最近看android的一些源码,里面有一些功能是用驱动实现的.于是就兴起看了一些驱动相关的东西,准备日后深入.这没有技术含量的水文,仅作为日后的备忘吧. 系统使用的是ubuntu 12.0.04,内核 ...

  10. c#用牛顿法计算根号下2的值

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...