Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级

这篇具有很好参考价值的文章主要介绍了Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级,【Spring Boot2.X】,spring boot,RateLimiter,Resilience4j


Resilience4j概述

Resilience4J 是一个针对 Java 8 应用程序的轻量级容错和弹性库。它设计用于在分布式系统中的服务之间提供弹性和容错性。Resilience4J 的名字来源于它提供的核心功能,即让系统(服务)能够“弹性”(resilient)地应对各种失败情况,包括网络问题、第三方服务故障等。

Resilience4J 提供了以下功能:

  1. 断路器(Circuit Breaker):当检测到服务异常或超时,断路器会打开,阻止进一步的请求发送到该服务。一段时间后(通常是秒级),断路器会进入半开状态,允许一个测试请求通过以检查服务是否恢复。如果请求成功,断路器关闭;如果失败,断路器会再次打开。
  2. 限流(Rate Limiter):限制进入系统的请求速率,防止系统过载。这可以通过令牌桶算法或滑动窗口算法实现。
  3. 隔离(Isolation):通过信号量或线程池隔离不同的服务调用,防止一个服务的失败影响到其他服务。
  4. 超时(Timeouts):为服务调用设置超时时间,超过时间后会触发超时异常。
  5. 重试(Retry):在遇到特定异常时自动重试服务调用,可以配置重试次数和间隔。
  6. 缓存(Caching):提供缓存机制,以避免重复执行计算密集型或远程调用。

Resilience4J 的一大特点是它的轻量级特性,它只使用了 Vavr 库(一个函数式编程库),没有其他外部库依赖。这使得它在集成到现有系统时非常方便,且性能开销小。

Resilience4J 设计上易于配置,支持通过代码、配置文件或运行时参数进行配置。它也支持通过 actuator 模块与 Spring Boot 的监控和管理特性集成。

由于 Resilience4J 的这些特性和优势,它在现代分布式系统和微服务架构中得到了广泛应用,尤其是在需要高可用性和弹性的环境中。


Resilience4j官方地址

https://resilience4j.readme.io/

Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级,【Spring Boot2.X】,spring boot,RateLimiter,Resilience4j

https://github.com/resilience4j/resilience4j

Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级,【Spring Boot2.X】,spring boot,RateLimiter,Resilience4j


Resilience4j-RateLimiter

https://resilience4j.readme.io/docs/ratelimiter

Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级,【Spring Boot2.X】,spring boot,RateLimiter,Resilience4j

RateLimiter 的默认实现是 AtomicRateLimiter ,它通过 AtomicReference 管理其状态。 AtomicRateLimiter.State 是完全不可变的。

功能点:

  • Warm-Up Period: 当启动应用程序或重置后,可能会有一个预热期,在此期间速率限制器逐渐增加允许的请求速率。这是为了防止启动后流量突然激增,从而可能导致系统过载。

  • Steady State: 预热期结束后,速率限制器进入稳定状态。在此阶段,速率限制器根据配置的速率限制允许请求通过。例如,如果将限制设置为每分钟 100 个请求,则速率限制器将允许大约每 0.6 秒一个请求。

  • Limit Exceeded: 如果传入请求速率超过配置的限制,速率限制器立即开始拒绝超出的请求。

  • Replenishing Tokens: 速率限制器以与配置的限制相对应的速率持续补充“Token”。每个允许的请求消耗一个令牌。如果系统未充分利用允许的速率,则未使用的令牌会累积,从而允许偶尔爆发请求。

  • Cooldown Period: 如果速率限制器因超出速率限制而拒绝请求,则可能存在一个冷却期,在此期间速率限制器会再次逐渐增加允许的请求速率。这是为了防止限制放宽后流量突然激增。


微服务演示

Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级,【Spring Boot2.X】,spring boot,RateLimiter,Resilience4j

