hdfs设计原则
1.非常大的文件:
这里的非常大是指几百MB,GB,TB.雅虎的hadoop集群已经可以存储PB级别的数据
2.流式数据访问:
基于一次写,多次读。
3.商用硬件:
hdfs的高可用是用软件来解决,因此不需要昂贵的硬件来保障高可用性,各个生产商售卖的pc或者虚拟机即可。
hdfs不适用的场景
hdfs block
1 为了最小化查找时间比例,hdfs的块要比磁盘的块大很多。hdfs块的大小默认为64MB,和文件系统的块不同,默认大小可以修改
2 hdfs的文件可以小于块大小,并且不会占满整个块大小
3 做个统数据统计:
查找时间在10ms左右,数据传输几率在100MB/s,为了使查找时间是传输时间的1%,块的大小必须在100MB左右,一般都会设置为128MB
在有了块概念后,hdfs增加如下优点:(这三个没看出来是多大的优点,或许是对hdfs理解不深入吧)
namenodes和datanodes
hdfs Federation
hdfs的高可用
不管namenode节点的备份还是第二namenode节点都只能保证数据的恢复,并不能保证hdfs的高可用性,
failover和fencing
static FileSystem getFileSystem() {
try {
return FileSystem.get(new URI(PATH), new Configuration());
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
return null;
}
new Configuration(), 查看源代码发现有如下写法
addDefaultResource("core-default.xml");
addDefaultResource("core-site.xml");
会自动加载hdfs的这两个核心文件
写数据
FileSystem类有很多种创建文件的方法,最简单的一种是
public FSDataOutputStream create(Path f) throws IOException
它还有很多重载方法,可以指定是否强制覆盖已存在的文件,文件的重复因子,写缓存的大小,文件的块大小,文件的权限等。
还可以指定一个回调接口:
public interface Progressable {
void progress();
}
和普通文件系统一样,也支持apend操作,写日志时最常用
public FSDataOutputStream append(Path f) throws IOException
但并非所有hadoop文件系统都支持append,hdfs支持,s3就不支持。
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.util.Progressable;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
public class FileCopyWithProgress {
public static void main(String[] args) throws Exception {
String localSrc = args[0];
String dst = args[1];
InputStream in = new BufferedInputStream(new FileInputStream(localSrc));
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(dst), conf);
OutputStream out = fs.create(new Path(dst), new Progressable() {
@Override
public void progress() {
System.out.print(".");
}
});
IOUtils.copyBytes(in, out, 4096, true);
FileStatus
封装了hdfs文件和目录的元数据,包括文件的长度,块大小,重复数,修改时间,所有者,权限等信息,FileSystem的getFileStatus可以获得这些信息
Listing files
PathFilter
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.PathFilter;
public class RegexExludePathFilter implements PathFilter {
private final String regex;
public RegexExludePathFilter(String regex) {
this.regex = regex;
}
@Override
public boolean accept(Path path) {
return !path.toString().matches(regex);
}
}
File patterns
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.fs.Path;
import java.io.IOException;
import java.net.URI;
public class GlobStatus {
public static void main(String[] args) throws IOException {
String uri = args[0];
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(uri), conf);
FileStatus[] status = fs.globStatus(new Path(uri),new RegexExludePathFilter("^.*/1901"));
Path[] listedPaths = FileUtil.stat2Paths(status);
for (Path p : listedPaths) {
System.out.println(p);
}
}
}
删除数据
public abstract boolean delete(Path f, boolean recursive) throws IOException
package hdfs;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
// 使用 hadoop的FileSystem API进行文件操作
public class FileSystemHdfs {
static final String PATH = "hdfs://master:9000/"; // 本机host中已经配置 192.168.1.105 master
static final String DIR = "/d1";
static final String FILE = "/d1/file";
public static void main(String[] args) {
// 获取hadoop文件系统
FileSystem fileSystem = getFileSystem();
// 创建文件夹
//mkdir(fileSystem);
// 上传文件
//putData(fileSystem);
// 下载文件
//getData(fileSystem);
// 浏览文件夹
list(fileSystem);
// 删除文件
//remove(fileSystem);
}
private static void list(FileSystem fileSystem) {
try {
FileStatus[] filesStatus = fileSystem.listStatus(new Path("/"));
for (FileStatus fileStatus : filesStatus) {
String isDir = fileStatus.isDir()?"文件夹":"文件";
String permission = fileStatus.getPermission().toString();
short replication = (short) fileStatus.getBlockSize();
long len = fileStatus.getLen();
String path = fileStatus.getPath().toString();
System.out.println(isDir+"\t"+permission+"\t"+replication+"\t"+len+"\t"+path);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void getData(FileSystem fileSystem) {
try {
FSDataInputStream in = fileSystem.open(new Path(FILE));
IOUtils.copyBytes(in, System.out, 1024,true);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void putData(FileSystem fileSystem) {
try {
/**
* * @param in InputStrem to read from
* @param out OutputStream to write to
* 虽然下面定义 hdfs上的FILE文件为输出流感觉和真正JAVA上学的IO 输出流概念正好相反,但是看到IOUtils.copyBytes(in, out, 1024, true)
* 方法中对 in,out的英文解释,你就按照Java世界IO概念的反方向理解吧。
*/
FSDataOutputStream out = fileSystem.create(new Path(FILE));
FileInputStream in = new FileInputStream("E:/yy.txt");
IOUtils.copyBytes(in, out, 1024, true);
} catch (Exception e) {
e.printStackTrace();
}
//fileSystem.geto
}
private static void remove(FileSystem fileSystem) {
try {// true表示递归删除
fileSystem.delete(new Path(DIR), true);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void mkdir(FileSystem fileSystem) {
try {
fileSystem.mkdirs(new Path(DIR));
} catch (IOException e) {
e.printStackTrace();
}
}
// 创建hadoop的文件操作系统 filesystem实例
private static FileSystem getFileSystem() {
try {
return FileSystem.get(new URI(PATH), new Configuration());
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
return null;
}
/**
* new Configuration()会自动加载hdfs的
* addDefaultResource("core-default.xml");
addDefaultResource("core-site.xml");
*/
}