go語言實現分佈式對象存儲系統之單體對象存儲

 

對象存儲

基本概念算法

主流存儲類型分爲三種:塊存儲、文件存儲以及對象存儲數據庫

  • NAS(文件存儲):Network Attached storage,提供了存儲功能和文件系統的網絡服務器,客戶端能夠訪問NAS上的文件系統,還能夠上傳和下載文件,使用協議:SMB、NFS以及AFS等網絡文件系統協議,對於客戶端來講就是網絡上的文件服務器。
  • SAN(塊存儲):Storage Area Network,和NAS的區別就是SAN只提供了塊存儲,而把文件系統抽象給客戶端來管理,使用協議:Fibre\Channel、iSCSI\ATA over Ethnet和HyperSCSI,對於客戶端來講就是一塊磁盤,能夠對其格式化,建立文件系統並掛載。
  • 對象存儲:對象指的是面向對象,集合了塊存儲和文件存儲的優勢,擁有訪問速度快、容量大等特性。而且容易搭配雲計算,是一種新的網絡存儲架構。

對象存儲系統(Object-Based Storage System)是綜合了NAS和SAN的優勢,同時具備SAN的高速直接訪問和NAS的數據共享等優點,提供了高可靠性、跨平臺性以及安全的數據共享的存儲體系結構。數組

爲了更好的說明三者的差別,我打個比方,假設有三我的想從A地到B地,如今有三種交通方式。甲選擇轎車、乙選擇公共汽車、丙選擇地鐵。塊存儲相似於轎車,速度快,可是容量小(轎車只能乘坐幾我的);文件存儲相似於公共汽車,速度慢(公共汽車有站點和紅綠燈須要考慮),可是容量較大(能多坐很多人);對象存儲相似於地鐵,速度快,容量大。安全

 

 

 

 

不一樣的數據管理方式服務器

  • NAS,數據是以一個個文件的形式管理的。
  • SAN,數據是以數據塊的形式管理的,每一個數據塊都有本身的地址,沒有額外的背景信息。
  • 對象存儲,數據是以對象的方式管理,一個對象包括:數據、元數據、全局標識符。
對象的數據一般是無結構的數據,好比:圖片、視頻或文檔等;對象的元數據則指的是對象的相關描述,好比:圖片的大小、文檔的擁有者等;對象id則是一個全局的惟一標識符,用來區分對象的。

 

不一樣的訪問數據方式網絡

  • NAS,經過NFS等網絡協議訪問某個遠程服務器上存儲的文件
  • SAN,經過數據塊的地址訪問SAN上的數據塊
  • 對象存儲,經過REST網絡服務訪問對象
對象存儲,訪問對象的方式很方便,是經過REST接口對對象進行操做,用HTTP動詞(GET、POST、PUT、DELETE等)描述操做。除此以外,還有一種訪問方式,就是使用各大雲商提供的客戶端去操做對象。
好比:Amazon的s3cmd、阿里雲的osscmd/ossutil、騰訊雲的coscmd等。

  

 

對象存儲優缺點架構

先說優勢,以前大概也提了下:分佈式

  • 可擴展性高:對象存儲可以擴展數十乃至數百EB的容量,可以充分利用高密度存儲;
  • 效率高:扁平化結構,不受複雜目錄系統對性能的影響;
  • 無需遷移:對象存儲是一種橫向擴展系統,隨着容量的增長,數據根據算法自動分佈於全部的對象存儲節點;
  • 安全性高:對象存儲一般憑藉HTTP調用對象存儲自己提供的認證密鑰來提供數據訪問;訪問方便:不光支持HTTP(S)協議,採用REST的API方式調用和檢索數據,一樣增長了NFS和SMB支持;成本相對低:與塊存儲方式相比,對象存儲是最具成本效益的數據存儲類型,而且與雲計算搭配,把對象存儲的這一特性發揮的淋漓盡致。

