该协议基于文件指纹实现轻量分布式单向同步,核心环节包括文件发现、差异计算、增量传输和一致性保障;采用客户端上报manifest、服务端比对下发指令模式,用SHA-256+大小+修改时间生成指纹,支持并发上传与删除,并通过超时、校验、压缩和文件锁增强可靠性。

用 Go 实现一个简单的分布式文件同步协议,核心不在于造轮子替代 rsync 或 Syncthing,而在于理解同步的关键环节:文件发现、差异计算、增量传输和一致性保障。下面是一个轻量、可运行、带注释的实现思路,聚焦单向同步(A → B),支持本地目录到远程目录的实时/定时同步。
1. 协议设计:基于文件指纹的轻量同步
不依赖中心元数据服务,采用“客户端主动上报 + 服务端比对”模式:
- 每个文件用 SHA-256 + 文件大小 + 修改时间(秒级) 生成唯一指纹(避免仅用 mtime 导致冲突)
- 客户端定期扫描本地目录,生成
file_manifest.json:含路径、指纹、是否删除标记 - 服务端接收 manifest 后,与本地已知状态比对,返回需上传/删除/跳过的文件列表
- 客户端按指令执行:上传新文件(分块 POST)、发送删除请求(DELETE /file?path=xxx)
2. Go 服务端:接收比对并下发指令
使用标准 net/http,无外部依赖:
func handleSync(w http.ResponseWriter, r *http.Request) {
var manifest []FileEntry
json.NewDecoder(r.Body).Decode(&manifest)
<pre class="brush:php;toolbar:false;">// 加载或初始化本地状态(生产中建议用 BoltDB 或 SQLite)
localState := loadLocalState()
var actions SyncActions
for _, entry := range manifest {
local, exists := localState[entry.Path]
switch {
case !exists || entry.Fingerprint != local.Fingerprint:
actions.Upload = append(actions.Upload, entry.Path)
case entry.Deleted && exists:
actions.Delete = append(actions.Delete, entry.Path)
}
// 其他情况:跳过(一致)
}
// 更新本地状态(实际应事务化)
for _, e := range manifest {
localState[e.Path] = e
}
saveLocalState(localState)
json.NewEncoder(w).Encode(actions)}
3. Go 客户端:扫描、计算、执行
关键逻辑封装为可复用函数:
- ScanDir:递归遍历,跳过 .git、临时文件等
- ComputeFingerprint:打开文件,读取前 1MB + 后 1MB(大文件不全读),哈希拼接 size+mtime
-
SyncOnce:POST manifest → 解析响应 → 并发上传(用
sync.WaitGroup控制并发数)→ 发送删除请求
示例上传片段:
func uploadFile(path string, serverURL string) error {
file, _ := os.Open(path)
defer file.Close()
_, err := http.Post(serverURL+"/upload", "application/octet-stream", file)
return err
}
4. 基础可靠性增强点
不追求强一致,但规避常见坑:
- 所有 HTTP 请求加超时(
http.Client{Timeout: 30 * time.Second}) - 上传前校验服务端返回的
Upload列表是否包含该文件(防中间人篡改) - manifest 传输用 JSON+gzip(服务端
gzip.Handler,客户端设置Accept-Encoding: gzip) - 本地状态文件加写锁(
flock),避免多实例冲突
这个协议不是生产级方案,但跑通了分布式同步最核心的数据流闭环。真正落地时,可按需接入 etcd 做租约协调、用 gRPC 替代 HTTP 提升效率、增加断点续传和校验回执。重点是先让“谁该传什么”这件事清晰可控。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











