首页 > 其他分享 >面试官:限流的实现方式有哪些?

面试官:限流的实现方式有哪些?

时间:2024-02-26 15:25:28浏览次数:34  
标签:面试官 请求 zone 哪些 网关 Nginx 限流 limit

限流是指在各种应用场景中,通过技术和策略手段对数据流量、请求频率或资源消耗进行有计划的限制,以避免系统负载过高、性能下降甚至崩溃的情况发生。限流的目标在于维护系统的稳定性和可用性,并确保服务质量。

使用限流的好处有以下几个:

  1. 保护系统稳定性:过多的并发请求可能导致服务器内存耗尽、CPU 使用率饱和,从而引发系统响应慢、无法正常服务的问题。
  2. 防止资源滥用:确保有限的服务资源被合理公平地分配给所有用户,防止个别用户或恶意程序过度消耗资源。
  3. 优化用户体验:对于网站和应用程序而言,如果任由高并发导致响应速度变慢,会影响所有用户的正常使用体验。
  4. 保障安全:在网络层面,限流有助于防范 DoS/DDoS 攻击,降低系统遭受恶意攻击的风险。
  5. 运维成本控制:合理的限流措施可以帮助企业减少不必要的硬件投入,节省运营成本。

在 Java 中,限流的实现方式有很多种,例如以下这些:

  1. 单机限流:使用 JUC 下的 Semaphore 限流,或一些常用的框架,例如 Google 的 Guava 框架进行限流,但这种限流方式都是基于 JVM 层面的内存级别的单台机器限流。
  2. 网关层限流:单机限流往往不适用于分布式系统,而分布式系统可以在网关层限流,如 Spring Cloud Gateway 通过 Sentinel、Hystrix 对整个集群进行限流。
  3. Nginx 限流:通常在网关层的上游,我们会使用 Nginx 一起来配合使用,也就是用户请求会先到 Nginx(或 Nginx 集群),然后再将请求转发给网关,网关再调用其他的微服务,从而实现整个流程的请求调用,因此 Nginx 限流也是分布式系统中常用的限流手段。

它们限流的具体实现如下。

1.单机限流

JVM 层面多线程级别的限流可以使用 JUC 下的 Semaphore,具体使用示例如下:

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class SemaphoreExample {

    private final Semaphore semaphore = new Semaphore(5); // 只允许5个线程同时访问

    public void accessResource() {
        try {
            semaphore.acquire(); // 获取许可,如果当前许可数不足,则会阻塞
            System.out.println(Thread.currentThread().getName() + "获得了许可,正在访问资源...");
            // 模拟访问资源的时间消耗
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + "访问资源结束,释放许可...");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            e.printStackTrace();
        } finally {
            semaphore.release(); // 访问结束后释放许可
        }
    }

    public static void main(String[] args) {
        SemaphoreExample example = new SemaphoreExample();

        for (int i = 0; i < 10; i++) {
            new Thread(() -> example.accessResource()).start();
        }
    }
}

想要实现更平滑的单机限流,可以考虑 Google 提供的 Guava 框架,它的使用示例如下。

首先在 pom.xml 添加 guava 引用,配置如下:

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>28.2-jre</version>
</dependency>

具体实现代码如下:

import com.google.common.util.concurrent.RateLimiter;
import java.time.Instant;

/**
 * Guava 实现限流
 */
public class RateLimiterExample {
    public static void main(String[] args) {
        // 每秒产生 10 个令牌(每 100 ms 产生一个)
        RateLimiter rt = RateLimiter.create(10);
        for (int i = 0; i < 11; i++) {
            new Thread(() -> {
                // 获取 1 个令牌,获取到令牌就执行,否则就阻塞等待
                rt.acquire();
                System.out.println("正常执行方法,ts:" + Instant.now());
            }).start();
        }
    }
}

2.网关层限流

在 Spring Cloud Gateway 网关层限流,可以借助 Sentinel 等限流框架来实现,它的实现步骤如下。

首先,在 pom.xml 中添加 Gateway 和 Sentinel 相关依赖,如下所示:

<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>

配置限流相关的规则,如下示例所示:

spring:
  application:
    name: gate-way-blog
  cloud:
    sentinel:
      transport:
        dashboard: localhost:18080
      scg: # 配置限流之后,响应内容
        fallback:
          # 两种模式,一种是 response 返回文字提示信息,
          # 另一种是 redirect 重定向跳转,不过配置 redirect 也要配置对应的跳转的 uri
          mode: response
          # 响应的状态
          response-status: 200
          # 响应体
          response-body: '{"code": -10,"message": "被熔断或限流!"}'

最后在 Sentinel 控制台配置网关的限流设置即可,当然也可以使用 Nacos 作为数据源,两者选择配置其中一个即可。

3.Nginx 限流

Nginx 提供了两种限流手段:

  • 通过控制速率来实现限流。
  • 通过控制并发连接数来实现限流。

我们一个一个来看。

3.1 控制速率实现限流

我们需要使用 limit_req_zone 用来限制单位时间内的请求数,即速率限制,示例配置如下:

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s;
server {
  location / {
    limit_req zone=mylimit;
  }
}

以上配置表示,限制每个 IP 访问的速度为 2r/s,因为 Nginx 的限流统计是基于毫秒的,我们设置的速度是 2r/s,转换一下就是 500ms 内单个 IP 只允许通过 1 个请求,从 501ms 开始才允许通过第 2 个请求。

我们使用单 IP 在 10ms 内发并发送了 6 个请求的执行结果如下:

从以上结果可以看出他的执行符合我们的预期,只有 1 个执行成功了,其他的 5 个被拒绝了(第 2 个在 501ms 才会被正常执行)。

速率限制升级版

