go实现的分布式文件上传服务含gateway、storage node、registry三层,通过http通信解耦存储与入口,支持横向扩展与轻量容错,适用于中小规模场景。

用Go语言实现一个简单的分布式文件上传服务,核心在于解耦存储、统一入口、支持横向扩展,并保证基本的可靠性。不需要复杂的一致性协议或强一致性存储,适合中小规模场景(比如内部工具、日志归集、素材中转等)。
服务分层与角色划分
整个系统分为三个轻量角色,全部用Go编写,通过HTTP通信:
-
Gateway(网关层):接收客户端上传请求(如
POST /upload),校验文件元信息(大小、类型、签名),生成唯一上传ID(如UUID或时间戳+随机数),返回临时上传地址(含token)给客户端 -
Storage Node(存储节点):实际保存文件的Worker,每个节点监听独立端口,提供
PUT /file/{id}接口;支持本地磁盘或对接MinIO/S3兼容存储;启动时向注册中心上报自身地址和容量 - Registry(注册中心):轻量服务发现组件(可用etcd、Consul,或简单HTTP心跳+内存map实现),记录活跃节点列表及负载指标(如当前文件数、磁盘使用率)
文件路由与负载均衡策略
Gateway不固定绑定某台Storage Node,而是按需选择目标节点:
- 从Registry拉取健康节点列表,过滤掉磁盘使用率 > 85% 或心跳超时的节点
- 采用加权轮询或最小负载优先(选当前文件数最少的节点)——实现简单且足够实用
- 为每个上传ID生成带签名的临时URL(如
https://node1.example.com/file/abc123?token=xxx),token有效期5–10分钟,防止恶意刷写
上传流程与容错设计
客户端分两步完成上传,避免网关成为瓶颈或单点故障:
- 第一步:调
POST /v1/upload到Gateway,传filename、size、可选md5;Gateway返回{“id”: “abc123”, “upload_url”: “https://...”} - 第二步:客户端直传到指定Storage Node的
upload_url,Node收到后校验token、size、MD5(若提供),保存文件至本地路径/data/files/abc123.bin,并写入简易元数据JSON(含原始名、大小、时间) - 失败重试:若某节点不可达,Gateway可在第二次请求时换节点;Storage Node异常时,Gateway可返回
503 + Retry-After,引导客户端稍后重试同一ID
关键代码片段示意(Go)
Gateway生成带签URL示例:
func genUploadURL(nodeAddr, uploadID string) string {
expires := time.Now().Add(10 * time.Minute).Unix()
sig := hmacSum(fmt.Sprintf("%s:%d", uploadID, expires), secretKey)
return fmt.Sprintf("https://%s/file/%s?expires=%d&sig=%s",
nodeAddr, uploadID, expires, sig)
}Storage Node验证token逻辑(中间件):
func verifyUploadToken(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
expires, _ := strconv.ParseInt(r.URL.Query().Get("expires"), 10, 64)
sig := r.URL.Query().Get("sig")
expected := hmacSum(fmt.Sprintf("%s:%d", id, expires), secretKey)
if time.Now().Unix() > expires || sig != expected {
http.Error(w, "Invalid or expired token", http.StatusForbidden)
return
}
next.ServeHTTP(w, r)
})
}golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











