Go语言实现的下载服务速度限制方案

发表时间: 2024-05-21 11:51

如何解决在golang中如何限制服务器上载和下载的速度?

github地址:

github.com/juju/ratelimit

ratelimit 包提供了一个高效的令牌桶实现

package mainimport ("bytes""fmt""io""time""github.com/juju/ratelimit")func main() {    // 源容量1MB    src := bytes.NewReader(make([]byte, 1024*1024))    // 目的地    dst := &bytes.Buffer{}    // Bucket每秒增加100KB,最多可容纳100KB    bucket := ratelimit.NewBucketWithRate(100*1024, 100*1024)    start := time.Now()    // 将源复制到目的地,但用价格有限的一个包装我们的读者    io.Copy(dst, ratelimit.Reader(src, bucket))    fmt.Printf("copied %d bytes in %s\n", dst.Len(), time.Since(start))}


运行它之后, 输出为:

copied 1048576 bytes in 9.239607694s

您可以使用不同的存储桶实现来提供所需的行为。在您的代码中, 设置正确的令牌桶后, 您将调用:

_, err = io.copy(out, ratelimit.Reader(file, bucket))

实例1: 文件下载服务的速率限制

package mainimport ("fmt""io""net/http""os""github.com/juju/ratelimit")// 本案例演示文件服务下载的限流// io.Copy// downloadHandler : 文件下载接口func downloadHandler(w http.ResponseWriter, r *http.Request) {    r.ParseForm()    filename := r.Form.Get("filename") //获取文件的名称    localPath := "C:/tmp/" + filename    // 打开文件    f, err := os.Open(localPath)    if err != nil {    w.WriteHeader(http.StatusInternalServerError) // 500    return    }    defer f.Close()    //下载响应头设置    w.Header().Set("Content-Type", "application/octect-stream")    w.Header().Set("content-disposition", "attachment; filename=\""+filename+"\"")    // 下载速度 100KB/s    // NewBucketWithRate 返回一个令牌桶, 该桶以每秒速率令牌的速率填充桶, 直至达到给定的最大容量。由于时钟分辨率有限, 在高速率下, 实际速率可能与指定速率相差高达 1%。    // 创建一个令牌桶, 设置每秒速率(rate)、初始容量(capacity)。    bucket := ratelimit.NewBucketWithRate(100*1024, 100*1024) // 单位: 字节 1KB 等于 1024 byte(字节)    io.Copy(w, ratelimit.Reader(f, bucket))}/*http://localhost:8080/download?filename=zuoweibiao.png*/func main() {    // 静态资源处理    http.Handle("/static/",    http.StripPrefix("/static/",    http.FileServer(http.Dir("./static"))))    // 动态接口路由设置    http.HandleFunc("/download", downloadHandler)    // 监听端口    fmt.Println("文件服务正在启动, 监听端口:8080...")    err := http.ListenAndServe(":8080", nil)    if err != nil {        fmt.Printf("Failed to start server, err:%s", err.Error())    }}

相关的方法解释:

// 指定时间间隔、容量大小的令牌桶、每个tick添加的令牌数 1、 clock的类型是Clockfunc NewBucket(fillInterval time.Duration, capacity int64) *Bucket// 指定时间间隔、容量大小、每个tick添加的令牌数 quantumfunc NewBucketWithQuantum(fillInterval time.Duration, capacity, quantum int64) *Bucket// 创建填充速度为指定速率和容量大小的令牌桶// NewBucketWithRate(0.5, 100) 表示每秒填充50个令牌, fillInterval 时间间隔为1func NewBucketWithRate(rate float64, capacity int64) *Bucket

limiter包

github地址:

github.com/dxvgef/limiter

实例2: 文件下载服务的速率限制

package mainimport (    "log"    "net/http"    "github.com/dxvgef/limiter")func main() {    http.HandleFunc("/", func (resp http.ResponseWriter, req *http.Request) {    // 传输demo.mp4文件, 限速每秒100KB    if err := limiter.ServeFile(resp, req, "./demo.mp4", 100*1024); err != nil {        resp.WriteHeader(500)        resp.Write([]byte(err.Error()))    }    })    if err := http.ListenAndServe(":8080", nil); err != nil {        log.Println(err.Error())        return    }}