hadoop檔案系統架構分析
(軟體體系結構的大作業,閱讀分析hadoop檔案系統)
寫在前面/後面
FileSystem = abstractFileSystem -》 面向檔案系統實現者
FileContext -》面向應用程式編寫者
FS中具體的檔案系統作為最基層的類,用於實現對對應的檔案系統的讀取,同一繼承自FileSystem/AbstarctFileSystem,HDFS是單獨的一套系統,對等於VFS,用於操作不同的檔案系統。HDFS雖然繼承於AbstractFileSystem,主體又DFSClient類實現,(借屍還魂),只是為了做一個檔案系統的樣子,內在的實現在另外一個HDFS的資料夾裡(有單獨的DFSInputStream),獨立於fs資料夾
FileSystem的結構:
extends Config(提供訪問配置檔案的功能)
檔案建立,讀取,重新命名,拷貝,刪除等操作
GlobFilter
description:A class that could decide if a string matches the glob or not
Cache:
Caching FileSystem objects,內含有hashMap
Statistics:
statisticsTable是一個IdentityHashMap
BlockLocation:
包含一個檔案塊的詳細資訊(全部副本,主機埠,網路拓撲結構,塊檔案長度,偏移,塊長度等)
java
string[] {副本主機};
string[] {副本主機埠};
string[] {主機網路中的拓撲路徑};
FileStatus:
extends PathFilter,用來過濾檔案,或的想要的檔案。
獲取檔案狀態,path.length,isdir,block_replocation等
Trash:
垃圾桶的功能
fs有用文章:
其他類:
DFSClinet:
DFSClient can connect to a Hadoop FileSystem and perform basic file tasks.It uses the ClientProtocol to commuicate with a NameNode daemon,and connects directly to DataNodes to read/write block data.HDFS users should obtain an instance of DistributedFileSystem,whith uses DFSClient to handle fileSystem tasks.
要求
閱讀教師提供的前期分析報告[3],並仔細閱讀與修正。
–
下載 JDK、Apache 的構建工具 Maven[4]、Eclipse[2],構建閱讀程式碼的環 境。
–
在詳細閱讀原始碼的基礎上,理解設計思想,並給出軟體架構圖。
FS中具體的檔案系統作為最基層的類,用於實現對對應的檔案系統的讀取,同一繼承自FileSystem/AbstarctFileSystem,HDFS是單獨的一套系統,對等於VFS,用於操作不同的檔案系統。HDFS雖然繼承於AbstractFileSystem,主體又DFSClient類實現,(借屍還魂),只是為了做一個檔案系統的樣子,內在的實現在另外一個HDFS的資料夾裡(有單獨的DFSInputStream),獨立於fs資料夾
在軟體架構圖的基礎上,給出原始碼的詳細類圖和核心過程的順序圖, 說明原始碼的設計如何與設計思想呼應。
FS的架構
可以看出類圖的繼承結構,FileSystem = abstractFileSystem + FileContext ,所以繼承自abstractFileSystem 的類基本與fileSystem的類的實現方式功能一樣,所以不再重複說明。
我們可以把FS的有關類分為2部分,一個是工具類,一個是實現類。
工具類:
FilterFileSystem
FilterFileSystem繼承FileSystem,聲明瞭一個FileSystem的物件,自己做一些處理,交給FS處理
CheckSumFileSystem
ChecksumFileSystem類繼承FilterFileSystem類,提供校驗CRC
LocalFilesystem
繼承自ChecksumFileSystem,重寫父類的檔案複製的類,新增內部物件rfs,不過沒咋用,判斷為基本同父類一樣
實現類:
NativeS3FileSystem
實現具體功能的檔案系統子類與其父類FileSystem的差異顯而易見,除去父類中的抽象函式如append,Create,delete,getUri,getFileStatus,getWorkingDirectory等需要根據子類的情況實現重寫的函式之外,一些函式子類利用了其系統中獨有的類或者介面進行了自己的實現。
FTPFileSystem
子類FTPFileSystem與父類FileSystem的函式實現差異很大,主要原因在於FTPFileSystem引入了Client物件並利用其完成了很多與父類不同的函式實現機制
KosmosFileSystem
子類KosmosFileSystem與父類FileSystem的函式實現差異較大,主要原因在於KosmosFileSystem利用了KfsImpl介面
S3FileSystem
子類S3FileSystem與父類FileSystem的函式實現差異較大,子類利用INode節點的特性對函式的實現方式進行重寫
RawLocalFileSytem
自己重寫filesystem的大多數方法,去操作檔案,所依賴的流都是自己過載過的內部類流
HDFS
檔案系統實現主體依靠DFSClient來實現,只是為了包裝一層filesystem
Stream流的架構
流的結構類似與Fs的結構,FSInputStream/FSOutputStream是每一個具體(實際)檔案系統的父類,每一個檔案系統都有對應的流作為內部流,
然後內部流最終需要作為引數被包裝為FSDataInputStream/FSDataOutputStream在HDFS上傳遞。
(java流的一大特色,巢狀包裝)
比如:new FSDataInputSteam(new S3InputStream(…))
同時,流的結構也印證了上述的架構,fs只是為HDFS做同一的檔案系統介面,消除每一個檔案系統的差異
介面的繼承
這裡值得注意的就是writealbe是序列化的介面,繼承該結構的類可以將物件轉化為流的形式。
操作/異常處理/config+shell![異常錯誤]
無可奉告!
在明確詳細設計的基礎上,以原始碼中的相關程式碼為例證明自己的判斷。
新建檔案系統的流程 -》
- 得到configuration的物件,
- 用filesystem.get(configuration)得到對應的檔案系統
- 對檔案進行操作
- 如果對檔案的讀寫,單獨用DataInput/OutputStream操作
檔案系統的建立流程:
Filesystem.get()
public static FileSystem get(URI uri, Configuration conf) throws IOException {
String scheme = uri.getScheme();
String authority = uri.getAuthority();
if (scheme == null) { // no scheme:不知道是什麼檔案系統
return get(conf);
}
if (authority == null) { // no authority
URI defaultUri = getDefaultUri(conf); //如果沒有許可權,從預設配置裡獲取URI
if (scheme.equals(defaultUri.getScheme()) // if scheme matches default
&& defaultUri.getAuthority() != null) { // & 有解碼許可權(不爽很懂)
return get(defaultUri, conf); // 返回預設的引數
}
}
String disableCacheName = String.format("fs.%s.impl.disable.cache", scheme);
//是否可以從cache裡獲取
if (conf.getBoolean(disableCacheName, false)) {
return createFileSystem(uri, conf);
}
return CACHE.get(uri, conf);
}
//FileSystem.createFileSystem()
private static FileSystem createFileSystem(URI uri, Configuration conf
) throws IOException {
Class<?> clazz = conf.getClass("fs." + uri.getScheme() + ".impl", null); //really create filesystem,獲取對應檔案系統的名稱
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;
}
//Cache.get()
獲取key()-》scheme,authority,username標識
private FileSystem getInternal(URI uri, Configuration conf, Key key) throws IOException{
FileSystem fs;
synchronized (this) {
fs = map.get(key);
}
if (fs != null) {
return fs;
}
fs = createFileSystem(uri, conf);
//以下涉及同步問題
synchronized (this) { // refetch the lock again
FileSystem oldfs = map.get(key);
if (oldfs != null) { // 一樣的系統被建立當這個fs在建立的時候,比你早一步
fs.close(); // close the new file system
return oldfs; // return the old file system
}
// now insert the new file system into the map
if (map.isEmpty() && !clientFinalizer.isAlive()) {
Runtime.getRuntime().addShutdownHook(clientFinalizer);
}
fs.key = key;
map.put(key, fs); //加入map中
if (conf.getBoolean("fs.automatic.close", true)) {
toAutoClose.add(key); //自動關閉的連結串列,如果需要自動關閉
}
return fs;
}
}
這裡的檔案系統只是本地的檔案系統,HDFS的專門處理分散式的檔案系統,繼承於abstractFileSystem的目的是為了介面通訊。在完整的原始碼中,有hadoop-common-project /hadoop-hdfs-project,在這個版本里hdfs放在hdfs-project裡,而不是common裡,推測老師給的版本應該是過渡版本
通過閱讀原始碼,深刻體會 Hadoop 雲端計算平臺與檔案系統之間的關係, 修正提供的分析報告,給出完整的分析過程與修訂後的報告
雲端計算的主體的儲存部分又HDFS實現,而我們研究的fs為HDFS提供一個同一的介面,用來遮蔽每一種檔案系統內部具體的特性或者細節。使得HDFS可以將他們同一視為一種檔案系統而不用在意其他細節。
在檔案系統的提供的服務上,為了實現雲端儲存,適合分散式儲存,又有nameNode和dataNode的結構。
dataNode作為儲存節點,具體負責儲存檔案資料,是檔案系統的工作節點,根據需要儲存並檢索資料塊(受客戶端或namenode排程),並且定期向namenode傳送它們所儲存的塊的列表。
nameNode負責儲存檔案的元資料, 管理檔案系統的名稱空間,主要作用是維護著檔案系統樹及整棵樹內所有的檔案和目錄、資料節點資訊,並將名稱空間映象檔案、編輯日誌檔案永久儲存在本地磁碟。雖然都是依賴與檔案系統,但是有一個主從的邏輯關係在裡面。
dataNode多備份為資料儲存可靠性提供保障。
多備份同時對系統的吞吐量有一定提升,客戶端從namenode獲取需要的BlockLocation(參見上文),然後由HDFS去尋找對應的資料主機,返回
一個HDFS 叢集可能包含上千DataNode 節點,這些DataNode 定時和 NameNode通訊,接受NameNode的指令。為了減輕NameNode的負擔,NameNode不永久儲存資料塊的位置資訊,系統啟動時通過DataNode的上報,來重建NameNode上的對映表
通過Client的檔案讀寫分析:
HDFS資料儲存: