zoukankan      html  css  js  c++  java
  • go语言实现分布式对象存储系统之单体对象存储

    对象存储

    基本概念

    主流存储类型分为三种:块存储、文件存储以及对象存储

    • NAS(文件存储):Network Attached storage,提供了存储功能和文件系统的网络服务器,客户端可以访问NAS上的文件系统,还可以上传和下载文件,使用协议:SMB、NFS以及AFS等网络文件系统协议,对于客户端来说就是网络上的文件服务器。
    • SAN(块存储):Storage Area Network,和NAS的区别就是SAN只提供了块存储,而把文件系统抽象给客户端来管理,使用协议:FibreChannel、iSCSIATA 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:UsersAdministratorgosrcawesomeProject	est_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:UsersAdministratorgosrcawesomeProject	est_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语言实现第一章总结


  • 相关阅读:
    [原创]什么是兼容性测试?
    [原创]Web开发测试辅助工具介绍
    [原创]如何顺利通过中国电信Brew平台软件测试?
    [原创]网站性能优化利器之二"Yahoo Yslow"
    [原创]HP SiteScope工具介绍及下载地址
    [原创]网站前端页面级性能测试方法
    [原创]网银在线chinabank安全漏洞之“不完善的开发软件包”
    [原创] linux必学的常用命令
    [原创]如何做好目标管理?
    Visual Studio 小技巧:自定义代码片断
  • 原文地址:https://www.cnblogs.com/-wenli/p/11434347.html
Copyright © 2011-2022 走看看