前言
開源的分布式存盤系統比較多,比較有名的有:Ceph、GlusterFS、HDFS、TFS等,這些系統都比較復雜,代碼動則幾十上百萬行,這些系統對初學者來說門檻比較高,特別是對于從事非分布式存盤行業,但又想跨行學習分布式的同學來說,往往有這想法,但是不知道怎么入手,本文介紹之前實作的一個C++極簡版的分布式檔案系統 https://github.com/goyas/goya-fs, 代碼只有一兩百行,當然功能也很粗糙,只實作了簡單的mkdir和ls這兩條命令,但就像剛剛描述的,目的是學習,也便于大家對分布式有體感之后,方便閱讀其他龐大的分布式存盤系統,當然以后有空時間也會不斷完善功能,
對于嵌入式,或者主要是從事單機開發的程式員來說,沒接觸分布式之前,都會感覺很神秘,往往會被高并發、海量資料分析處理等名詞唬住,其實,職位沒有智商之分,區別也就在于你有沒有親自動手摸過這些玩意兒,以往的經驗告訴我,就算不會的東西,一個版本的時間,只要你稍微努點力基本就會達到行業的基本水平,當然越往上走就要看自己的興趣和時間投入了,
好了,言歸正傳,下面開始介紹這個簡單的分布式檔案系統,選用的基礎組件是leveldb + goyas-rpc,leveldb作為存盤底座,goyas-rpc作為行程之間通信使用,有關leveldb的介紹網上非常多,這里就不再驁述,goyas-rpc可以參考之前的 一個基于protobuf的極簡RPC 這篇文章,
思考
如果讓你設計分布式檔案系統,你會怎么設計?
1、如果自己設計一個簡單的分布式存盤系統,對于檔案的讀取存盤,你會怎么設計?
2、比如執行下面的命令經過怎么樣的IO路徑local_file檔案才會存盤到磁盤? ./fs_client put local_file /user/ —把local_file檔案存放到檔案系統/user目錄
3、怎么讓local_file檔案存盤到分布式檔案系統的3個不同結點,并且3副本保存?
架構設計
系統架構設計采用經典的GFS分布式存盤模型,由3個不同的角色(client、master、chunkserver)負責管理不同的事務,client作為客戶端,接受來自用戶的請求,master作為元資料及namespace存盤管理,chunkserver和磁盤打交道,作為最終的單機存盤引擎, 執行./fs_client put local_file /user/ 命令,會大致經歷下面圖里面從左到右的流程,最終呼叫系統呼叫write把local_file存放到存盤介質,

fs_client
fs_client用于接受用戶的請求,比如:./fs_client mkdir /file1執行這條命令,會最初呼叫下面的函式介面
int FileSystemImpl::CreateDirectory(char* path) { printf("Create directory %s\n", path); CreateFileRequest request; CreateFileResponse response; request.set_sequence_id(0); request.set_file_name(path); request.set_type((1<<9)|0755); bool ret = rpc_wrapper_->SendRequest(masterserver_stub_, &MasterServer_Stub::CreateFile, &request, &response, 5, 3); if (!ret || response.status() != 0) { printf("Create directory fail\n"); return -1; } return 0;}
函式功能:把序列號、檔案名及檔案型別通過RPC發送到元資料管理行程masterserver進行處理,其實這里比我們經常單機環境寫的fopen、fwrite也就僅僅多了個RPC,需要通過它把不用節點的資訊發送到其他節點,呵呵,這就是分布式!再來看看masterserver行程收到這個request訊息后干了些啥?
masterserver
void MasterServerImpl::CreateFile(google::protobuf::RpcController* controller, const ::goya::fs::CreateFileRequest* request, goya::fs::CreateFileResponse* response, google::protobuf::Closure* done) { printf("masterserver create file\n"); response->set_sequence_id(request->sequence_id()); const std::string& filename = request->file_name(); if (filename.empty() || filename[0] != '/') { printf("path format error\n"); response->set_status(3); done->Run(); return ; } std::string file_value; leveldb::Status s; s = db_->Get(leveldb::ReadOptions(), filename, &file_value); if (s.IsNotFound()) { FileInfoProto file_info; file_info.set_time(time(NULL)); file_info.set_type(request->type()); file_info.SerializeToString(&file_value); s = db_->Put(leveldb::WriteOptions(), filename, file_value); if (s.ok()) { printf("CreateFile %s file\n", filename.c_str()); response->set_status(0); } else { printf("CreateFile %s file\n", filename.c_str()); response->set_status(2); } } else { printf("CreateFile %s fail: already exist\n", filename.c_str()); response->set_status(1); } done->Run();}
函式功能:從收到的訊息中提取出檔案名作為key,檔案型別和時間作為value,然后使用KV存盤引擎leveldb存盤,最后把完成訊息通過response發送給呼叫方,這個程序到這里就完了,是不是很簡單?!

ls命令的功能和上面的介紹相反,就是把上面mkdir創建的檔案資訊給列出來,這里就不講究了,大家可以去看看原始碼,也是非常簡單,
chunkserver
待實作 …
寫在最后
到這里整個分布式檔案系統就講解完了,當然真正的分布式存盤系統遠比這個復雜的太多,不然怎么會到百萬級別的代碼,希望這個簡單的檔案系統的講解對你有點幫忙,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/46439.html
標籤:架構設計
上一篇:初探微服務架構
