Home > Article > Backend Development > How to implement user daily limit in Go
This article is written by the golang tutorial column to introduce how to implement the user's daily limit in Go. I hope it will be helpful to friends in need!
Implement the user’s daily limit in Go (for example, you can only receive benefits three times a day)
If you write a bug management system and use this
PeriodLimit
, you can limit each tester to only submit one bug to you per day. Is work much easier? :P
The essential reason why microservice architecture is so popular nowadays is to reduce the overall complexity of the system, evenly distribute system risks to subsystems to maximize the stability of the system, and split it into different systems through domain division. After the subsystems are installed, each subsystem can be independently developed, tested, and released, and the R&D rhythm and efficiency can be significantly improved.
But it also brings problems, such as: the calling link is too long, the complexity of the deployment architecture increases, and various middleware needs to support distributed scenarios. In order to ensure the normal operation of microservices, service governance is indispensable, which usually includes: current limiting, downgrading, and circuit breaker.
Current limiting refers to limiting the frequency of interface calls to avoid exceeding the load limit and bringing down the system. For example:
E-commerce Flash Sale Scenario
API current limit for different merchants
Commonly used The current limiting algorithms are:
This article mainly explains the fixed time window current limiting algorithm.
Starting from a certain point in time, each request comes with a request count of 1. At the same time, it is judged whether the number of requests in the current time window exceeds the limit. If it exceeds the limit, it will be rejected. The request is then cleared when the next time window begins waiting for the request.
Advantages
Easy to implement It is efficient and is especially suitable for limiting scenarios such as a user can only post 10 articles a day, can only send SMS verification codes 5 times, and can only try to log in 5 times. Such scenarios are very common in actual business.
Disadvantages
The disadvantage of fixed time window current limiting is that it cannot handle critical section request burst scenarios.
Assume that the current limit is 100 requests every 1 second, and the user initiates 200 requests within 1 second starting from the middle 500ms. At this time, all 200 requests can be passed. This is inconsistent with our expectation of limiting the current to 100 times per second. The root cause is that the fine-grainedness of the current limit is too coarse.
Go-zero uses redis expiration time to simulate a fixed time window.##core/limit/periodlimit.go
redis lua script:-- KYES[1]:限流器key-- ARGV[1]:qos,单位时间内最多请求次数-- ARGV[2]:单位限流窗口时间-- 请求最大次数,等于p.quotalocal limit = tonumber(ARGV[1])-- 窗口即一个单位限流周期,这里用过期模拟窗口效果,等于p.permitlocal window = tonumber(ARGV[2])-- 请求次数+1,获取请求总数local current = redis.call("INCRBY",KYES[1],1)-- 如果是第一次请求,则设置过期时间并返回 成功if current == 1 then redis.call("expire",KYES[1],window) return 1-- 如果当前请求数量小于limit则返回 成功elseif current limit则返回 失败else return 0end
Fixed time window current limiter definitionPay attention to the align parameter, align= When true, the request upper limit will change periodically.type ( // PeriodOption defines the method to customize a PeriodLimit. // go中常见的option参数模式 // 如果参数非常多,推荐使用此模式来设置参数 PeriodOption func(l *PeriodLimit) // A PeriodLimit is used to limit requests during a period of time. // 固定时间窗口限流器 PeriodLimit struct { // 窗口大小,单位s period int // 请求上限 quota int // 存储 limitStore *redis.Redis // key前缀 keyPrefix string // 线性限流,开启此选项后可以实现周期性的限流 // 比如quota=5时,quota实际值可能会是5.4.3.2.1呈现出周期性变化 align bool } )
For example, when quota=5, the actual quota may be 5.4.3.2.1, showing periodic changes
Current limiting logicIn fact, the current limiting logic is above The lua script is implemented. It should be noted that the return value
// Take requests a permit, it returns the permit state. // 执行限流 // 注意一下返回值: // 0:表示错误,比如可能是redis故障、过载 // 1:允许 // 2:允许但是当前窗口内已到达上限 // 3:拒绝 func (h *PeriodLimit) Take(key string) (int, error) { // 执行lua脚本 resp, err := h.limitStore.Eval(periodScript, []string{h.keyPrefix + key}, []string{ strconv.Itoa(h.quota), strconv.Itoa(h.calcExpireSeconds()), }) if err != nil { return Unknown, err } code, ok := resp.(int64) if !ok { return Unknown, ErrUnknownCode } switch code { case internalOverQuota: return OverQuota, nil case internalAllowed: return Allowed, nil case internalHitQuota: return HitQuota, nil default: return Unknown, ErrUnknownCode } }
// 计算过期时间也就是窗口时间大小 // 如果align==true // 线性限流,开启此选项后可以实现周期性的限流 // 比如quota=5时,quota实际值可能会是5.4.3.2.1呈现出周期性变化 func (h *PeriodLimit) calcExpireSeconds() int { if h.align { now := time.Now() _, offset := now.Zone() unix := now.Unix() + int64(offset) return h.period - int(unix%int64(h.period)) } return h.period }Project addressgithub.com/zeromicro/go-zeroWelcome to use
go-zero and
star support us!
The above is the detailed content of How to implement user daily limit in Go. For more information, please follow other related articles on the PHP Chinese website!