复现一个分布式对象存储 01 | 青训营笔记

198 阅读3分钟

复现一个分布式对象存储 01 | 青训营笔记

这是我参与「第四届青训营 」笔记创作活动的第1天

介绍

本系列是我对书籍《分布式对象存储——原理、架构及Go语言实现》的复现和思考以及踩坑经验,动机是在第四届青训营大数据专场选择的作业三《简易分布式存储系统实现》,打算提前看一些存储相关的书,正好这本书与作业三比较相关,所以看一下先练练手

环境准备

系统:ubuntu20.04,Go版本:go1.18,代码编辑器:Goland

目标

实现一个简单的单机版对象存储,通过REST接口上传和下载一个对象。

架构和接口

单机版对象存储架构如下图所示

REST接口实现两个put、get方法,put将对象的名字和数据上传,get从服务器下载一个对象。

实现

文件结构

├── 第一章笔记.md
├── objects
│   ├── get.go
│   ├── handler.go
│   └── put.go
└── server.go

首先看一下server.go文件

package main

import (
   "book-object-storage/01/objects"
   "log"
   "net/http"
   "os"
)

func main() {
   http.HandleFunc("/objects/", objects.Handler)
    // LISTEN_ADDRESS是我们自己设置的ip地址,这里为本地ip地址127.0.0.1
   log.Fatal(http.ListenAndServe(os.Getenv("LISTEN_ADDRESS"), nil))
}

main函数大概意思就是我们启动一个http服务,处理函数为我们自己定义的objects.Handler

接着看一下objects包里的三个文件

handler.go

package objects

import "net/http"

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

这个文件也很简单,就是根据请求的Method来判断是采用put还是get方法

put.go

package objects

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

func put(w http.ResponseWriter, r *http.Request) {
	f, err := os.Create(os.Getenv("STORAGE_ROOT") + "/objects/" + strings.Split(r.URL.EscapedPath(), "/")[2])
	if err != nil {
		log.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	defer f.Close()
	io.Copy(f, r.Body)
}


strings.Split(r.URL.EscapedPath(), "/")[2] 从请求中拿到我们要上传的文件的名字,通过os.Creat创建一个文件f,将请求的r.Body拷贝至f

get.go


package objects

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

func get(w http.ResponseWriter, r *http.Request) {
	f, err := os.Open(os.Getenv("STORAGE_ROOT") + "/objects/" + strings.Split(r.URL.EscapedPath(), "/")[2])
	if err != nil {
		log.Println(err)
		w.WriteHeader(http.StatusNotFound)
		return
	}
	defer f.Close()
	io.Copy(w, f)
}

STORAGE_ROOT是我们测试时候自己设置的,strings.Split(r.URL.EscapedPath(), "/")[2] 是从请求中拿到我们要下载的文件的名字,然后和前面的文件前缀拼接成一个在磁盘可以找到的文件地址。然后通过io.Copy方法将读到的文件f复制到返回的w中

测试

提前创建好目录
mkdir /tmp/objects/

在项目文件server.go的目录下
在命令行输入下面指令 设置LISTEN_ADDRESS和 STORAGE_ROOT 以及运行server.go
LISTEN_ADDRESS=127.0.0.1:12345 STORAGE_ROOT=/tmp go run server.go


使用curl命令作为客户端来访问服务器 试图 Get一个test的对象
由于是本地测试 将ip地址改成本地
curl -v 127.0.0.1:12345/objects/test

PUT一个test对象
curl -v 127.0.0.1:12345/objects/test -XPUT -d"this is a test objects"

创建好tmp下的objects目录后,

image.png

再启动一个终端

image.png

此时由于我们还没上传文件,所以get不到文件,出现404 NOT Found,我们接下来通过curl上传一个test文件,内容为this is a test objects

image.png

上传成功后 我们继续get这个test,发现成功

image.png

我的代码地址如下

参考

新手写东西,感谢观看