Fix: overload_control/flow_control:smooth_limiter issues related to accuracy and efficiency #185 #186
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
解决方案
通过引入
RecentQueue来实现滑动窗口算法。RecentQueue用来保存滑动窗口内最近所有活跃请求的时间戳。从实现上说,依然使用 ring queue,该队列的初始大小为 QPS(滑动窗口内能够保存连接的最大值)。不难看出,由于
RecentQueue保存时序,所以在RecentQueue内时间戳螺旋递增,RecentQueue是一个有序结构。在
RecentQueue中cur表示存放当前请求时间戳的位置。当新请求到达的时候,cur指示RecentQueue中缓存最久的时间戳。过滤请求
当一个请求到达的时候,该请求的时间戳为
now。当
now - 1s < RecentQueue[cur]时,说明当前RecentQueue已满,且缓存最久时间戳RecentQueue[cur]比较新,不能被淘汰,故应拒绝本次访问;当
now - 1s ≥ RecentQueue[cur]时,说明缓存最久时间戳RecentQueue[cur]缓存时间超过1s 可以被淘汰,故更新RecentQueue。流程的时间复杂度为O(1)。
求当前时刻滑动窗口内活跃请求总数
由于
RecentQueue具有螺旋递增的性质,其逻辑结构是一个有序结构,故能够通过二分查找找到第一个满足大于now - 1s的位置,与当前 cur 做偏移量计算即可得到当前时刻滑动窗口内活跃请求总数。流程的时间复杂度为O(logn)。
算法设计思想
惰性求值
这一点沿用了之前设计令牌桶算法时的思想。
建模——以缓存设计的角度解决滑动窗口问题
熟悉缓存策略的朋友应该不难看出这个算法有点像
LRU。RecentQueue和Least Recently Used稍有区别:RecentQueue缓存时间戳只访问/缓存一次;Least Recently Used缓存的对象可能被访问多次。访问次数的差异,造成了在底层数据结构选型的不同,LRU需要频繁插入、删除,故而使用双向链表结构,另外,为了提升LRU查找的能力,通常在LRU实现的时候维护 hash 表。RecentQueue有拒绝更新缓存的能力;相反,LRU没有。算法优点