这段时间折腾的都是hadoop和lucene,总结了hadoop在运营过程中出现问题时的解决方案,请大家指教!
HDFS(0.20.2)运营中急救方案
1 Namenode 挂掉(secondarynamenode无影响)
如果Namenode挂掉,如果能立即起来通过,start-dfs.sh 能够重新起来则可以正常使用。否则按照以下操作。下面所有操作前提是有完整的secondarynamenode。
1) 在非secondarynamenode服务器中选择datanode作为namenode。(目前在正式文档中没有发现,建议采用第二种,但在测试中没发现问题)
a) Kill掉所有服务。
b) 修改新namenode服务器 配置文件:core-site.xml,masters,slaves等相关文件。
c) 修改hosts文件
d) 重新配置各节点 ssh ,使新namenode到其他datanode 正常无密码ssh登陆
e) 将运行secondarynamedode机器上的hadoop.tmp.dir/dfs/namesecondary 拷贝到新namenode服务器hadoop.tmp.dir/dfs目录。
f) 将namesecondary改名为name
g) bin/start-dfs.sh启动hdfs。
2) 在非secondarynamenode服务器中选择datanode作为namenode。通过导入以前的检查点来恢复namenode。
a) Kill掉所有服务。
b) 修改新namenode服务器 配置文件:core-site.xml,masters,slaves等相关文件。
c) 修改hosts文件
d) 重新配置各节点 ssh ,使新namenode到其他datanode 正常无密码ssh登陆
e) 在namenode服务器core-site.xml中配置fs.checkpoint.dir(默认是在$hadoop.tmp.dir/dfs/ namesecondary).
<property>
<name>fs.checkpoint.dir</name>
<value>/home/hadoop/hadoop-data/dfs/namesecondary</value>
</property>
f) 将运行secondarynamedode机器上的hadoop.tmp.dir/dfs/namesecondary 拷贝到namenode服务器fs.checkpoint.dir目录.
g) 执行bin/hadoop namenode –importCheckpoint 导入检查点。
h) 执行bin/start-dfs.sh 启动dfs.
2 Datanode挂掉(不带secondarynamenode)
1) 原服务器完全坏掉,起不来,只能引入新的datanode。
i. 从其他datanode拷贝hadoop所有配置到新服务器
ii. 设置hosts,将所有datanodes 和namenode 设置hosts
iii. 设置ssh无密码登陆,并测试
iv. 在namenode conf 的slaves中配置新加datanode
v. 在新加datanode上通过bin/hadoop-daemon.sh start datanode 启动该新datanode。
2) 原服务器可以立即起来
i. 因为namenode slaves有该datanode,可以直接在namenode中执行bin/start-dfs.sh 启动
ii. 也可以在该服务器 通过bin/hadoop-daemon.sh start datanode启动
3 Datanode挂掉(带secondarynamenode)
1) Namenode正常运行情况下,如果该datanode可以立即投入使用,则直接在namenode中执行bin/start-dfs.sh 启动
2) Namenode正常运行情况下,如果该datanode无法使用,则考虑新增datanode,并配置secondarynamenode。
在新节点 配置文件hdfs-site.xml中 配置:
<property>
<name>dfs.http.address</name>
<value>netease-namenode-test:50070</value>
</property>
该配置在namenode使用默认即可。如果添加上通过外网访问netease-namenode-test:50070可能会由于网段不同导致访问不到。
SequenceFile 解决hadoop小文件问题
OverviewSequenceFile is a flat file consisting of binary key/value pairs. It is extensively used in MapReduce as input/output formats. It is also worth noting that, internally, the temporary outputs of maps are stored using SequenceFile. The SequenceFile provides a Writer, Reader and Sorter classes for writing, reading and sorting respectively. There are 3 different SequenceFile formats:
The recommended way is to use the SequenceFile.createWriter methods to construct the ‘preferred‘ writer implementation. The SequenceFile.Reader acts as a bridge and can read any of the above SequenceFile formats.
SequenceFile FormatsThis section describes the format for the latest ‘version 6‘ of SequenceFiles. Essentially there are 3 different file formats for SequenceFiles depending on whether compression and block compression are active.
SequenceFile Common Header
All strings are serialized using Text.writeString api.
Uncompressed & RecordCompressed Writer Format
The sync marker permits seeking to a random point in a file and then re-synchronizing input with record boundaries. This is required to be able to efficiently split large files for MapReduce processing.
BlockCompressed Writer Format
简介:
SequenceFile 是一个由二进制序列化过的key/value的字节流组成的文本存储文件,它可以在map/reduce过程中的input/output 的format时被使用。在map/reduce过程中,map处理文件的临时输出就是使用SequenceFile处理过的。 SequenceFile分别提供了读、写、排序的操作类。 SequenceFile的操作中有三种处理方式: 1) 不压缩数据直接存储。 //enum.NONE 2) 压缩value值不压缩key值存储的存储方式。//enum.RECORD 3) key/value值都压缩的方式存储。//enum.BLOCK SequenceFile提供了若干Writer的构造静态获取。 //SequenceFile.createWriter(); SequenceFile.Reader使用了桥接模式,可以读取SequenceFile.Writer中的任何方式的压缩数据。 三种不同的压缩方式是共用一个数据头,流方式的读取会先读取头字节去判断是哪种方式的压缩,然后根据压缩方式去解压缩并反序列化字节流数据,得到可识别的数据。 流的存储头字节格式: Header: *字节头”SEQ”, 后跟一个字节表示版本”SEQ4”,”SEQ6”.//这里有点忘了 不记得是怎么处理的了,回头补上做详细解释 *keyClass name *valueClass name *compression boolean型的存储标示压缩值是否转变为keys/values值了 *blockcompression boolean型的存储标示是否全压缩的方式转变为keys/values值了 *compressor 压缩处理的类型,比如我用Gzip压缩的Hadoop提供的是GzipCodec什么的.. *元数据 这个大家可看可不看的 所有的String类型的写操作被封装为Hadoop的IO API,Text类型writeString()搞定。 未压缩的和只压缩values值的方式的字节流头部是类似的: *Header *RecordLength记录长度 *key Length key值长度 *key 值 *是否压缩标志 boolean *values package com.netease.hadooplucene.lucene.test;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.lang.String;
import java.lang.Object;
import java.net.URI;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.conf.*;
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapred.*;
import org.apache.hadoop.util.*;
import org.apache.hadoop.io.compress.*;
import org.apache.hadoop.fs.*;
import
com.netease.hadooplucene.lucene.util.HadoopService;
public class SequenceFileTest {
public static void
writeSequceFile(String uri)throws IOException{
FileSystem fs =
HadoopService.getInstance().getHDFSClient();
Path path = new
Path(uri);
IntWritable key = new
IntWritable();
Text value = new
Text();
SequenceFile.Writer writer
= null;
try {
writer =
SequenceFile.createWriter(fs, fs.getConf(), path, key.getClass(),
value.getClass());
for (int i =
0; i < 100; i++) {
String tt = String.valueOf(100 - i);
key.set(i);
value.set(tt);
System.out.printf("[%s]/t%s/t%s/n", writer.getLength(), key,
value);
writer.append(key, value);
}
} finally {
IOUtils.closeStream(writer);
}
}
// public static File getFile(String
uri){
// FileSystem fs =
HadoopService.getInstance().getHDFSClient();
// Path path = new
Path(uri);
// SequenceFile.Reader
reader=new SequenceFile.Reader(fs, path, fs.getConf());
// reader.
// reader.
// }
public static void main(String[] args)
throws IOException {
String uri =
args[0];
// Configuration conf = new
Configuration();
// FileSystem fs =
FileSystem.get(URI.create(uri), conf);
}
}
前天项目组里遇到由于sequenceFile 的压缩参数设置为record 而造成存储空间的紧张,后来设置为block 压缩方式的压缩方式,存储空间占用率为record 方式的1/5 。问题虽解决了,但是还不是很清楚这两种方式是如何工作以及他们的区别是啥。昨天和今天利用空闲时间,细细的看了一遍sequenceFile 这个类和一些相关类的源码。 sequenceFile 文件存储有三种方式:可以通过在程序调用 enum CompressionType { NONE , RECORD , BLOCK } 指定,或通过配置文件io.seqfile.compression.type 指定,这三种存储方式如下图:
对于Record 压缩这种存储方式,RecordLen 表示的是key 和value 的占用的byte 之和,Record 压缩方式中 key 是不压缩 ,value 是压缩后的值,在record 和非压缩这两种方式,都会隔几条记录插入一个特殊的标号来作为一个同步点Sync ,作用是当指定读取的位置不是记录首部的时候,会读取一个同步点的记录,不至于读取数据的reader “迷失”。 每两千个byte 就插入一个同步点,这个同步点占16 byte ,包括同步点标示符:4byte ,一个同步点的开销是20byte 。 对于block 这种压缩方式, key 和value 都是压缩的 ,通过设置io.seqfile.compress.blocksize 这个参数决定每一个记录块压缩的数据量,默认大小是1000000 byte ,这个值具体指的是key 和value 缓存所占的空间,每要往文件写一条key/value 时,都是将key 和value 的长度以及key 和value 的值缓存在keyLenBuffer keyBuffer valLenBuffer valBuffer 这四个DataOutputStream 中,当keyBuffer.getLength() + valBuffer.getLength() 大于或等于io.seqfile.compress.blocksize 时,将这些数据当做一个block 写入sequence 文件,如上图所示 每个block 之间都会插入一个同步点。 |
使secondarynamenode能够post请求到namenode。
然后在namenode masters中增加 新的secondarynamenode 并配置hosts
使用bin/start-dfs.sh 启动。