Files
SKYMirror 84df9996cb
CI 测试 / go vet + go test (push) Successful in 49s
26.9:版本号统一 + CI 精简 + 前端产物重建
- 全项目版本号统一:v3.x 迭代号(26.9/26.9/26.9/26.9 及裸 v2/v3)→ 26.9,
  覆盖 Go 注释 / 文档 / openapi.yaml / README×4 / 前端源码(80+ 处)
- v31_test.go 更名 custom_code_test.go;TestV2AccessorDefaults → TestKVAccessorDefaults
- docs/api/00-overview.md 更新日志合并为单条 26.9 条目(修复错位拼接)
- .goreleaser.yaml 头部注释与实际一致(Pro 2.18.1 / GITEA_TOKEN / semver tag 要求)
- CI:release-image.yml → ci.yml,仅保留 vet+test 门禁;
  镜像发布移交 GoReleaser Pro(原 build-push 的 tag 校验与 26.9 版本方案冲突,历史 9 次失败)
- 前端重建:server/web/dist 与 web-embed 同步(docs 文案嵌入更新)
2026-09-08 03:16:51 +08:00

5.2 KiB
Raw Permalink Blame History

带宽限速(26.9

26.9 新增。管理端可独立设置上行(上传)/ 下行(下载)带宽,单位字节/秒(前端 UI 友好单位为 MB/s), 0=不限速。修改后立即生效(每请求动态读取最新 KV,不需重启容器/进程)。

适用对象

方向 范围 说明
上行 POST /share/filePOST /chunk/upload/{id}/{idx}POST /chunk/upload(扁平兼容)、PUT /presign/upload/proxy/{id} 包裹 c.Request.Body,对 multipart 解析与表单字段读取天然节流
下行 GET /share/download?key=&code=GET /share/select?code=(文件流)、GET /admin/file/download?id= 包裹 storage.ReadCloserlocal/webdav/s3 代理下载),Range 分段也按节流后的字节流推进

不在限速范围S3 预签名直传(客户端 → S3 桶直连,服务端无法介入); 文本分享下载(GET /share/select 命中 text 字段时直接返回 JSON 字符串,体积通常远小于 1MB)。

配置项

类型/边界 默认 说明
upload_rate int640 ~ 1 073 741 824,即 1 GiB/s 0 上行字节/秒;0=不限速
download_rate int640 ~ 1 073 741 824 0 下行字节/秒;0=不限速

UI 输入:管理端「系统设置 → 上传频率限制」卡底部两个字段,MB/s 整数,0=不限速。 保存时前端把 MB/s × 1024 × 1024 换算为字节/秒写入 KV。

算法(实现原理)

基于时间窗的精确调度,每个 Read 调用:

start  ← 首次 Read 的时刻
bytes  ← 累计已读字节(每次 Read 累加返回值 n
expected = start + bytes / rate     // 按限速值推算"应到达时间"
if now < expected:
    sleep(expected - now)           // 超前则阻塞补齐
return n, err

保证长期速率严格 ≤ rate,瞬时由调用方 Read 块大小自然突发。不按字节微睡眠——避免单次 Read 在低速场景下被调度抖动放大。

早期版本按每字节 sleep 1/rate 秒,被 Mac 调度粒度(约 10µs)放大后实际速率只有目标值的 1/3;26.9 修正为整块对齐 sleep。

公开接口

GET /api/v1/configGET /admin/config/get 均下发当前生效值(数值型,字节/秒):

{
  "data": {
    "config": {
      "upload_rate": 0,
      "download_rate": 0,
      ...
    }
  }
}

修改(管理端)

# PATCH /admin/config/update
curl -X PATCH http://localhost:8466/admin/config/update \
  -H "Authorization: Bearer <admin-jwt>" \
  -H "Content-Type: application/json" \
  -d '{"upload_rate": 1048576, "download_rate": 524288}'
# ↑ 上行 1 MB/s、下行 512 KB/s

边界校验(来自 settings.KVSchema,越界 400 中文错误):

  • upload_rate / download_rate 必须是整数,0 ≤ 值 ≤ 1073741824

验证(端到端)

# 1) 设下载限速 200 KB/s
curl -X PATCH http://localhost:8466/admin/config/update \
  -H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
  -d '{"download_rate": 204800}' -w '\nHTTP %{http_code}\n'
# 2) 上传 2 MB 测试文件(自动随机取件码或自定义 5~8 位)
curl -X POST http://localhost:8466/share/file -F file=@/tmp/2mb.bin \
  -F "expire_value=1" -F "expire_style=day" -F "code="
# 3) 管理员接口下载(不消耗取件次数,便于压测)
ID=$(curl -s "http://localhost:8466/admin/file/list?page=1&size=20" \
  -H "Authorization: Bearer <token>" | jq '.data.data[0].id')
time curl -s -o /tmp/dl.bin "http://localhost:8466/admin/file/download?id=$ID" \
  -H "Authorization: Bearer <token>"
# 期望 ~10s2 097 152 字节 / 200 000 B/s = 10.486 s
# 实测 10.65s(误差 1.5%,含 HTTP 头/响应开销)

测完记得恢复:PATCH /admin/config/update 设回 0。

性能开销

  • 0 速率路径:完全透传,无任何额外分配/锁/计时。
  • 限速路径:每次 Read 多两次 time.Now() 与一次整数除法;mutex.Lock 仅在并发复用同一 reader 时阻塞(每请求独立实例,正常无争用)。

边界与注意

  1. S3 预签名直传不可限速:客户端拿到预签名 URL 后直连 S3 桶,不经本服务。PUT /presign/upload/proxy/{id}代理模式)仍受上行限速;前端实现可在管理端提示用户这一点。
  2. 共享存储后端的"突发":令牌桶改为时间窗对齐后,单次 Read 仍可能瞬时突发到调用方请求的块大小(典型 32~64 KB)。需更严格平滑的可在调用方调小读取块大小(如 4 KB)。
  3. 代理/反代层限速:如部署在 Nginx / Cloudflare 后,公网入站还会经过代理的限速/带宽上限;本服务限速只对服务进程侧可见。
  4. Range 多区间:HTTP Range 单区间请求的字节流仍按限速推进;多区间未实现,回退全量。
  5. 重置:UI 「恢复默认」按钮把两个速率归 0(不限速)。

相关

  • 配置 KV 概览:见《环境变量与配置》upload_rate / download_rate 条目
  • 管理端修改示例:见《管理后台 API》PATCH /admin/config/update
  • OpenAPI schemadocs/openapi.yaml/admin/config/update requestBody.properties