高可用之限流降级_压测流量降级-程序员宅基地

技术标签: 限流  降级  高可用  

高可用之限流降级

1、前言

在大规模微服务架构的场景下,为了避免服务出现雪崩,要减少停机时间,尽可能的提高服务可用性。提高服务可用性,可以从很多方向入手,比如缓存、池化、异步化、负载均衡、队列和降级熔断等手段。

  • 缓存以及队列等手段,增加系统的容量
  • 限流和降级则是关心在到达系统瓶颈时系统的响应,更看重稳定性

缓存和异步等关注提高系统战力,而限流降级则关注增强系统防御,具体实施方法可以归纳为八字箴言,限流、降级、熔断、隔离

2、限流&降级

2.1、限流

  • 限流,顾名思义,即提前对各个类型的请求设置最高的QPS阈值,若高于设置的阈值则对该请求直接返回,不再调用后续资源

  • 限流需要结合压测等,了解系统的最高水位,也是在实际开发中应用最多的一种稳定性保障手段。

2.2、降级

  • 降级,则是指在系统调用高峰时,优先保证核心服务,对于非核心服务可以选择将其关闭以保证核心服务的可用。 例如在淘宝双11时,支付功能是核心,其他诸如用户中心等非核心功能可以选择降级,优先保证交易。

  • 从降级配置方式上,降级一般可以分为主动降级和自动降级

    • 主动降级是提前配置,自动降级则是系统发生故障时,如超时或者频繁失败,自动降级。
    • 其中自动降级,又可以分为以下策略:
      • 超时降级
      • 失败次数降级
      • 故障降级

2.3、降级通知设计

在系统设计中,降级一般是结合系统配置中心,通过配置中心进行推送,下面是一个典型的降级通知设计:

img

3、 熔断&隔离

3.1、熔断

  • 如果某个目标服务调用慢或者有大量超时,此时熔断该服务的调用,对于后续调用请求,不在继续调用目标服务,直接返回,快速释放资源。

  • 熔断一般需要设置不同的恢复策略,如果目标服务情况好转则恢复调用。

3.2、隔离

服务隔离与前面的三个略有区别,我们的系统通常提供了不止一个服务,但是这些服务在运行时是部署在一个实例,或者一台物理机上面的,如果不对服务资源做隔离,一旦一个服务出现了问题,整个系统的稳定性都会受到影响!

  • 服务隔离的目的就是避免服务之间相互影响。一般来说,隔离要关注两方面,一个是在哪里进行隔离,另外一个是隔离哪些资源。
  • 何处隔离?

    • 一次服务调用,涉及到的是服务提供方和调用方,我们所指的资源,也是两方的服务器等资源,服务隔离通常可以从提供方和调用方两个方面入手。
  • 隔离什么?

    • 广义的服务隔离,不仅包括服务器资源,还包括数据库分库,缓存,索引等,这里我们只关注服务层面的隔离。

3.3、降级和熔断的区别

服务降级和熔断在概念上比较相近,通过两个场景,谈谈我自己的理解。

  • 熔断,一般是停止服务

典型的就是股市的熔断,如果大盘不受控制,直接休市,不提供服务,是保护大盘的一种方式。

  • 降级,通常是有备用方案

从深圳到郑州,下雨导致航班延误,我可以乘坐高铁,如果高铁票买不到,也可以乘坐汽车或者开车过去。

  • 两者的区别

降级一般是主动的,有预见性的,熔断通常是被动的,服务A降级以后,一般会有服务B来代替,而熔断通常是针对核心链路的处理。实际开发中,熔断的下一步通常就是降级

4、常用限流算法设计

4.1、计数器法

计数器法是限流算法里最简单也是最容易实现的一种算法。

  • 假设一个接口限制一分钟内的访问次数不能超过100个,维护一个计数器,每次有新的请求过来,计数器加一,这时候判断,如果计数器的值小于限流值,并且与上一次请求的时间间隔还在一分钟内,允许请求通过,否则拒绝请求,如果超出了时间间隔,要将计数器清零。

  • 计数器限流可以比较容易的应用在分布式环境中,用一个单点的存储来保存计数值,比如用Redis,并且设置自动过期时间,这时候就可以统计整个集群的流量,并且进行限流。

  • 计数器方式的缺点是不能处理临界问题,或者说限流策略不够平滑。假设在限流临界点的前后,分别发送100个请求,实际上在计数器置0前后的极短时间里,处理了200个请求,这是一个瞬时的高峰,可能会超过系统的限制。

  • 计数器限流允许出现2*permitsPerSecond 的突发流量,可以使用滑动窗口算法去优化

4.2 漏桶算法

  • 假设我们有一个固定容量的桶,桶底部可以漏水(忽略气压等,不是物理问题),并且这个漏水的速率可控的,那么我们可以通过这个桶来控制请求速度,也就是漏水的速度。

  • 我们不关心流进来的水,也就是外部请求有多少,桶满了之后,多余的水会溢出。

漏桶算法的示意图如下:

img
  • 将算法中的水换成实际应用中的请求,可以看到漏桶算法从入口限制了请求的速度。
  • 使用漏桶算法,我们可以保证接口会以一个常速速率来处理请求,所以漏桶算法不会出现临界问题。漏桶算法无法解决系统突发流量的情况
  • 可以使用GuavaSmoothWarmingUp类,可以更好的控制漏桶算法,

4.3 令牌桶算法

  • 假设一个大小恒定的桶,桶里存放着令牌(token)。桶一开始是空的,现在以一个固定的速率往桶里填充,直到达到桶的容量,多余的令牌将会被丢弃。

  • 如果令牌不被消耗,或者被消耗的速度小于产生的速度,令牌就会不断地增多,直到把桶填满。后面再产生的令牌就会从桶中溢出。最后桶中可以保存的最大令牌数永远不会超过桶的大小,

  • 每当一个请求过来时,就会尝试从桶里移除一个令牌,如果没有令牌的话,请求无法通过

  • 在令牌桶算法中,只要令牌桶中存在令牌,那么就允许突发地传输数据直到达到用户配置的门限,因此它适合于具有突发特性的流量。

4.4、令牌桶和漏桶区别

  • 漏桶是控制水流入的速度,令牌桶则是控制流出,通过控制token,调节流量。

  • 令牌桶算法相对漏桶算法的优势在于可以处理系统的突发流量

  • 这两种算法的主要区别在于漏桶算法能够强行限制数据的传输速率,而令牌桶算法在能够限制数据的平均传输速率外,还允许某种程度的突发传输。

5、使用RateLimiter实现限流

  • Google开源工具包Guava提供了限流工具类RateLimiter,该类基于令牌桶算法实现流量限制,使用方便。

  • RateLimiter使用的是令牌桶的流控算法,RateLimiter会按照一定的频率往桶里扔令牌,线程拿到令牌才能执行,比如你希望自己的应用程序QPS不要超过1000,那么RateLimiter设置1000的速率后,就会每秒往桶里扔1000个令牌,方法说明如下:

import com.google.common.util.concurrent.RateLimiter;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class RateLimiterExample {
    

    public static void main(String[] args) throws InterruptedException {
    
        // qps设置为5,代表一秒钟只允许处理五个并发请求
        RateLimiter rateLimiter = RateLimiter.create(5);
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        int nTasks = 10;
        CountDownLatch countDownLatch = new CountDownLatch(nTasks);
        long start = System.currentTimeMillis();
        for (int i = 0; i < nTasks; i++) {
    
            final int j = i;
            executorService.submit(() -> {
    
                rateLimiter.acquire(1);
                try {
    
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
    
                }
                System.out.println(Thread.currentThread().getName() + " gets job " + j + " done");
                countDownLatch.countDown();
            });
        }
        executorService.shutdown();
        countDownLatch.await();
        long end = System.currentTimeMillis();
        System.out.println("10 jobs gets done by 5 threads concurrently in " + (end - start) + " milliseconds");
    }
}


5.1、算法原理

