为什么需要这三个功能?
高并发场景下,服务器可能会因为爆炸性的流量冲击导致拒绝服务,甚至整个服务集群都会因为出现雪崩效益而大面积宕机。那么,如何在高并发场景下依然能提供稳定且高效的服务?
众所周知,高效的服务是建立在稳定的服务器基础上的,如果服务器只在某一时刻好用,某一时刻一直转圈圈甚至连接失败,那你在那个好用时刻的高光表现将完全被这个不好用给淹没,因此,服务器的稳定是第一优先级。因此,标题所讲的这三个功能,就是保证服务器在任何情况下,都能保持稳定的服务的关键。
服务的稳定性
当系统的整体负荷超过了它能提供的极限,如果任由其野马脱缰,终究会造成不可预估的结果,这里先不考虑提升这匹马(增加硬件环境,如cpu、内存、服务集群等)的素质所带来的好处,只考虑如何让这匹脱缰的野马重归于好。那么这里业界通常普遍的做法则是减负,表现形式则分别两种,一是降级,而是熔断。
降级是从宏观层面考虑。把不重要的服务暂时下降其优先级,使其占用系统的资源减少,从而给整体减负。 熔断是从微观层面考虑。也称服务过载保护,某服务负载过大,则下降甚至关闭其提供服务的能力,也可以达到给系统减负的目的。
从某种层面上来讲,熔断、限流分别都是降级的一种特殊情况。
降级的方式
- 限流。输入输出流量限制。
- 熔断。暂停服务。
- 延迟服务(缓存)。不直接读写db,采用缓存的方式提供服务,等服务恢复正常后,再同步至db。
限流
常见限流方式
计数器
计数器主要目的是限制系统在固定时间间隔内允许处理的最大作业数。根据其固定时间间隔规则的不同,又分为三类。
- 固定窗口计数器 - 限制在给定的固定时间间隔内允许执行多少个作业。 如每分钟最多处理100个作业,到下一分钟时,则重新开始计数。
- 滑动窗口计数器 - 限制在任何特定时间间隔内允许执行多少个作业执行。 如最近一分钟最多处理100个作业,随着时间的推移,当每个作业开始执行时间过去一分钟后,都会释放一次计数器。
https://media.pearsoncmg.com/aw/ecs_kurose_compnetwork_7/cw/content/interactiveanimations/selective-repeat-protocol/index.html
- 动态窗口计数器 - 允许根据作业参数动态创建窗口计数器。 这里可以根据参数动态选择是固定还是滑动窗口,时间间隔周期是多少,设置完成后下次作业开始时,自动生效。
代码示例:
代码语言:javascript复制# 固定窗口计数器,一分钟过期时间缓存,每次来一个请求,计数器加1,一分钟后过期,重新生成计数器
const CounterCacheKey = "CounterCacheKey"
cache := NewCache(cache.WithExpiration(time.Minutes))
counter, ok := cache.Get(CounterCacheKey)
if !ok{
counter = NewCounter(100) // Maximum
}
defer cache.Put(CounterCacheKey, counter)
counter.Increase() // Block until the increase is successful
// Continue processing
# 滑动窗口计数器