上面的速率控制虽然很精准但是应用于真实环境未免太苛刻了,真实情况下我们应该控制一个 IP 单位总时间内的总访问次数,而不是像上面那么精确但毫秒,我们可以使用 burst 关键字开启此设置,示例配置如下:

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s;
server {
  location / {
    limit_req zone=mylimit burst=4;
  }
}

burst=4 表示每个 IP 最多允许4个突发请求,如果单个 IP 在 10ms 内发送 6 次请求的结果如下:

从以上结果可以看出,有 1 个请求被立即处理了,4 个请求被放到 burst 队列里排队执行了,另外 1 个请求被拒绝了。

3.2 控制并发数实现限流

利用 limit_conn_zone 和 limit_conn 两个指令即可控制并发数,示例配置如下:

limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
server {
  ...
  limit_conn perip 10;
  limit_conn perserver 100;
}

其中 limit_conn perip 10 表示限制单个 IP 同时最多能持有 10 个连接;limit_conn perserver 100 表示 server 同时能处理并发连接的总数为 100 个。

小贴士:只有当 request header 被后端处理后,这个连接才进行计数。

课后思考

Semaphore 限流和 Guava 限流有什么区别?Sentinel 和 Nginx 限流有什么不足?应该如何避免?

标签:面试官,请求,zone,哪些,网关,Nginx,限流,limit
From: https://www.cnblogs.com/vipstone/p/18034390

相关文章

  • APP应用内测分发时需要注意哪些
    作为开发人员,我们都知道,一个APP的成功与否,不仅取决于其功能和用户体验,更与其分发方式息息相关。尤其在当前市场竞争激烈的环境下,如何让你的APP脱颖而出,快速触达目标用户,是每一个开发者都面临的挑战。而作为行业内知名的APP分发平台,虾分发https://xiafenfa.com/始终站在分发技术的......
  • 五金配件ERP软件做什么的?能够协助企业处理哪些问题
        在我们的日常生活当中广泛的使用五金配件,这些配件有各式各样的款式、尺码、规格等。另外,这些差异化的五金配件营销渠道多、销售策略灵活、价格波动变化快,这些也给五金配件企业的经营管理带来不少难题。而五金配件产品的制造存在工艺多变、替代料繁多、工序繁杂等情......
  • 在K8S中,Pod亲和性和反亲和性作用区别有哪些?该如何使用?
    1.Pod亲和性(PodAffinity)作用:资源协同:当Pod需要与具有特定标签的Node或已经在特定Node上运行的Pod紧密合作时,比如共享硬件加速器或者进行高效的数据交互,可以利用Pod亲和性将这些Pod调度到一起。负载分片:在大规模集群中,可以根据业务需求,将相似类型的Pod调度到同一组Node上,以......
  • 在K8S中,影响pod调度的因素有哪些?
    在Kubernetes(K8s)中,影响Pod调度的因素非常多,主要包括但不限于以下几个方面:资源需求与限制:资源请求(Requests):Pod在创建时声明需要的最小资源量,如CPU和内存。调度器会寻找至少能满足这些资源请求的Node进行调度。资源限额(Limits):Pod可使用的最大资源量,超过限额可能会被系统限......
  • OpenResty中如何实现,按QPS、时间范围、来源IP进行限流
    OpenResty是一个基于Nginx与Lua的高性能Web平台,它通过LuaJIT在Nginx中运行高效的Lua脚本和模块,可以用来处理复杂的网络请求,并且支持各种流量控制和限制的功能。近期研究在OpenResty中如何实现,按QPS、时间范围、来源IP进行限流,以及动态更新限流策略。今天将实现方案分享给大家。......
  • 有哪些适合程序员的副业?
    如果你经常玩知乎、看公众号(软件、工具、互联网这几类的)你就会发现,好多资源连接都变成了夸克网盘、迅雷网盘的资源链接。例如:天涯神贴,基本上全是夸克、UC、迅雷网盘的资源链接。有资源的前提下,迅雷网盘拉新基本上是躺赚!汇总迅雷网盘拉新相关的5个问题:1、拉新的流程是什么?保......
  • 面试官:你知道Comparable 和 Comparator 的区别吗?我:巴拉巴拉
    写在开头面试官:“我们在Java的集合和数据结构中都离不开比较器,请你聊一聊Comparable和Comparator这两种的区别吧”内心活动:“上来就这么直接吗,那些ArrayList,HashMap都不问呀,好,既然如此,那让我来征服你吧,面试官大人!”我:“好滴!巴拉巴拉~”ComparableComparable是java.lang包......
  • 西安有哪些值得去的互联网公司?最新版
    接下来的一段时间,我将出一些地方上比较值得去的公司,供Java程序员作为找工作和跳槽时进行挑选。西安作为中国西部的科技和互联网产业发展的重要城市,拥有着少些知名且对Java程序员具有吸引力的互联网公司,接下来,我们将分这些公司分为3类来介绍:私企国企外企0.国企、私企......
  • 9.Polly在NET中的使用,重试、熔断、超时、降级、限流简单用法
    Polly是一个.NET弹性和瞬态故障处理库,允许开发人员以Fluent和线程安全的方式来实现重试、断路、超时、隔离、限流和降级策略。文档: https://gitee.com/hubo/Polly重试(Retry)出现故障自动重试,这个是很常见的场景,如:当发生请求异常、网络错误、服务暂时不可用时,就应该重试。......
  • 在K8S中,存储敏感信息方式有哪些?
    在Kubernetes(K8s)中,存储敏感信息主要有以下几种方式:使用Secret资源:Kubernetes通过Secret资源对象来安全地存储和管理敏感数据,如密码、密钥、证书等。Secret的数据以密文形式存储在etcd集群中。创建Secret的方式有多种:--from-literal:直接在命令行创建时指定,每个--from-liter......