zoukankan      html  css  js  c++  java
  • golang限流器

    服务限流

    在突发的流量下,通过限制用户访问的流量,保证服务能够正常运行

     常见的限流思路

    •  排队
    •  应用场景:秒杀抢购,用户点击抢购之后,进行排队,直到抢到或售罄为止
    •  拒绝
    •  应用场景:除秒杀之外的任何场景

     限流算法

    •  计数器限流算法
    •  漏桶限流算法
    •  令牌桶限流算法

    计数器限流算法

    • 在单位时间内进行计数,如果大于设置的最大值,则进行拒绝
    • 如果过了单位时间,则重新进行计数

    package main
    
    import (
        "fmt"
        "sync/atomic"
        "time"
    )
    
    type CounterLimit struct {
        counter      int64 //计数器
        limit        int64 //指定时间窗口内允许的最大请求数
        intervalNano int64 //指定的时间窗口
        unixNano     int64 //unix时间戳,单位为纳秒
    }
    
    func NewCounterLimit(interval time.Duration, limit int64) *CounterLimit {
    
        return &CounterLimit{
            counter:      0,
            limit:        limit,
            intervalNano: int64(interval),
            unixNano:     time.Now().UnixNano(),
        }
    }
    
    func (c *CounterLimit) Allow() bool {
    
        now := time.Now().UnixNano()
        if now-c.unixNano > c.intervalNano { //如果当前过了当前的时间窗口,则重新进行计数
            atomic.StoreInt64(&c.counter, 0)
            atomic.StoreInt64(&c.unixNano, now)
            return true
        }
    
        atomic.AddInt64(&c.counter, 1)
        return c.counter < c.limit //判断是否要进行限流
    }
    
    func main() {
    
        limit := NewCounterLimit(time.Second, 100)
        m := make(map[int]bool)
        for i := 0; i < 1000; i++ {
            allow := limit.Allow()
            if allow {
                //fmt.Printf("i=%d is allow
    ", i)
                m[i] = true
            } else {
                //fmt.Printf("i=%d is not allow
    ", i)
                m[i] = false
            }
        }
    
        for i := 0; i < 1000; i++ {
            fmt.Printf("i=%d allow=%v
    ", i, m[i])
        }
    }

    计数器限流算法

    优点:

      实现非常简单

    缺点:

      突发流量会出现毛刺现象

        比如一秒限流100个请求, 前100ms内处理完了100个请求,后900ms时间内没有请求处理

      计数不准确

    漏桶限流算法

    • 一个固定大小的水桶
    • 以固定速率流出
    • 水桶满了,则进行溢出(拒绝)

    package main
    
    import (
        "fmt"
        "math"
        "time"
    )
    
    type BucketLimit struct {
        rate       float64 //漏桶中水的漏出速率
        bucketSize float64 //漏桶最多能装的水大小
        unixNano   int64   //unix时间戳
        curWater   float64 //当前桶里面的水
    }
    
    func NewBucketLimit(rate float64, bucketSize int64) *BucketLimit {
        return &BucketLimit{
            bucketSize: float64(bucketSize),
            rate:       rate,
            unixNano:   time.Now().UnixNano(),
            curWater:   0,
        }
    }
    
    func (b *BucketLimit) reflesh() {
        now := time.Now().UnixNano()
        //时间差, 把纳秒换成秒
        diffSec := float64(now-b.unixNano) / 1000 / 1000 / 1000
        b.curWater = math.Max(0, b.curWater-diffSec*b.rate)
        b.unixNano = now
        return
    }
    
    func (b *BucketLimit) Allow() bool {
        b.reflesh()
        if b.curWater < b.bucketSize {
            b.curWater = b.curWater + 1
            return true
        }
    
        return false
    }
    
    func main() {
    
        //限速50qps, 桶大小100
        limit := NewBucketLimit(50, 100)
        m := make(map[int]bool)
        for i := 0; i < 1000; i++ {
            allow := limit.Allow()
            if allow {
                m[i] = true
                continue
            }
            m[i] = false
            time.Sleep(time.Millisecond * 10)
        }
    
        for i := 0; i < 1000; i++ {
            fmt.Printf("i=%d allow=%v
    ", i, m[i])
        }
    }

    漏桶限流算法

    优点

    • 解决了计数器限流算法的毛刺问题
    • 整体流量控制的比较平稳

    缺点

    • 无法应对某些突发的流量

    令牌桶限流算法

    • 一个固定大小的水桶
    • 以固定速率放入token
    • 如果能够拿到token则处理,否则拒绝

    package main
    
    import (
        "fmt"
    
        "golang.org/x/time/rate"
    )
    
    func main() {
    
        //限速50qps, 桶大小100
        limit := rate.NewLimiter(50, 100)
        for i := 0; i < 1000; i++ {
            allow := limit.Allow()
            if allow {
                fmt.Printf("i=%d is allow
    ", i)
                continue
            }
            fmt.Printf("i=%d is not allow
    ", i)
        }
    
    }

    优点

    不限制流速, 能够应对突发流量

  • 相关阅读:
    pycharm配置svn
    python发送邮件
    HttpRunner接口自动化测试框架--7.执行测试
    HttpRunner接口自动化测试框架--6.skip跳过用例
    HttpRunner接口自动化测试框架--5.hook机制
    python读取csv文件
    HttpRunner接口自动化测试框架--常见问题
    HttpRunner接口自动化测试框架--4.参数化操作(parameters)
    易错点
    pycharm破解
  • 原文地址:https://www.cnblogs.com/sunlong88/p/13622185.html
Copyright © 2011-2022 走看看