日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當前位置:首頁 > 單片機 > 架構師社區(qū)
[導讀]本文將通過一個演示工程來快速上手java調(diào)用HDFS的常見操作。接下來以創(chuàng)建文件為例,通過閱讀HDFS的源碼,一步步展開HDFS相關原理、理論知識的說明。 說明:本文檔基于最新版本Hadoop3.2.1 目錄: 一、java調(diào)用HDFS的常見操作 1.1、演示環(huán)境搭建 1.2、操作HDFS

本文將通過一個演示工程來快速上手java調(diào)用HDFS的常見操作。接下來以創(chuàng)建文件為例,通過閱讀HDFS的源碼,一步步展開HDFS相關原理、理論知識的說明。

說明:本文檔基于最新版本Hadoop3.2.1


目錄:

一、java調(diào)用HDFS的常見操作

1.1、演示環(huán)境搭建

1.2、操作HDFS

1.3、java文件操作常用方法

二、深入了解HDFS寫文件的流程和HDFS原理

2.1、Hadoop3.2.1 源碼下載及介紹

2.2、文件系統(tǒng):FileSystem

2.3、HDFS體系結構:namenode、datanode、數(shù)據(jù)塊

2.4、如何訪問阿里云OSS等文件系統(tǒng)

2.5、文件租約機制

2.6、RPC機制

2.7、HAState:active、standby

2.8、Hadoop3.x新特性:糾刪碼

2.9、文件透明加密處理和目錄樹

2.10、HDFS客戶端寫流程總結


一、java調(diào)用HDFS的常見操作

首先我們搭建一個簡單的演示工程(演示工程使用的gradle,Maven項目也同樣添加以下依賴),本次使用的是Hadoop最新的3.2.1。

1.1、演示環(huán)境搭建

新增一個普通的java工程即可,過程略,添加hdfs相關依賴jar包

implementation ('org.apache.hadoop:hadoop-common:3.2.1')
implementation ('org.apache.hadoop:hadoop-hdfs:3.2.1')
implementation ('org.apache.hadoop:hadoop-mapreduce-client-core:3.2.1')
implementation ('org.apache.hadoop:hadoop-client:3.2.1')

在實際運行過程中,可能會發(fā)現(xiàn)日志Jar包沖突問題,排除掉即可

exclude group:'org.slf4j',module: 'slf4j-log4j12'

1.2、操作HDFS

以創(chuàng)建文件為例,代碼如下。可以看到java操作hdfs就是這么簡單、絲滑,so easy!

    publicstaticvoidmain(String[] args)throws IOException {
// 配置對象
Configuration configuration = new Configuration();
configuration.set("fs.defaultFS", "hdfs://172.22.28.202:9000");
// HDFS文件系統(tǒng)的操作對象
FileSystem fileSystem = FileSystem.get(configuration);
// 創(chuàng)建文件。
FSDataOutputStream outputStream =
fileSystem.create(new Path("/hdfs/madashu/test"));
// 寫入文件內(nèi)容
outputStream.write("你好Hadoop,我是碼大叔".getBytes());
outputStream.flush();
IOUtils.closeStream(outputStream);
}

1.3、java文件操作常用方法

參照第2步文件創(chuàng)建的操作,我們可以預定義好Configuration和FileSystem,然后提取出HDFSUtil的工具類出來。涉及到文件方面的操作基本只需要hadoop-common包下的FileSystem就足夠了,一些常用方法的說明:

//文件是否存在
fileSystem.exists(new Path(fileName));
//創(chuàng)建目錄
fileSystem.mkdirs(new Path(directorName));
//刪除目錄或文件,第二個參數(shù)表示是否要遞歸刪除
fileSystem.delete(new Path(name), true);
//獲取當前登錄用戶在HDFS文件系統(tǒng)中的Home目錄
fileSystem.getHomeDirectory();
//文件重命名
fileSystem.rename(new Path(oldName), new Path(newName));
//讀取文件,返回的是FSDataInputStream
fileSystem.open(new Path(fileName));
//創(chuàng)建文件,第二個參數(shù)表示文件存在時是否覆蓋
fileSystem.create(new Path(fileName), false);
//從本地目錄上傳文件到HDFS
fileSystem.copyFromLocalFile(localPath, hdfsPath);
//獲取目錄下的文件信息,包含path,length,group,blocksize,permission等等
fileSystem.listStatus(new Path(directorName));
//釋放資源
fileSystem.close();
//設置HDFS資源權限,其中FsPermission可以設置user、group等
fileSystem.setPermission(new Path(resourceName), fsPermission);
//設置HDFS資源的Owner和group
fileSystem.setOwner(new Path(resourceName), ownerName, groupName);
//設置文件的副本
fileSystem.setReplication(new Path(resourceName), count);

二、深入了解HDFS寫文件的流程和HDFS原理

文件操作的方法比較多,本期我們以create方法為例,來通過閱讀源碼深入了解下hdfs寫文件的流程和原理,代碼參見1.2 。

2.1、Hadoop3.2.1 源碼下載及介紹

hadoop源碼地址:https://github.com/apache/hadoop,。
正常途徑下訪問比較慢的同學(每次寫到這句話,都滿臉的憂傷和xx)也可以通過國內(nèi)的清華大學開源軟件鏡像站來下載,地址是https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common/hadoop-3.2.1/hadoop-3.2.1-src.tar.gz

下載后我們可以看到這是一個maven工程,導入到idea等我們熟悉開發(fā)工具中即可。如果是使用VS需要編譯的小伙伴注意下,
讀Hadoop3.2源碼,深入了解java調(diào)用HDFS的常用操作和HDFS原理
目錄下有一個BUILDINDG.txt文件,針對比較關鍵的幾個modules做了說明。
讀Hadoop3.2源碼,深入了解java調(diào)用HDFS的常用操作和HDFS原理
這里面很多工程都是和打包相關的,有一個沒提到的“hadoop-cloud-storage-project”是和云存儲相關的,比如我們熟悉的阿里云,AWS等。這次我們需要關注的是hadoop-hdfs-project,hadoop-hdfs-common-project。

2.2、文件系統(tǒng):FileSystem

代碼參見1.2,我們看到在操作hdfs之前首先需要根據(jù)配置文件獲取文件系統(tǒng)。
問題
1、為什么傳入的地址是“hdfs:”開頭的
2、為什么要獲取文件操作系統(tǒng)

我們直接進入get方法

  publicstatic FileSystem get(URI uri, Configuration conf)throws IOException {
//獲取文件的前綴,即我們傳入的 hdfs:
String scheme = uri.getScheme();
// 為了便于閱讀,刪除掉很多代碼
// 從緩存中獲取
return CACHE.get(uri, conf);
}

那么緩存中存放了什么呢?一層層深入代碼,首先會檢查文件系統(tǒng)是否存在,不存在則創(chuàng)建文件系統(tǒng),最終將文件系統(tǒng)存放在map中。

 private static final Map<String, Class<? extends FileSystem>>