RateLimiter基于令牌桶算法,它的核心思想主要有:

  1. 响应本次请求之后,动态计算下一次可以服务的时间,如果下一次请求在这个时间之前则需要进行等待。SmoothRateLimiter类中的 nextFreeTicketMicros 属性表示下一次可以响应的时间。例如,如果我们设置QPS为1,本次请求处理完之后,那么下一次最早的能够响应请求的时间一秒钟之后。
  2. RateLimiter 的子类 SmoothBursty 支持处理突发流量请求,例如,我们设置QPS为1,在十秒钟之内没有请求,那么令牌桶中会有10个(假设设置的最大令牌数大于10)空闲令牌,如果下一次请求是 acquire(20) ,则不需要等待20秒钟,因为令牌桶中已经有10个空闲的令牌SmoothRateLimiter 类中的 storedPermits 就是用来表示当前令牌桶中的空闲令牌数。
  3. acquire 方法没有等待超时的概念,会一直阻塞直到满足本次请求。
  4. RateLimiter 子类SmoothWarmingUp 不同于SmoothBursty,它存在一个“热身”的概念。它将 storedPermits 分成两个区间值:[0, thresholdPermits) 和 [thresholdPermits, maxPermits]。当请求进来时,如果当前系统处于"cold"的状态,从 [thresholdPermits, maxPermits] 区间去拿令牌,所需要等待的时间会长于从区间 [0, thresholdPermits) 拿相同令牌所需要等待的时间。当请求增多,storedPermits 减少到 thresholdPermits 以下时,此时拿令牌所需要等待的时间趋于稳定。这也就是所谓“热身”的过程。这个过程后面会详细分析。

RateLimiter主要的类的类图如下所示:

image-20200813074533804

RateLimiter 是一个抽象类,SmoothRateLimiter继承自RateLimiter,不过 SmoothRateLimiter 仍然是一个抽象类,SmoothBurstySmoothWarmingUp 才是具体的实现类。

5.2、SmoothRateLimiter主要属性

storedPermits 表明当前令牌桶中有多少令牌。maxPermits 表示令牌桶最大令牌数目,storedPermits 的取值范围为:[0, maxPermits]。stableIntervalMicros 等于 1/qps,它代表系统在稳定期间,两次请求之间间隔的微秒数。例如:如果我们设置的 qps 为5,则 stableIntervalMicros 为200ms。nextFreeTicketMicros 表示系统处理完当前请求后,下一次请求被许可的最短微秒数,如果在这之前有请求进来,则必须等待。

当我们设置了 qps 之后,需要计算某一段时间系统能够生成的令牌数目,那么怎么计算呢?一种方式是开启一个后台任务去做,但是这样代价未免有点大。RateLimiter 中采取的是惰性计算方式:在每次请求进来的时候先去计算上次请求和本次请求之间应该生成多少个令牌。

【面试系列】会持续更新,欢迎关注公众号“任冬学编程”,一起学习与进步!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_29893385/article/details/120004980

智能推荐

linux devkmem 源码,linux dev/mem dev/kmem实现访问物理/虚拟内存-程序员宅基地

文章浏览阅读451次。dev/mem: 物理内存的全镜像。可以用来访问物理内存。/dev/kmem: kernel看到的虚拟内存的全镜像。可以用来访问kernel的内容。调试嵌入式Linux内核时,可能需要查看某个内核变量的值。/dev/kmem正好提供了访问内核虚拟内存的途径。现在的内核大都默认禁用了/dev/kmem,打开的方法是在 make menuconfig中选中 device drivers --> ..._dev/mem 源码实现

vxe-table 小众但功能齐全的vue表格组件-程序员宅基地

文章浏览阅读7.1k次,点赞2次,收藏19次。vxe-table,一个小众但功能齐全并支持excel操作的vue表格组件_vxe-table

(开发)bable - es6转码-程序员宅基地

文章浏览阅读62次。参考:http://www.ruanyifeng.com/blog/2016/01/babel.htmlBabelBabel是一个广泛使用的转码器,可以将ES6代码转为ES5代码,从而在现有环境执行// 转码前input.map(item => item + 1);// 转码后input.map(function (item) { return item..._让开发环境支持bable

FPGA 视频处理 FIFO 的典型应用_fpga 频分复用 视频-程序员宅基地

文章浏览阅读2.8k次,点赞6次,收藏29次。摘要:FPGA视频处理FIFO的典型应用,视频输入FIFO的作用,视频输出FIFO的作用,视频数据跨时钟域FIFO,视频缩放FIFO的作用_fpga 频分复用 视频

