ratelimit

package module
v0.0.0-...-5166aca Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 5, 2021 License: Apache-2.0 Imports: 6 Imported by: 0

README

滑动窗口限流


算法思想 将一个大的时间窗口分成多个小窗口,每次大窗口向后滑动一个小窗口,并保证大的窗口内流量不会超出最大值,这种实现比固定窗口的流量曲线更加平滑。

slidewindow


使用

go get github.com/sunanzhi/ratelimit-go

示例

import(
    "fmt"
    "net/http"
    ratelimit "github.com/sunanzhi/ratelimit-go"
)

func main() {
    var (
        limitTime = 10
        bucketCount = 5
        limitCount = 200
    )
    slideWindow, _ := ratelimit.Init(limitTime, bucketCount, limitCount)

    http.HandleFunc("/ratelimit", func(w http.ResponseWriter, r *http.Request) {
        err := slideWindow.Limiting()
        if err != nil {
            w.WriteHeader(http.StatusBadGateway)
            fmt.Println(err.Error())
        } else {
            w.Write([]byte("httpserver"))
        }
    })
    fmt.Println("Starting server ...")
    http.ListenAndServe(":9090", nil)
}

hey.exe 轻量压缩测试结果

用golang的boom来做压测,要提前安装boom工具

go get github.com/rakyll/hey

go install github.com/rakyll/hey

执行以下命令

C:\Users\0\go\bin> .\hey.exe -c 6 -n 300 -q 6 -t 80 http://localhost:9090/ratelimit

控制台输出
  Summary:
  Total:        8.3399 secs
  Slowest:      0.0608 secs
  Fastest:      0.0001 secs
  Average:      0.0030 secs
  Requests/sec: 35.9718
  
  Total data:   2600 bytes
  Size/request: 8 bytes

  Response time histogram:
  0.000 [1]     |
  0.006 [269]   |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  0.012 [14]    |■■
  0.018 [4]     |■
  0.024 [3]     |
  0.030 [4]     |■
  0.037 [1]     |
  0.043 [0]     |
  0.049 [2]     |
  0.055 [0]     |
  0.061 [2]     |


  Latency distribution:
  10% in 0.0002 secs
  25% in 0.0002 secs
  50% in 0.0002 secs
  75% in 0.0025 secs
  90% in 0.0062 secs
  95% in 0.0132 secs
  99% in 0.0461 secs

  Details (average, fastest, slowest):
  DNS+dialup:   0.0001 secs, 0.0001 secs, 0.0608 secs
  DNS-lookup:   0.0001 secs, 0.0000 secs, 0.0044 secs
  req write:    0.0000 secs, 0.0000 secs, 0.0001 secs
  resp wait:    0.0028 secs, 0.0001 secs, 0.0607 secs
  resp read:    0.0000 secs, 0.0000 secs, 0.0002 secs

  Status code distribution:
  [200] 200 responses
  [502] 100 responses

原理实现

基于双向链表实现,减少滑动过程中过多的创建销毁

doublyLinkedList

bukcetCount 数值就是链表长度,每次初始化链表将会以当前时间末节点 + 节点的时间范畴开始 依次递减

举例:

  • 限速时间 limitTime=4s
  • 节点数量 bucketCount=4
  • 且当前时间为第 4

那么每个节点统计时间范畴为 1s

节点数据如下:(其他数据不具体展示)

nodeData

窗口滑动:

通过定时任务滑动,定时时间为每个节点统计的时间范畴值(单位毫秒)

说明:

  • 从初始化到后续的滑动,链表有效时间的节点只有末节点
  • 因此请求进来的都统一放入末节点 count
  • 因为滑动窗口会改变末节点,因此不需要遍历当前请求时间属于哪个节点

注意:

  • 此包只有全部限流,不能映射任何 key 或者其他字段来做分组
  • 如果有需求请自己创建线程安全 map 来映射限流数据

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type SlideWindow

type SlideWindow struct {
	LimitTime      int        // 限流区间长度 单位(秒)
	BucketCount    int        // 滑动窗口个数
	LimitCount     int        // 限流数量
	Count          int        // 统计数量
	StartTime      int64      // 开始时间
	EndTime        int64      // 结束时间
	BucketInterval int        // 窗口区间时间 单位(毫秒)
	BucketChain    *ring.Ring // 窗口环形链
	// contains filtered or unexported fields
}

滑动窗口

func Init

func Init(limitTime int, bucketCount int, limitCount int) (*SlideWindow, error)

初始化

func (*SlideWindow) Limiting

func (slideWindow *SlideWindow) Limiting() error

限流

func (*SlideWindow) Print

func (slideWindow *SlideWindow) Print()

打印数据

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL