【golang】简单模拟实现服务器限制QPS

服务器限流可以降低服务器的压力,如果我们将QPS限定在1000,那么就可以保证服务器每秒处理的请求不会超过1000,超过1000的那一部分直接返回一个错误信息就行了,不然他走业务流程。

思路一

假设我们需要限流QPS为100,我们可以实现预备好100个牌子,请求到了先尝试拿牌子,拿到牌子后才能进入业务流程,否则就直接返回错误信息。同时我们开启一个协程去不停的补充牌子。

package main

import (
	"fmt"
	"time"
)

func main() {
	go addRemain()
	for {
		time.Sleep(time.Microsecond * 500)
		fmt.Println(getData())
	}
}

var remain = 100

func getData() string {
	if remain > 0 {
		remain--
	} else {
		return "被限流了"
	}
	return "message"
}

func addRemain() {
	for {
		time.Sleep(time.Millisecond * 10)
		if remain >= 100 {
			continue
		}
		remain += 1
	}
}

思路二

上面这种方法会导致addRemain()在1秒内被多次执行,效率比较差,也不够优雅。其实我们可以在请求到来的时候才顺便添加牌子,根据距离上一次请求过去的时间,来决定应该添加多少个牌子,这样子就降低了addRemain协程的无效执行次数。
或者说,可以在请求处理结束后,归还牌子,这样子就不需要自己手动添加令牌了,这样子的话其实就不是限制QPS了,而是限制最大并发数,不过也没问题,我们限制QPS的最终目的不就是为了限制最大并发量吗。

思路三

根据上一次请求的时间戳,决定下一次请求应该在什么时间戳,如果还没到时间就来请求,就拦截,否则放心,更新下一次时间戳。

package main

import (
	"fmt"
	"time"
)

const MAX_QPS int64 = 500           // 每秒访问量
const MAX_NPQ int64 = 1e9 / MAX_QPS // 两次访问之间应该隔多少纳秒

var nextTimestamp int64

func main() {
	nextTimestamp = time.Now().UnixNano()
	count := 0
	for {
		if getData() == "message" {
			count++
			fmt.Printf("成功请求了%d次\n", count)
		}
	}
}

func getData() string {
	now := time.Now().UnixNano()
	if now < nextTimestamp {
		return "被限流了"
	}
	//更新下一次时间戳
	nextTimestamp = now + MAX_NPQ
	return "message"
}


我们运行程序,发现成功请求次数大概每秒打印500次左右(实际上远比500小),然后将QPS改成5,发现打印频率明显下降。说明我们的限流成功了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值