我们的演示有 2 个服务,名为支付服务和支付处理器。

Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级,【Spring Boot2.X】,spring boot,RateLimiter,Resilience4j

  • 付款服务处理来自购物者的传入付款请求,并将其转发到付款处理器进行处理。
  • 支付处理器处理并发送结果。

我们将对支付服务实施速率限制,以控制传入付款请求的速率。

Payment processor

首先构建支付处理器,因为它是一个依赖服务.

为了演示的目的,将其简化为显示成功消息

POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.artisan</groupId>
    <artifactId>payment-processor</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>payment-processor</name>

    <properties>
        <java.version>17</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>


配置文件

server:
  port: 1010
spring:
  application:
    name: payment-processor

Service

package com.artisan.paymentprocessor.service;
/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
public interface PaymentProcessorService {
    String processPayment(String paymentInfo);
}
package com.artisan.paymentprocessor.service.impl;

import org.springframework.stereotype.Service;

import com.artisan.paymentprocessor.service.PaymentProcessorService;
/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
@Service
public class PaymentProcessorServiceImpl implements PaymentProcessorService {
    @Override
    public String processPayment(String paymentInfo) {
        // Simulated logic to process payment
        return "Payment processed: " + paymentInfo;
    }
}


Controller

package com.artisan.paymentprocessor.controller;

import com.artisan.paymentprocessor.service.PaymentProcessorService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import lombok.RequiredArgsConstructor;

/**
 * @author artisan
 */
@RestController
@RequestMapping("/api/v1/processor-payment")
@RequiredArgsConstructor
public class PaymentProcessorController {
    private final PaymentProcessorService paymentProcessorService;

    @PostMapping
    public String processPayment(@RequestBody String paymentInfo) {
        return paymentProcessorService.processPayment(paymentInfo);
    }
}

测试一下:

Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级,【Spring Boot2.X】,spring boot,RateLimiter,Resilience4j


Payment service

我们将配置 Rate Limiter,并通过 Actuator 监控其状态 。

POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.artisan</groupId>
    <artifactId>payment-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>payment-service</name>

    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2022.0.4</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>


Model

public interface Type {
}

@Data
public class Success implements Type {
    private final String msg;
}



@Data
public class Failure implements Type {
    private final String msg;
}

Service

如何调用外部API -------------->我们这里使用 Spring的 RestTemplate

package com.artisan.paymentservice.service;

import com.artisan.paymentservice.model.Type;

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
public interface PaymentService {
    Type submitPayment(String paymentInfo);
}

package com.artisan.paymentservice.service.impl;

import com.artisan.paymentservice.model.Failure;
import com.artisan.paymentservice.model.Success;
import com.artisan.paymentservice.model.Type;
import com.artisan.paymentservice.service.PaymentService;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import io.github.resilience4j.ratelimiter.RequestNotPermitted;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import lombok.RequiredArgsConstructor;

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
@Service
@RequiredArgsConstructor
public class PaymentServiceImpl implements PaymentService {
    private final RestTemplate restTemplate;
    private static final String SERVICE_NAME = "payment-service";
    private static final String PAYMENT_PROCESSOR_URL = "http://localhost:1010/api/v1/processor-payment";


    @Override
    @RateLimiter(name = SERVICE_NAME, fallbackMethod = "fallbackMethod")
    public Type submitPayment(String paymentInfo) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> entity = new HttpEntity<>(paymentInfo, headers);
        ResponseEntity<String> response = restTemplate.exchange(PAYMENT_PROCESSOR_URL,
                HttpMethod.POST, entity, String.class);
        Success success = new Success(response.getBody());
        return success;
    }

    private Type fallbackMethod(RequestNotPermitted requestNotPermitted) {
        return new Failure("服务降级: Payment service does not permit further calls");
    }
}

重点关注: @RateLimiter(name = SERVICE_NAME, fallbackMethod = "fallbackMethod")

需要注意这两种方法应该返回相同的数据类型, 所以对两个模型类都使用“Type”来实现。