再提缺點:函數

  • 最終一致性:因爲不一樣節點的位置不一樣,數據同步時可能會有必定時間的延遲或者錯誤;
  • 不易作數據庫:對象存儲比較適合存儲那些變更不大甚至不變的文件,而對於像數據庫這種須要直接與存儲裸盤相互映射的應用,仍是塊存儲更合適。

 

 

單體對象存儲架構實現

單體對象存儲架構性能

 

go語言實現

package main

import (
	"io"
	"net/http"
	"os"
	"log"
	"strings"
)

func main() {
	http.HandleFunc("/objects/",Handler)
	println("server...")
	log.Fatal(http.ListenAndServe("127.0.0.1:8006", nil))
}

func Handler(w http.ResponseWriter, r  *http.Request){
	println(r)
	m := r.Method
	if m == http.MethodPut{
		Put(w,r)
		return
	}
	if m == http.MethodGet{
		Get(w,r)
		return
	}
	w.WriteHeader(http.StatusMethodNotAllowed)

}

func Put(w http.ResponseWriter,r *http.Request){
	//C:\Users\Administrator\go\src\awesomeProject\test_file
	f,e := os.Create(("C:/Users/Administrator/go/src/awesomeProject/test_file"+"/objects/"+strings.Split(r.URL.EscapedPath(),"/")[2]))

	if e != nil {
		log.Println(e)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	defer f.Close()
	io.Copy(f,r.Body)
}


func Get(w http.ResponseWriter,r *http.Request){

	f,e := os.Open(("C:/Users/Administrator/go/src/awesomeProject/test_file"+"/objects/"+strings.Split(r.URL.EscapedPath(),"/")[2]))

	if e != nil {
		log.Println(e)
		w.WriteHeader(http.StatusNotFound)
		return
	}
	defer f.Close()
	io.Copy(w,f)
}

  

詳解

main函數,註冊一個HTTP處理函數並開始監聽端口。

http.HandleFunc的做用是註冊HTTP處理函數Handler,若是由客戶端訪問本機的HTTP服務且以「/objects/」開頭,那麼請求將由Handler負責處理。

http.ListenAndServer正式監聽端口,正常狀況下會一直監聽,非正常狀況下,log.Fatal會對於錯誤並退出程序。

http.HandleFunc("/objects/",Handler)
println("server...")
log.Fatal(http.ListenAndServe("127.0.0.1:8006", nil))
 

Handler函數,HTTP中最重要的請求和響應Response,Request爲參數,根據客戶端不一樣的請求方式,執行不一樣的處理函數:Put函數與Get函數。

func Handler(w http.ResponseWriter, r  *http.Request){
	println(r)
	m := r.Method
	if m == http.MethodPut{
		Put(w,r)
		return
	}
	if m == http.MethodGet{
		Get(w,r)
		return
	}
	w.WriteHeader(http.StatusMethodNotAllowed)

}

 

Put函數,r.URL變量記錄HTTP請求的URL,EscapedPath方法用於獲取結果轉義之後的路徑部分,該路徑形式是:/objects/<object_name>,而後strings.Split函數功能是分割/objects/<object_name>,分割爲"「、」objects"、<object_name>,去數組的第三個元素就是<object_name>,os.Create在本地文件系統的根存儲目錄建立同名文件f,建立成功將r.Body用io.Copy寫入文件f。

func Put(w http.ResponseWriter,r *http.Request){
	//C:\Users\Administrator\go\src\awesomeProject\test_file
	f,e := os.Create(("C:/Users/Administrator/go/src/awesomeProject/test_file"+"/objects/"+strings.Split(r.URL.EscapedPath(),"/")[2]))

	if e != nil {
		log.Println(e)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	defer f.Close()
	io.Copy(f,r.Body)
}
Get函數同Put函數相似。此文爲分佈式對象存儲-原理、架構及Go語言實現第一章總結
相關文章
相關標籤/搜索