首页 > 编程知识 正文

Hadoop HDFS FileSystem详解

时间:2023-05-04 10:37:16 阅读:237040 作者:2275

背景介绍

Hadoop实现了一套分布式文件系统HDFS,当使用Hadoop的API进行开发,使用HDFS文件系统的时候,必定会用到Hadoop中的FileSystem抽象类,通过FileSystem类的get的方法获取FileSystem的实例,并通过该实例来进行文件系统的操作。

FileSystem fs = FileSystem.get(cfg);

 对于该场景,我们可能会有如下疑问:

FileSystem是一个抽象类,那用来HDFS文件系统的具体实现类是哪一个呢?通过FileSystem的get方法,是如何获取到HDFS文件系统实例的呢?Hadoop并不仅支持HDFS文件系统,还支持非常多样的第三方文件系统,如:Amazon S3,当使用这些第三方文件系统的时候,也是用同样的方法来获取文件系统实例的,FileSystem是如何做到的呢?

接下来将一一讲解这些问题。
问题分析

首先看一下FileSystem类的get方法具体实现:

/** * Returns the configured filesystem implementation. * @param conf the configuration to use */ public static FileSystem get(Configuration conf) throws IOException { return get(getDefaultUri(conf), conf); } /** Get the default filesystem URI from a configuration. * @param conf the configuration to use * @return the uri of the default filesystem */ public static URI getDefaultUri(Configuration conf) { return URI.create(fixName(conf.get(FS_DEFAULT_NAME_KEY, DEFAULT_FS))); }

该静态方法首先从配置文件中读取了URI信息,并调用了另一个异构get方法。如果是使用HDFS文件系统,其URI为hdfs://;如果没有配置,默认使用的是本地文件系统,URI为:file://。

/** Returns the FileSystem for this URI's scheme and authority. The scheme * of the URI determines a configuration property name, * <tt>fs.<i>scheme</i>.class</tt> whose value names the FileSystem class. * The entire URI is passed to the FileSystem instance's initialize method. */ public static FileSystem get(URI uri, Configuration conf) throws IOException { String scheme = uri.getScheme(); String authority = uri.getAuthority(); if (scheme == null && authority == null) { // use default FS return get(conf); } if (scheme != null && authority == null) { // no authority URI defaultUri = getDefaultUri(conf); if (scheme.equals(defaultUri.getScheme()) // if scheme matches default && defaultUri.getAuthority() != null) { // & default has authority return get(defaultUri, conf); // return default } } String disableCacheName = String.format("fs.%s.impl.disable.cache", scheme); if (conf.getBoolean(disableCacheName, false)) { return createFileSystem(uri, conf); } return CACHE.get(uri, conf); }

这个get方法判断了是否配置了FileSystem实例的缓存功能。如果配置为true,当使用get获取实例的时候,如果先前创建的实例还可用,则使用已经存在的实例,而不进行重新创建。

接下来我们直接看创建实例的方法,不对cache功能进行深入分析。createFileSystem方法如下:

private static FileSystem createFileSystem(URI uri, Configuration conf ) throws IOException { Class<?> clazz = getFileSystemClass(uri.getScheme(), conf); if (clazz == null) { throw new IOException("No FileSystem for scheme: " + uri.getScheme()); } FileSystem fs = (FileSystem)ReflectionUtils.newInstance(clazz, conf); fs.initialize(uri, conf); return fs; }该方法首先通过URI的前缀获取了URI中描述的文件系统的具体实现类,然后通过反射机制创建出FileSystem的实例。

接下来看下getFileSystemClass方法的实现,查看如何通过URI前缀获取相应文件系统的具体实现类。

public static Class<? extends FileSystem> getFileSystemClass(String scheme, Configuration conf) throws IOException { if (!FILE_SYSTEMS_LOADED) { loadFileSystems(); } Class<? extends FileSystem> clazz = null; if (conf != null) { clazz = (Class<? extends FileSystem>) conf.getClass("fs." + scheme + ".impl", null); } if (clazz == null) { clazz = SERVICE_FILE_SYSTEMS.get(scheme); } if (clazz == null) { throw new IOException("No FileSystem for scheme: " + scheme); } return clazz; }
该方法首先判断了file system是否已经加载,如果未加载,则加载file system相关的信息。具体加载内容如下:

private static void loadFileSystems() { synchronized (FileSystem.class) { if (!FILE_SYSTEMS_LOADED) { ServiceLoader<FileSystem> serviceLoader = ServiceLoader.load(FileSystem.class); for (FileSystem fs : serviceLoader) { SERVICE_FILE_SYSTEMS.put(fs.getScheme(), fs.getClass()); } FILE_SYSTEMS_LOADED = true; } } }这里通过了Java中的ServiceLoader加载了FileSystem的服务,所谓的FileSystem服务就是实现了FileSystem抽象类的具体实现类,具体ServiceLoader的相关介绍请看 ServiceLoader详解。

通过ServiceLoader,把META-INF/services中描述的FileSystem服务的具体实现类加载进来了,并获取各个类的前缀和类,从而使得在getFileSystemClass方法中通过URI前缀,获取相应的实现类,并返回去创建相应实例。

通过以上的几个主要的方法,Hadoop把文件系统进行了抽象,提供给用户统一的接口进行文件系统的操作,另外也提供了统一的实现方式,可以更方便的集成第三方的文件系统。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。