RestConfig

package com.artisan.paymentservice.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
@Configuration
public class RestConfig {
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

Controller

package com.artisan.paymentservice.controller;

import com.artisan.paymentservice.model.Type;
import com.artisan.paymentservice.service.PaymentService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import lombok.RequiredArgsConstructor;
/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
@RestController
@RequestMapping("/api/v1/payment-service")
@RequiredArgsConstructor
public class PaymentController {
    private final PaymentService paymentService;
    @PostMapping
    public Type submitPayment(@RequestBody String paymentInfo) {
        return paymentService.submitPayment(paymentInfo);
    }
}


配置

server:
  port: 9090
spring:
  application:
    name: payment-service
management:
  endpoint:
    health:
      show-details: always
  endpoints:
    web:
      exposure:
        include: health
  health:
    ratelimiters:
      enabled: true
resilience4j:
  ratelimiter:
    instances:
      payment-service:
        limit-for-period: 5
        limit-refresh-period: 15s
        timeout-duration: 5s
        register-health-indicator: true
  • limit-for-period:一个“limit-refresh-period”期间允许的请求数
  • limit-refresh-period:指定“limit-for-period”将被重置的持续时间
  • timeout-duration:设置速率限制器允许后续请求的最大等待时间。

这段配置确保了payment-service服务的请求速率不会超过每15秒5次,同时如果请求超过5秒没有响应,则认为请求超时。此外,通过注册健康指标,可以对速率限制器的状态进行监控和管理。


验证

Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级,【Spring Boot2.X】,spring boot,RateLimiter,Resilience4j

Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级,【Spring Boot2.X】,spring boot,RateLimiter,Resilience4j


探究 Rate Limiting

确保两个服务启动成功

Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级,【Spring Boot2.X】,spring boot,RateLimiter,Resilience4j

访问 http://localhost:9090/actuator/health 查看速率限制器详细信息。

Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级,【Spring Boot2.X】,spring boot,RateLimiter,Resilience4j


请求三次 ,观察

Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级,【Spring Boot2.X】,spring boot,RateLimiter,Resilience4j

http://localhost:9090/api/v1/ payment-service 请求3次 ,然后刷新执行器链接 http://localhost:9090/actuator/health

Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级,【Spring Boot2.X】,spring boot,RateLimiter,Resilience4j

等待15秒

等待 15 秒(如果在 API 访问之前开始,时间可能会更短),然后刷新执行器链接 http://localhost:9090/actuator/health,我们将观察到允许的请求重置为 5。

Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级,【Spring Boot2.X】,spring boot,RateLimiter,Resilience4j

连续访问6次

API 访问 6 次 http://localhost:9090/api/v1/ payment-service。第 6 个请求将因超出限制而延迟 5 秒。等待期间,刷新 http://localhost:9090/actuator/health 以获取以下详细信息
Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级,【Spring Boot2.X】,spring boot,RateLimiter,Resilience4j文章来源地址https://www.toymoban.com/news/detail-802253.html

到了这里,关于Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Boot利用Kaptcha生成验证码

    我们在登录或注册某个网站的时候,会需要我们输入验证码,才能登录注册,那么如何生成验证码呢?其实,生成验证码我们可以用Java Swing在后台内存里的区域画一个出来,但是非常麻烦,所以我们选择一些现成的工具——Kaptcha,接下来就看看如何使用这个工具在内存中画

    2024年02月22日
    浏览(42)
  • Spring Boot进阶(19):探索ElasticSearch:如何利用Spring Boot轻松实现高效数据搜索与分析

            ElasticSearch是一款基于Lucene的开源搜索引擎,具有高效、可扩展、分布式的特点,可用于全文搜索、日志分析、数据挖掘等场景。Spring Boot作为目前最流行的微服务框架之一,也提供了对ElasticSearch的支持。本篇文章将介绍如何在Spring Boot项目中整合ElasticSearch,并展

