设为首页 收藏本站
查看: 1079|回复: 0

[经验分享] hadoop_hdfs_基础知识和java调用写法

[复制链接]

尚未签到

发表于 2016-12-11 10:36:38 | 显示全部楼层 |阅读模式
hdfs设计原则
  1.非常大的文件:
  这里的非常大是指几百MB,GB,TB.雅虎的hadoop集群已经可以存储PB级别的数据
  2.流式数据访问:
  基于一次写,多次读。
  3.商用硬件:      
   hdfs的高可用是用软件来解决,因此不需要昂贵的硬件来保障高可用性,各个生产商售卖的pc或者虚拟机即可。

hdfs不适用的场景

1.低延迟的数据访问   

hdfs的强项在于大量的数据传输,递延迟不适合他,10毫秒以下的访问可以无视hdfs,不过hbase可以弥补这个缺陷。

 

2.太多小文件              

 namenode节点在内存中hold住了整个文件系统的元数据,因此文件的数量就会受到限制,每个文件的元数据大约150字节

 1百万个文件,每个文件只占一个block,那么就需要300MB内存。你的服务器可以hold住多少呢,你可以自己算算

 

3.多处写和随机修改   

目前还不支持多处写入以及通过偏移量随机修改

 

hdfs block
  1 为了最小化查找时间比例,hdfs的块要比磁盘的块大很多。hdfs块的大小默认为64MB,和文件系统的块不同,默认大小可以修改
  2 hdfs的文件可以小于块大小,并且不会占满整个块大小
  3 做个统数据统计:
  查找时间在10ms左右,数据传输几率在100MB/s,为了使查找时间是传输时间的1%,块的大小必须在100MB左右,一般都会设置为128MB
  在有了块概念后,hdfs增加如下优点:(这三个没看出来是多大的优点,或许是对hdfs理解不深入吧)

1.可以存储比单个磁盘更大的文件

2.存储块比存储文件更加简单,每个块的大小都基本相同

3.使用块比文件更适合做容错性和高可用

   

 
namenodes和datanodes

hdfs集群有两种类型的节点,一种为master及namenode,另一种为worker及datanodes。

 

namenode节点管理文件系统的命名空间。它包含一个文件系统的树,所有文件和目录的原数据都在这个树上,这些信息被存储在本地磁盘的两个文件中,image文件和edit log文件。


文件相关的块存在哪个块中,块在哪个地方,这些信息都是在系统启动的时候加载到namenode的内存中


datanode节点在文件系统中充当的角色就是苦力,按照namenode和client的指令进行存储或者检索block,并且周期性的向namenode节点报告它存了哪些文件的block


 

namenode节点如果不能使用了,那么整个hdfs就玩完了,为了防止这种情况,有两种方式可供选择

1.namenode通过配置元数据可以写到多个磁盘中,最好是独立的磁盘,或者NFS.

2 使用第二namenode节点(secondnamenode),第二namenode节点平时并不作为namenode节点工作,

它的主要工作内容就是定期将编辑日志(edit log)合并到namespace image中,并清空 edit log,

合并后的image它自己也保留一份,等着namenode节点挂掉,然后它可以转正,由于不是实时的,


有数据上的损失是很可能发生的。

 

 

 
hdfs Federation

namenode节点保持所有的文件和块的引用在内存中,这就意味着在一个拥有很多很多文件的很大的集群中,内存就成为了一个

限制的条件,hdfs federation在hadoop 2.x的被实现了,允许hdfs有多个namenode节点,每个管hdfs的一部分,比如一个管/usr,

另一个管/home,每个namenode节点是相互隔离的,一个挂掉不会影响另外一个。

 

hdfs的高可用
  不管namenode节点的备份还是第二namenode节点都只能保证数据的恢复,并不能保证hdfs的高可用性,

一旦namenode节点挂掉就会产生单点故障,这时候要手动去数据恢复,并且启用第二name节点


新的namenode节点在对外服务器要做三件事:

1.把命名空间的镜像加载到内存中

2.重新运行编辑日志

3.接受各个datanode节点的block报告

在一个大型一点的hdfs系统中,等这些做完需要30分钟左右。

 

 
hadoop2.x已经支持了高可用性(HA),通过一对namenode热备来实现,一台挂掉,备机马上提供无中断服务

要实现HA,要做三点微调:

1.namenode节点必须使用高可用的共享存储。

2.datanode节点必须象两个namenode节点发送block报告

3.客户端做改动可以在故障时切换到可用的namenode节点上,而且要对用户是无感知的

 

failover和fencing

将备份namenode激活的过程就叫failover,管理激活备份namenode的系统叫做failover controller,

zookeeper就可以担当这样的角色,可以保证只有一个节点处于激活状态。

必须确认原来的namenode已经真的挂掉了,很多时候只是网络延迟,如果备份节点已经激活了,

原来的节点又可以提供服务了,这样是不行的,防止原来namenode活过来的过程就叫fencing。

可以用STONITH实现, STONITH可以做到直接断电把原namenode节点fencing掉

 

 

java操作hdfs最核心的类就是
FileSystem, 可以通过如下代码创建此对象:



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就不支持。

以下是个拷贝本地文件到hdfs的例子

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

有时候你可能会需要找一组符合要求的文件,那么下面的示例就可以帮到你,通过FileSystem的listStatus方法可以获得符合条件的一组FileStatus对象,listStatus有几个重载的方法,可以传入多个路径,还可以使用PathFilter做过滤




 

 
PathFilter

接着上面我们来讲PathFilter接口,该接口只需实现其中的一个方法即可,即accpet方法,方法返回true时表示被过滤掉,
我们来实现一个正则过滤,并在下面的例子里起作用


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



当需要很多文件时,一个个列出路径是很不便捷的,hdfs提供了一个通配符列出文件的方法,通过FileSystem的globStatus方法提供了这个便捷,globStatus也有重载的方法,使用PathFilter过滤,那么我们结合两个来实现一下



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


第一个参数很明确,第二个参数表示是否递归删除子目录或目录下的文件,在Path为目录但目录是空的或者Path为文件时可以忽略,但如果Path为目录且不为空的情况下,如果recursive为false,那么删除就会抛出io异常。







 







下面贴上java操作hdfs的一些简单代码:

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");
*/

}
 

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-312700-1-1.html 上篇帖子: 如何查看Hadoop运行过程中产生日志 下篇帖子: 《用 Hadoop 进行分布式并行编程, 第 2 部分——程序实例与分析》笔记
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表