SERVICE_FILE_SYSTEMS = new HashMap<>();
public final classHdfsConstants{
/**
* URI Scheme for hdfs://namenode/ URIs.
*/

public static final String HDFS_URI_SCHEME = "hdfs";

我們再回過頭來打開FileSystem

public abstract classFileSystemextendsConfiguredimplementsCloseable, DelegationTokenIssuer

可以看到FileSystem是一個抽象類,它有很多的子類即實現(xiàn),比如DistributedFileSystem。所以這一步的操作實際是根據(jù)你輸入的前綴,通過Java中SPI機制從Serviceloder中獲取所需的文件操作系統(tǒng)。這里我們還很驚喜地看到AliyunOSSFileSystem。Hadoop3.x中默認支持阿里云OSS對象存儲系統(tǒng)作為Hadoop兼容的文件系統(tǒng)。阿里云OSS是中國云計算廠商第一個也是目前唯一一個被Hadoop官方版本支持的云存儲系統(tǒng)。這是繼Docker支持阿里云存儲以后又一個更重大的里程碑,這也表明主流開源社區(qū)對中國技術生態(tài)的認可。假如我們要使用阿里云的文件系統(tǒng),前綴是什么呢?翻看AliyunOSSFileSystem代碼

  public String getScheme(){
return "oss";
}

比如 oss://madashu/test。同樣如果需要使用亞馬遜的文件系統(tǒng),則前綴是“abfs://”

2.3、HDFS體系結構:namenode、datanode、數(shù)據(jù)塊

根據(jù)1.2實例代碼,獲取到文件操作系統(tǒng)后,就是創(chuàng)建文件了,最終我們跟蹤到如下的方法

  publicabstract FSDataOutputStream create(Path f,
FsPermission permission,
boolean
int
short
long
throws IOException
;

參數(shù)說明:

  • Path:存放路徑

  • FsPermission:文件權限

  • overwrite:當文件存在時是否覆蓋

  • bufferSize:客戶端的buffer大小

  • replication:文件副本數(shù)

  • blockSize:塊大小

  • Progressable:文件寫入的進度

這里有2個參數(shù):replication和blockSize,在解釋之前得先了解一下HDFS的體系結構
讀Hadoop3.2源碼,深入了解java調(diào)用HDFS的常用操作和HDFS原理HDFS是一個主/從(Master/Slave)體系結構的分布式系統(tǒng),將一個大文件分成若干塊保存在不同服務器的多個節(jié)點中,通過聯(lián)網(wǎng)讓用戶感覺像是在本地一樣查看文件。HDFS集群擁有1個Namenode和n個Datanode,用戶可以通過HDFS客戶端和Namenode、Datanodes交互以訪問文件系統(tǒng)。

Namenode是HDFS的master節(jié)點,負責管理文件系統(tǒng)的命名空間,即namespace,它維護這文件系統(tǒng)樹及整棵樹內(nèi)所有的文件和目錄。這些信息以命名空間鏡像文件和編輯日志文件兩個文件持久化保存在文件磁盤上。namenode也留著每個文件中各個塊所在的數(shù)據(jù)節(jié)點信息,但是并不永久保存塊的位置信息,這些塊的位置信息會在系統(tǒng)啟動時根據(jù)數(shù)據(jù)信息節(jié)點創(chuàng)建

Datanode是文件系統(tǒng)的工作節(jié)點,它根據(jù)客戶端或namenode需要存儲并檢索數(shù)據(jù)塊,并且定期向nomenode發(fā)送所存儲的塊的列表。

Block是HDFS的最小存儲單元。默認大?。?28M(HDFS 1.x中,默認64M),若文件大小不足128M,則會單獨成為一個block。實質上就是Linux相應目錄下的普通文件,名稱格式:blk_xxxxxxx。

HDFS塊為什么這么大呢?HDFS的塊比磁盤的塊大,主要是為了最小化尋址的開銷。如果塊足夠大,從磁盤傳輸數(shù)據(jù)的時間會明顯大于定位這個塊開始位置所需的時間。因而,傳輸一個由多個塊組成的大文件的時間取決于磁盤傳輸速率。如果一個1MB的文件存儲在一個128M的塊中時,文件實際只是用了1M的磁盤空間,而不是128M。

為了降低文件丟失造成的錯誤,它會為每個小文件復制多個副本(默認為三個),以此來實現(xiàn)多機器上的多用戶分享文件和存儲。
第一個復本會隨機選擇,但是不會選擇存儲過滿的節(jié)點。
第二個復本放在和第一個復本不同且隨機選擇的機架上。
第三個和第二個放在同一個機架上的不同節(jié)點上。
剩余的副本就完全隨機節(jié)點了。

補充1:create方法還有最后一個參數(shù):Progressable,主要是為了便于我們知悉文件的寫入進度,使用方法如下:

    FSDataOutputStream outputStream = fileSystem.create(new Path(targetDirector +   File.separator + fileName), new Progressable() {
long fileCount = 0;
@Override
publicvoidprogress(){
fileCount++;
System.out.println("總進度:" + fileCount + "|" + fileSize + "|" + (fileCount / fileSize) * 100 + "%");
}
});

補充2:在Hadoop3.2中namenode的默認端口配置發(fā)生變化:從50070改為9870

2.4、如何訪問阿里云OSS等文件系統(tǒng)

我們繼續(xù)往下扒代碼

@Override
public FSDataOutputStream create(final Path f, final
final EnumSet<CreateFlag> cflags, finalint
finalshort replication, finallong
final Progressable progress, final ChecksumOpt checksumOpt)
throws IOException
{
// 文件操作統(tǒng)計,比如創(chuàng)建、刪除、拷貝等等,以及操作次數(shù)
statistics.incrementWriteOps(1);
storageStatistics.incrementOpCounter(OpType.CREATE);
// 創(chuàng)建文件輸出流,采用了責任鏈的設計模式
Path absF = fixRelativePart(f);
return new FileSystemLinkResolver<FSDataOutputStream>() {
@Override
public FSDataOutputStream doCall(final Path p)throws IOException {
final DFSOutputStream dfsos = dfs.create(getPathName(p), permission,
cflags, replication, blockSize, progress, bufferSize,
checksumOpt);
return dfs.createWrappedOutputStream(dfsos, statistics);
}
@Override
public FSDataOutputStream next(final FileSystem fs, final Path p)
throws IOException
{
return fs.create(p, permission, cflags, bufferSize,
replication, blockSize, progress, checksumOpt);
}
}.resolve(this, absF);
}

接下來再進入FileSystemLinkResolver類:
1、調(diào)用doCall 內(nèi)部類 DFSClient的create方法,然后將DFSOutputStream包裝FSDataOutputStream
2、如果是符號鏈接文件,則一層一層找到最底層的文件。甚至能連接到其他的文件系統(tǒng)的文件,比如從HDFS文件系統(tǒng)連接到阿里云OSS文件系統(tǒng)、亞馬遜文件系統(tǒng)等。

2.5、文件租約機制

繼續(xù)跟蹤代碼,進入DFSClient

  public DFSOutputStream create
boolean createParent, short
long blockSize, Progressable progress, int buffersize,
ChecksumOpt checksumOpt, InetSocketAddress[] favoredNodes,
String ecPolicyName)
throws IOException
{
//檢查客戶端是否已經(jīng)在運行了
checkOpen();
final FsPermission masked = applyUMask(permission);
LOG.debug("{}: masked={}", src, masked);
//創(chuàng)建文件輸出流,和Namenode進行交互
final DFSOutputStream result = DFSOutputStream.newStreamForCreate(this,
src, masked, flag, createParent, replication, blockSize, progress,
dfsClientConf.createChecksum(checksumOpt),
getFavoredNodesStr(favoredNodes), ecPolicyName);
//更新文件租約:也可以理解為token,保證不會發(fā)生寫文件沖突。
beginFileLease(result.getFileId(), result);
return result;
}

我們看到最后一個beginFileLease操作,也就是獲取文件租約。我們暫時先忽略文件創(chuàng)建的過程,繼續(xù)往下翻和FileLease有關的代碼:

  //如果是第一次,還是設置文件租約。
stat = FSDirWriteFileOp.startFile(this, iip, permissions, holder,
clientMachine, flag, createParent, replication, blockSize, feInfo,
toRemoveBlocks, shouldReplicate, ecPolicyName, logRetryCache);
//設置文件租約的方法見FSDirWriteFileOp
fsn.leaseManager.addLease(
newNode.getFileUnderConstructionFeature().getClientName(),
newNode.getId());

FileLease:文件租約,HDFS給客戶端發(fā)放一個寫文件操作的臨時許可證,只有持有該證件者才允許操作此文件,從而保證保證數(shù)據(jù)的一致。

  • 每個客戶端用戶持有一個文件租約。

  • 每個文件租約內(nèi)部包含有一個租約持有者信息,還有租約對應的文件Id列表,即當前租約持有者正在寫這些文件Id對應的文件。

  • 每個文件租約內(nèi)包含有一個最新近更新時間,最近更新時間將會決定此租約是否已過期。過期的租約會導致租約持有者無法繼續(xù)執(zhí)行寫數(shù)據(jù)到文件中,除非進行租約的更新。

既然每個客戶端都有一個文件租約,那么HDFS如如何管理的呢?比如有些客戶端用戶寫某文件后未及時關閉此文件。這樣會導致租約未釋放,從而造成其他用戶無法對此文件進行寫操作。答案就是LeaseManager,運行在Active NameNode的服務中。它主要做2件事:
1、維護HDFS內(nèi)部當前所有的租約,
2、定期釋放過期的租約對象。

補充:HDFS 只允許對一個已打開的文件順序寫入,或者在現(xiàn)有文件的末尾追加數(shù)據(jù)。

2.6、RPC機制

接下來我們的代碼將進入DFSOutputStream.newStreamForCreate()方法

//調(diào)用namenode的文件創(chuàng)建方法
stat = dfsClient.namenode.create(src, masked, dfsClient.clientName,
new EnumSetWritable<>(flag), createParent, replication,
blockSize, SUPPORTED_CRYPTO_VERSIONS, ecPolicyName)

我們再次暫停一下,點擊“這里的namenode實際是ClientProtocol

ClientProtocol is used by user code via the DistributedFileSystem class to communicate with the NameNode. User code can manipulate the directory namespace, as well as open/close file streams, etc.

ClientProtocol用來通過DistributedFileSystem類與NameNode通信。可以操作目錄名稱空間,以及打開/關閉文件流等。ClientProtocol是一個接口,它的實現(xiàn)類有:

讀Hadoop3.2源碼,深入了解java調(diào)用HDFS的常用操作和HDFS原理
我們進入NameNodeRpcServer.create()方法

 @Override 
public HdfsFileStatus create(String src, FsPermission masked,
String clientName, EnumSetWritable<CreateFlag> flag,
boolean createParent, short replication, long

throws IOException
{
//確認namenode已啟動
checkNNStartup();
// 獲取服務端ip
String clientMachine = getClientMachine();
if (stateChangeLog.isDebugEnabled()) {
stateChangeLog.debug("*DIR* NameNode.create: file "
+src+" for "+clientName+" at "+clientMachine);
}
//檢查是否可以寫入。在生成上namenode正常也會進行HA,保證高可用。只有主的才可以寫入,
if (!checkPathLength(src)) {
throw new IOException("create: Pathname too long. Limit "
+ MAX_PATH_LENGTH + " characters, " + MAX_PATH_DEPTH + " levels.");
}
namesystem.checkOperation(OperationCategory.WRITE);
CacheEntryWithPayload cacheEntry = RetryCache.waitForCompletion(retryCache, null);
if (cacheEntry != null && cacheEntry.isSuccess()) {
return (HdfsFileStatus) cacheEntry.getPayload();
}

作為分布式文件系統(tǒng),少不了各個節(jié)點之間的通信和交互,比如client和namenode,namenode和datanode,所以需要這樣一套RPC(Remote Procedure CallProtocol,遠程過程調(diào)用協(xié)議)框架,允許程序像調(diào)用本地方法一樣調(diào)用遠程機器上應用程序提供的服務。Hadoop RPC并沒有采用JDK自帶的RMI,據(jù)說基于Google Protocol Buffer(簡稱Protobuf)來實現(xiàn)的。Hadoop的RPC和通用的RPC一樣,包含通信模塊、客戶端Stub程序、服務端Stub程序、請求程序、服務程序等。

讀Hadoop3.2源碼,深入了解java調(diào)用HDFS的常用操作和HDFS原理


Hadoop RCP 主要提供兩個接口

//構造一個客戶端代理對象,用于向服務器發(fā)送RPC請求
public static <T>ProtocolProxy <T> getProxy/waitForProxy()
// 為某個協(xié)議實例構造一個服務器對象,用于處理客戶端發(fā)送的請求
public static Server RPC.Builder (Configuration).build()

2.7 HAState:active、standby

    HdfsFileStatus status = null;
try {
PermissionStatus perm = new PermissionStatus(getRemoteUser()
.getShortUserName(), null, masked);
// 開始創(chuàng)建文件
status = namesystem.startFile(src, perm, clientName, clientMachine,
flag.get(), createParent, replication, blockSize, supportedVersions,
ecPolicyName, cacheEntry != null);
} finally {
RetryCache.setState(cacheEntry, status != null, status);
}

metrics.incrFilesCreated();
metrics.incrCreateFileOps();
return status;
}
 @Override
// 報錯
publicvoidcheckOperation(final OperationCategory op)
throws StandbyException
{
state.checkOperation(haContext, op);
}

在這個代碼里有一個HA狀態(tài)的檢查,standby 只能read,不能write。

  public static final HAState ACTIVE_STATE = new ActiveState();
public static final HAState STANDBY_STATE = new StandbyState();
public static final HAState OBSERVER_STATE = new StandbyState(true);

從Hadoop2開始,增加了對HDFS高可用(HA)的支持,配置了1對active-standby的namenode。當活動的namenode失效,備用的namenode能夠快速(幾十秒的時間)實現(xiàn)任務接管,因為最新的狀態(tài)存儲在內(nèi)存中:包括最新的編輯日志條目和最新的數(shù)據(jù)塊映射信息。實際觀察到的失效時間略長一點,需要1分鐘左右,這是因為系統(tǒng)需要保守確定活動的namenode是否真的失效了。假設活動的namenode和備用的namenode都失效了(人品爆發(fā)了),管理員依舊可以聲明一個備用namenode并實現(xiàn)冷啟動。

【實際開發(fā)踩坑】
在實際開發(fā)過程中,由于配置或者啟動順序的原因,倒是會經(jīng)查遇到standby的問題,甚至發(fā)現(xiàn)master和slave兩個NameNode的狀態(tài)均為standby。比如啟動了hdfs再啟動zookeeper 導致zookeeper的選舉機制zkfc(DFSZKFailoverController)沒有格式化 NameNode節(jié)點的自動切換機制沒有開啟 兩個NameNode都處于standby狀態(tài)(解決方案:先啟動zookeeper集群:zkServer.sh start 再啟動hdfs集群FSNamesystem)。

人工查看namenode的方法

sudo -E -u hadoop /home/hadoop/bin/hdfs haadmin -getServiceState nn1

2.8、Hadoop3.x新特性:糾刪碼

private HdfsFileStatus startFileInt(String src,
PermissionStatus permissions, String holder, String clientMachine,
EnumSet<CreateFlag> flag,
boolean createParent, short
long
boolean logRetryCache)throws IOException

//檢查冗余策略:副本或者糾刪碼
boolean shouldReplicate
= flag.contains(CreateFlag.SHOULD_REPLICATE);
//文件寫入鎖
writeLock();
//根據(jù)文件目錄字符串實例化目錄結構。比如/hdfs/madashu,在hdfs里需要把目錄結構映射成對象
iip = FSDirWriteFileOp.resolvePathForStartFile(
dir, pc, src, flag, createParent);

feInfo = FSDirEncryptionZoneOp.getFileEncryptionInfo(
dir, iip, ezInfo);
// 添加到文件目錄樹中:檢查文件是否已經(jīng)存在,是否可覆蓋,文件數(shù)量的限制,糾刪碼格式存儲,獲取糾刪碼策略,創(chuàng)建文件節(jié)點等。

這里面出現(xiàn)了一個新的名詞:糾刪碼,Erasure Coding,EC。前面章節(jié)我們提到了默認情況下,HDFS的數(shù)據(jù)塊都會保存三個副本。副本提供了一種簡單而健壯的冗余方式來最大化保證數(shù)據(jù)的可用性。數(shù)據(jù)的多副本同時可以盡量保證計算任務的本地化。但副本方式成本是較高的:默認情況下三副本方式會在存儲空間或其他資源(比如寫入數(shù)據(jù)時的網(wǎng)絡帶寬)中產(chǎn)生200%的開銷。對于較少訪問的數(shù)據(jù)集(對集群的I/O影響相對不大),它們的第二個或者第三個副本會比較少訪問,但是仍會消耗相同的存儲空間。因此可以使用糾刪碼來代替多副本的方式,它使用更少的存儲卻可以保證相同級別的容錯。在典型配置下,與三副本方式相比,EC可以將存儲成本降低約50%。但同樣他的使用也是需要一些代價的,一旦數(shù)據(jù)需要恢復,他會造成2大資源的消耗:
1、網(wǎng)絡帶寬的消耗,因為數(shù)據(jù)恢復需要去讀其他的數(shù)據(jù)塊和校驗塊
2、進行編碼,解碼計算需要消耗CPU資源
具體可參見https://cloud.tencent.com/developer/article/1363388

2.9、文件透明加密處理和目錄樹

目錄樹
讀Hadoop3.2源碼,深入了解java調(diào)用HDFS的常用操作和HDFS原理
讀Hadoop3.2源碼,深入了解java調(diào)用HDFS的常用操作和HDFS原理
在2.8 的代碼中,還出現(xiàn)了目錄樹和文件加密,這一塊就不做多講了。分享兩個相關的鏈接:
《HDFS文件目錄詳解》https://blog.csdn.net/baiye_xing/article/details/76268495
《HDFS數(shù)據(jù)加密空間--Encryption zone》https://www.cnblogs.com/bianqi/p/12183761.html

2.10、HDFS客戶端寫流程總結

以上源碼才完成了文件創(chuàng)建過程,接下來還需要通過管道方式將文件寫入datanode中去,后續(xù)有機會再和大家一些學習分享。

    // 創(chuàng)建文件。
FSDataOutputStream outputStream =
fileSystem.create(new Path("/hdfs/madashu/test"));
// 寫入文件內(nèi)容
outputStream.write("你好Hadoop,我是碼大叔".getBytes());
outputStream.flush();
IOUtils.closeStream(outputStream);

以下文字來自于《Hadoop權威指南》一書,對HDFS客戶端寫流程進行了總結,作為本文的收尾,向大牛致敬!
讀Hadoop3.2源碼,深入了解java調(diào)用HDFS的常用操作和HDFS原理

1、創(chuàng)建文件
HDFS客戶端寫一個新的文件時,會首先調(diào)用DistributedFileSystem.create()方法在HDFS文件系統(tǒng)中創(chuàng)建一個新的空文件。這個方法在底層會通過調(diào)用ClientProtocol.create()方法通知Namenode執(zhí)行對應的操作,Namenode會首先在文件系統(tǒng)目錄樹中的指定路徑下添加一個新的文件,然后將創(chuàng)建新文件的操作記錄到editlog 中。完ClientProtocol.create()調(diào)用后,DistributedFileSystem.create()方法就會返回一個HdfsDataOutputStream對象,這個對象在底層包裝了一個DFSOutputStream對象,真正執(zhí)行寫數(shù)據(jù)操作的其實是DFSOutputStream對象。
2、 建立數(shù)據(jù)流管道
獲取了DFSOutputStream對象,HDFS客戶端就可以調(diào)用DFSOutputStream.write()方法來寫數(shù)據(jù)了。由于 DistributedFileSystem.create()方法只是在文件系統(tǒng)目錄樹中創(chuàng)建了一個空文件,并沒有申請任何數(shù)據(jù)塊,所以DFSOutputStream 會首先調(diào)用 ClientProtocol.addBlock()向 Namenode 申請一個新的空數(shù)據(jù)塊,addBlock()方法會返冋一個LocatedBlock對象,這個對象保存了存儲這個數(shù)據(jù)塊的所有數(shù)據(jù)節(jié)點的位置信息。獲得了數(shù)據(jù)流管道中所有數(shù)據(jù)節(jié)點的信息后,DFSOutputStream就可以建立數(shù)據(jù)流管道寫數(shù)據(jù)塊了。
3、通過數(shù)據(jù)流管道寫入數(shù)據(jù)
成功地建立數(shù)據(jù)流管道后,HDFS客戶端就可以向數(shù)據(jù)流管道寫數(shù)據(jù)了。寫入DFSOutputStream中的數(shù)據(jù)會先被緩存在數(shù)據(jù)流中,之后這些數(shù)據(jù)會被切分成一個個數(shù)據(jù)包(packet)通過數(shù)據(jù)流管道發(fā)送到所有數(shù)據(jù)節(jié)點。這里的每個數(shù)據(jù)包都會按照上圖所示,通過數(shù)據(jù)流管道依次寫入數(shù)據(jù)節(jié)點的本地存儲。每個數(shù)據(jù)包都有個確認包,確認包會逆序通過數(shù)據(jù)流管道回到輸出流。輸出流在確認了所有數(shù)據(jù)節(jié)點已經(jīng)寫入這個數(shù)據(jù)包之后,就會從對應的緩存隊列刪除這個數(shù)據(jù)包。當客戶端寫滿一個數(shù)據(jù)塊之后,會調(diào)用addBlock()申請一個新的數(shù)據(jù)塊,然后循環(huán)執(zhí)行上述操作。
4、關閉輸入流并提交文件
當HDFS客戶端
完成了整個文件中所有數(shù)據(jù)塊的寫操作之后,就可以調(diào)用close()方法關閉輸出流,并調(diào)用ClientProtocol.completeO方法通知Namenode提交這個文件中的所有數(shù)據(jù)塊,也就完成了整個文件的寫入流程。

對于Datanode ,當Datanode成功地接受一個新的數(shù)據(jù)塊時,Datanode會通過
DatanodeProtocol.blockReceivedAndDeleted()方法向 Namenode 匯報,Namenode 會更新內(nèi)存中的數(shù)據(jù)塊與數(shù)據(jù)節(jié)點的對應關系。


本文參考:
《Hadoop權威指南》
《Hadoop 2.X HDFS源碼剖析 》
https://www.cnblogs.com/joqk/p/3963101.html

https://blog.csdn.net/baiye_xing/article/details/76268495
https://blog.csdn.net/androidlushangderen/article/details/52850349
http://blog.itpub.net/69908606/viewspace-2648472/
https://cloud.tencent.com/developer/article/1363388


特別推薦一個分享架構+算法的優(yōu)質內(nèi)容,還沒關注的小伙伴,可以長按關注一下:

讀Hadoop3.2源碼,深入了解java調(diào)用HDFS的常用操作和HDFS原理

長按訂閱更多精彩▼

讀Hadoop3.2源碼,深入了解java調(diào)用HDFS的常用操作和HDFS原理

如有收獲,點個在看,誠摯感謝

免責聲明:本文內(nèi)容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權益,請及時聯(lián)系本站刪除( 郵箱:macysun@21ic.com )。
換一批
延伸閱讀
關閉