    2024年02月11日
    浏览(51)
  • Spring Boot:利用JPA进行数据库的查删

    DAO 层负责数据库访问,它 封装了对数据库的访问操作 ,例如查询、插入、更新和删除等。 Service 层负责业务逻辑, Service 层位于 DAO 层之上 ,Service 层可以 调用多个 DAO 层的接口 来完成复杂的业务操作,也可以将多个 DAO 层的接口组合成一个新的接口,并将其返回给客户端

    2024年02月07日
    浏览(46)
  • 利用Spring Boot实现客户端IP地理位置获取

    在当今互联的世界中,了解客户端的地理位置对于提供个性化服务和增强用户体验至关重要。无论是根据地区偏好定制内容,还是确保符合本地法规,访问客户端IP位置都是一项宝贵的资产。如抖音评论区、用户页都会展示用户的IP属地信息。 在本文中,我们将探讨一个Spri

    2024年02月20日
    浏览(62)
  • Spring Boot进阶(63):「超详细」利用 Redis 实现高效延时队列:踩坑、优化、实践

            提到延时队列,相信各位同学并不会陌生,JDK原生提供了延时队列的使用,当然我们这里介绍的不是这种;在实际的项目中,如果我们有延时队列的场景,可以怎样去实现呢?举一个常见的例子,比如淘宝下单30分钟内,若没有支付,则自动取消订单,这该如何实现

    2024年02月07日
    浏览(44)
  • spring boot中常用的安全框架 Security框架 利用Security框架实现用户登录验证token和用户授权(接口权限控制)

    spring boot中常用的安全框架 Security 和 Shiro 框架 Security 两大核心功能 认证 和 授权 重量级 Shiro 轻量级框架 不限于web 开发 在不使用安全框架的时候 一般我们利用过滤器和 aop自己实现 权限验证 用户登录 Security 实现逻辑 输入用户名和密码 提交 把提交用户名和密码封装对象

    2024年02月06日
    浏览(55)
  • 【Spring Boot学习】Spring Boot的创建,第一个Spring Boot页面.

    前言: 大家好,我是 良辰丫 ,前面几篇文章,我们系统的学习了Spring框架,今天开始,我们就要学习更高级的SpringBoot框架了,不要着急哦,我们一起畅游SpringBoot框架的世界.💌💌💌 🧑个人主页:良辰针不戳 📖所属专栏:javaEE进阶篇之框架学习 🍎励志语句:生活也许会让我们遍体

    2024年02月08日
    浏览(54)
  • Spring Boot——Spring Boot启动原理

    2.1.1Spring Boot入口 2.1.2初始化SpringApplication 准备阶段,在程序运行之前初始化一些属性,用于在后序启动应用程序过程中。 2.1.2.1判断当前应用程序类型 2.1.2.2设置应用程序的所有初始化器(initializers) 上面这段代码主要是通过加载 “spring.factories” 配置文件中指定类型的工厂名

    2024年02月15日
    浏览(48)
  • 【Spring Boot 】Spring Boot 统一功能处理

    🎉🎉🎉 点进来你就是我的人了 博主主页: 🙈🙈🙈 戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔 🤺🤺🤺 目录 前言 1. Spring 拦截器 1.1 自定义拦截器 1.2 将自定义拦截器加入到系统配置中 1.3 拦截器实现原理 统一访问前缀添加 (扩展) 2. 统一异常的处理 (@Co

    2024年02月09日
    浏览(38)
  • 【Spring Boot】Spring Boot集成RabbitMQ

    Spring Boot提供了`spring-boot-starter-amqp`组件,只需要简单地配置即可与Spring Boot无缝集成。下面通过示例演示集成RabbitMQ实现消息的接收和发送。 步骤01 配置pom包。 创建Spring Boot项目并在pom.xml文件中添加spring-bootstarter-amqp等相关组件依赖: 在上面的示例中,引入Spring Boot自带的

    2024年02月06日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包