R语言:设置工作路径为当前文件存储路径_r语言设置工作目录到目标文件夹-程序员宅基地

文章浏览阅读575次。【代码】R语言:设置工作路径为当前文件存储路径。_r语言设置工作目录到目标文件夹

background 线性渐变-程序员宅基地

文章浏览阅读452次。格式:background: linear-gradient(direction, color-stop1, color-stop2, ...);<linear-gradient> = linear-gradient([ [ <angle> | to <side-or-corner>] ,]? &l..._background线性渐变

随便推点

【蓝桥杯省赛真题39】python输出最大的数 中小学青少年组蓝桥杯比赛 算法思维python编程省赛真题解析-程序员宅基地

文章浏览阅读1k次,点赞26次,收藏8次。第十三届蓝桥杯青少年组python编程省赛真题一、题目要求(注:input()输入函数的括号中不允许添加任何信息)1、编程实现给定一个正整数N,输出正整数N中各数位最大的那个数字。例如:N=132,则输出3。2、输入输出输入描述:只有一行,输入一个正整数N输出描述:只有一行,输出正整数N中各数位最大的那个数字输入样例:

网络协议的三要素-程序员宅基地

文章浏览阅读2.2k次。一个网络协议主要由以下三个要素组成:1.语法数据与控制信息的结构或格式,包括数据的组织方式、编码方式、信号电平的表示方式等。2.语义即需要发出何种控制信息,完成何种动作,以及做出何种应答,以实现数据交换的协调和差错处理。3.时序即事件实现顺序的详细说明,以实现速率匹配和排序。不完整理解:语法表示长什么样,语义表示能干什么,时序表示排序。转载于:https://blog.51cto.com/98..._网络协议三要素csdn

The Log: What every software engineer should know about real-time data's unifying abstraction-程序员宅基地

文章浏览阅读153次。主要的思想,将所有的系统都可以看作两部分,真正的数据log系统和各种各样的query engine所有的一致性由log系统来保证,其他各种query engine不需要考虑一致性,安全性,只需要不停的从log系统来同步数据,如果数据丢失或crash可以从log系统replay来恢复可以看出kafka系统在linkedin中的重要地位,不光是d..._the log: what every software engineer should know about real-time data's uni

《伟大是熬出来的》冯仑与年轻人闲话人生之一-程序员宅基地

文章浏览阅读746次。伟大是熬出来的  目录  前言  引言 时间熬成伟大:领导者要像狼一样坚忍   第一章 内圣外王——领导者的心态修炼  1. 天纵英才的自信心  2. 上天揽月的企图心  3. 誓不回头的决心  4. 宠辱不惊的平常心  5. 换位思考的同理心  6. 激情四射的热心  第二章 日清日高——领导者的高效能修炼  7. 积极主动,想到做到  8. 合理掌控自己的时间和生命  9. 制定目标,马..._当狼拖着受伤的右腿逃生时,右腿会成为前进的阻碍,它会毫不犹豫撕咬断自己的腿, 以

有源光缆AOC知识百科汇总-程序员宅基地

文章浏览阅读285次。在当今的大数据时代,人们对高速度和高带宽的需求越来越大,迫切希望有一种新型产品来作为高性能计算和数据中心的主要传输媒质,所以有源光缆(AOC)在这种环境下诞生了。有源光缆究竟是什么呢?应用在哪些领域,有什么优势呢?易天将为您解答!有源光缆(Active Optical Cables,简称AOC)是两端装有光收发器件的光纤线缆,主要构成部件分为光路和电路两部分。作为一种高性能计..._aoc 光缆

浏览器代理服务器自动配置脚本设置方法-程序员宅基地

文章浏览阅读2.2k次。在“桌面”上按快捷键“Ctrl+R”,调出“运行”窗口。接着,在“打开”后的输入框中输入“Gpedit.msc”。并按“确定”按钮。如下图 找到“用户配置”下的“Windows设置”下的“Internet Explorer 维护”的“连接”,双击选择“自动浏览器配置”。如下图 选择“自动启动配置”,并在下面的“自动代理URL”中填写相应的PAC文件地址。如下..._設置proxy腳本