SpringCloud Netflix集成Sentinel限流

2024-05-06 20:32

本文主要是介绍SpringCloud Netflix集成Sentinel限流,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、摘要

1.1、sentinel介绍

1.2、sentinel特征

二、学习目标

三、实施步骤

3.1、新建项目product-server。

        3.1.1、New->File->Project->Spring Initializr

        3.1.2、选择依赖的jar(product-server选择lombok、spring-boot-starter-web、spring-cloud-starter-netflix-eureka-client):

        3.1.3、知识拓展

3.2、同样的步骤,新建order-server服务模块;其中order-server需要依赖openFeign。

3.3、实现产品查询接口

3.4、order-server使用feign调用product-server查询接口.

3.5、启动product-server和order-server服务。

3.6、下载sentinel并启动。

3.7、下载jemeter压测,下载地址:Apache JMeter - Apache JMeter™

3.8、在sentinel面板设置限流策略

3.9、QPS限流——我们设置query/{id}接口qps为8个请求/秒。

3.10、并发线程数限流——设置成每秒5个请求。

四、sentinel限流原理

4.1、sentinel如何拦截feign接口

4.2、四种限流原理

计数器限流算法

滑动窗口限流算法

漏桶限流算法

令牌桶限流算法

五、参考文章


一、摘要

1.1、sentinel介绍

Sentinel是阿里开源的项目,提供了流量控制、熔断降级、系统负载保护等多个维度来保障服务之间的稳定性。官网:Home · alibaba/Sentinel Wiki · GitHub

2012年,Sentinel诞生于阿里巴巴,其主要目标是流量控制。2013-2017年,Sentinel迅速发展,并成为阿里巴巴所有微服务的基本组成部分。 它已在6000多个应用程序中使用,涵盖了几乎所有核心电子商务场景。2018年,Sentinel演变为一个开源项目。2020年,Sentinel Golang发布。

1.2、sentinel特征

丰富的应用场景 :Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即
突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
完备的实时监控 :Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机
器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
广泛的开源生态 :Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring
Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入Sentinel。

完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

Sentinel的生态圈

二、学习目标

2.1、完成springcloud netflix框架搭建

2.2、完成springCloud与Sentinel的集成

2.3、使用Jemeter测试限流功能

2.4、总结Sentinel限流原理

3.5、服务有:一个集群的eureka服务(部署两个)、一个产品服务product-server、一个订单服务order-server、还有sentinel服务。其中eureka服务部署请看Eureka Server集群服务搭建_DayDayUp的博客-CSDN博客。

3.6、各框架版本

框架版本注意
spring-boot2.5.5版本如果不兼容会出现意想不到的问题。
spring-cloud-starter-alibaba-sentinel2021.1
spring-cloud2020.0.4

三、实施步骤

3.1、新建项目product-server。

        3.1.1、New->File->Project->Spring Initializr

 输入项目名及选择配置。

        3.1.2、选择依赖的jar(product-server选择lombok、spring-boot-starter-web、spring-cloud-starter-netflix-eureka-client):

        3.1.3、知识拓展

  1. Developer tools->勾选Lombok, 作用:Lombok 提供了一些注解来帮助我们简化消除一些必须有但显得臃肿的 java 代码,如 gettingsetting、toString、equals等.
  2. Web->勾选Spring web,作用:Spring-boot-starter-web->提供servlet容器——tomcat、webmvc(restFul api)、spring核心jar、spring的bean装载jar、log日志jar等依赖(没有它,无法启动项目).
  3. Spring Cloud Discovery->勾选Eureka Discovery client: 注册中心eureka的客户端的依赖jar.
  4. Spring Cloud Routing->勾选OpenFeign,作用:Feign接口依赖的jar(feign自动依赖ribbon和hystrix相关jar).

3.2、同样的步骤,新建order-server服务模块;其中order-server需要依赖openFeign。

3.3、实现产品查询接口

        3.3.1、新建基本类请求对象ProductResponse和响应对象Response。

package com.example.product.response;import lombok.AllArgsConstructor;
import lombok.Data;import java.math.BigDecimal;@Data
@AllArgsConstructor
public class ProductResponse {private Integer id;private String name;private Integer num;private BigDecimal price;}
package com.example.product.response;import lombok.Getter;
import lombok.Setter;@Setter
@Getter
public class Response<T>{private Integer errorCode;private String errorMsg;private T data;public Response(Integer errorCode, String errorMsg, T data) {this.errorCode = errorCode;this.errorMsg = errorMsg;this.data = data;}public static <T> Response<T> success(T data){return new Response<>(null, null, data);}}

           3.3.2、product-server的application.yml配置。

spring:application:name: product-server
server:port: 8081servlet:context-path: /product
#配置注册eureka地址(带用户名和密码)
eureka:client:serviceUrl:defaultZone: http://eureka:eureka@localhost:8671/eureka,http://eureka:eureka@localhost:8672/eureka

        3.3.3、 product-server的pom.xml配置。

<?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>2.5.5</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>product-server</artifactId><version>0.0.1-SNAPSHOT</version><name>product-server</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version><spring-cloud.version>2020.0.4</spring-cloud.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</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>

        3.3.4、产品查询接口简单实现

package com.example.product.controller;import com.example.product.response.ProductResponse;
import com.example.product.response.Response;
import com.example.product.service.ProductService;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;@RestController
public class ProductController {@Resourceprivate ProductService productService;@RequestMapping(value = "/select/{id}")public Response<ProductResponse> selectById(@PathVariable Integer id){return Response.success(productService.queryById(id));}}
package com.example.product.service;import com.example.product.response.ProductResponse;
import org.springframework.stereotype.Service;import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;@Service
public class ProductService {private static Map<Integer, ProductResponse> productHashMap = new HashMap<>();static {productHashMap.put(1, new ProductResponse(1, "冰箱", 5, new BigDecimal(20000)));productHashMap.put(2, new ProductResponse(2, "空调", 9, new BigDecimal(30000)));productHashMap.put(3, new ProductResponse(3, "洗衣机", 8, new BigDecimal(5000)));}public ProductResponse queryById(Integer id){return productHashMap.get(id);}
}

3.4、order-server使用feign调用product-server查询接口.

        3.4.1、新建基本类请求对象ProductResponse和响应对象Response(可以做成jar依赖order)。

package com.example.order.response;import lombok.AllArgsConstructor;
import lombok.Data;import java.math.BigDecimal;@Data
@AllArgsConstructor
public class ProductResponse{private Integer id;private String name;private Integer num;private BigDecimal price;}
package com.example.order.response;import lombok.Getter;
import lombok.Setter;@Setter
@Getter
public class Response<T>{private Integer errorCode;private String errorMsg;private T data;public Response(Integer errorCode, String errorMsg, T data) {this.errorCode = errorCode;this.errorMsg = errorMsg;this.data = data;}public static <T> Response<T> success(T data){return new Response<>(null, null, data);}}

        3.4.2、feign接口实现

package com.example.order.feign;import com.example.order.response.ProductResponse;
import com.example.order.response.Response;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(name = "product-server", path = "/product", fallbackFactory = ProductMicroServerFallbackFactory.class)
public interface ProductMicroServer {@GetMapping(value = "/select/{id}")Response<ProductResponse> selectById(@PathVariable Integer id);
}
package com.example.order.feign;import com.example.order.response.ProductResponse;
import com.example.order.response.Response;
import org.springframework.stereotype.Service;import java.math.BigDecimal;@Service
public class ProductMicroServerFallback implements ProductMicroServer{@Overridepublic Response<ProductResponse> selectById(Integer id) {return Response.success(new ProductResponse(0, "棒棒糖(兜底商品)", 1, new BigDecimal(0.5)));}
}
package com.example.order.feign;import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;import javax.annotation.Resource;@Slf4j
@Service
public class ProductMicroServerFallbackFactory implements FallbackFactory<ProductMicroServer> {@Resourceprivate ProductMicroServerFallback productMicroServerFallback;@Overridepublic ProductMicroServer create(Throwable cause) {log.error("ProductMicroServerFallback->selectById(Integer id) exception:", cause);return productMicroServerFallback;}
}

 启动类添加激活feign接口注解并指定扫描包。

package com.example.order;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;@EnableFeignClients(value = "com.example.order.feign")
@SpringBootApplication
public class OrderServerApplication {public static void main(String[] args) {SpringApplication.run(OrderServerApplication.class, args);}}

    3.4.3、application.yml和pom.xml配置

        application.yml添加sentinel配置及支持。

spring:application:name: order-servercloud:sentinel:transport:#指定控制台交流的端口,随意指定一个未使用的端口即可port: 8719#sentinel dashboard 地址dashboard: localhost:8080
server:port: 8082servlet:context-path: /order#Sentinel 对 Feign 的支持
feign:sentinel:enabled: true#配置注册eureka地址(带用户名和密码)
eureka:client:serviceUrl:defaultZone: http://eureka:eureka@localhost:8671/eureka

 pom.xml添加sentinel的jar依赖。

<?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>2.5.4</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>order-server</artifactId><version>0.0.1-SNAPSHOT</version><name>order-server</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version><spring-cloud.version>2020.0.4</spring-cloud.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</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><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId><version>2021.1</version></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>

3.5、启动product-server和order-server服务。

        3.5.1、启动后并查看是否注册到eureka。

         3.5.2、访问order-server查询接口,检测feign服务是调用成功:http://localhost:8082/order/query/1

 

3.6、下载sentinel并启动。

        3.6.1、下载地址:控制台 · alibaba/Sentinel Wiki · GitHub

        3.6.2、启动sentinel

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

启动日志:

 浏览器输入sentinel启动时指定端口号8080,http://localhost:8080, 如下(默认登录密码为sentinel)。

成功访问一次product查询商品接口后再次刷新sentinel面板,出现order-server表示集成生效。

3.7、下载jemeter压测,下载地址:Apache JMeter - Apache JMeter™

        3.7.1、运行bin\jemeter.bat文件启动jemeter(可以选择中文操作界面)。

         3.7.2、添加线程组测试。

        3.7.3、添加http请求。

        3.7.4、添加结果数查看。

         3.7.5、添加http接口配置

        3.7.6、设置线程并发数。

3.8、在sentinel面板设置限流策略

        3.8.1、在sentinel面板找到指定的接口并设置限流策略。

3.9、QPS限流——我们设置query/{id}接口qps为8个请求/秒。

 启动jemeter压测。  

 启动后查看结果数,发现sentinel的qps限流生效。

 查看sentinel的限流数据及监控。

3.10、并发线程数限流——设置成每秒5个请求。

sentinel并发线程数限流设置。

 jemeter压测线程数设置成每秒300个线程(我电脑是4核)。

 压测结果:

 

四、sentinel限流原理

4.1、sentinel如何拦截feign接口

sentinel跟 hystrix 一样实现自定义的java.lang.reflect.InvocationHandler 接口 SentinelInvocationHandler 用来处理方法的调用。

4.2、四种限流原理

  • 计数器限流算法

        计数器是限流中最简单的,规定为:在指定周期内累加访问次数,当访问次数达到设定的阈值时,出发限流策略,当进入下一个时间周期时会将访问次数清零。

        优点:实现简单
        临界问题:如图所示,当在8-10秒和10-12秒内分别并发500,虽然没有超过阈值,但如果算8-12秒,则并发数高达1000,已经超过了原先定义的10秒内不超过500的并发量。

  • 滑动窗口限流算法

        为了避免计数器中的临界问题,让限制更加平滑,将固定窗口中分割出多个小时间窗口,分别在每个小的时间窗口中记录访问次数,然后根据时间将窗口往前滑动并删除过期的小时间窗口。

        优点:实现相对简单,且没有计数器算法的临界问题
        缺点:无法应对短时间高并发(突刺现象)

  • 漏桶限流算法

        漏桶限流算法的核心就是, 不管上面的水流速度有多块, 漏桶水滴的流出速度始终保持不变

        实际应用:消息中间件采用的就是漏桶限流的思想

        主要作用:

  1. 控制数据注入网络的速度
  2. 平滑网络上的突发流量(类似于电容整流)

        不足:无法应对突发的并发流量,因为流出速率一直都是恒定的

  • 令牌桶限流算法

        令牌桶是网络流量整形(Traffic Shaping)速率限制(Rate Limiting)中最常使用的一种算法。速度恒定、令牌桶大小固定,如果令牌桶被填满,则会丢弃生成的令牌,如果桶内没有令牌则出现限流策略。

        优点:可以像漏桶那样匀速,也可以像计数器那样突发处理。

五、参考文章

1、控制台 · alibaba/Sentinel Wiki · GitHub

2、常用的四种限流算法图解_July的博客-CSDN博客

这篇关于SpringCloud Netflix集成Sentinel限流的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/965301

相关文章

SpringBoot结合Docker进行容器化处理指南

《SpringBoot结合Docker进行容器化处理指南》在当今快速发展的软件工程领域,SpringBoot和Docker已经成为现代Java开发者的必备工具,本文将深入讲解如何将一个SpringBo... 目录前言一、为什么选择 Spring Bootjavascript + docker1. 快速部署与

Spring Boot spring-boot-maven-plugin 参数配置详解(最新推荐)

《SpringBootspring-boot-maven-plugin参数配置详解(最新推荐)》文章介绍了SpringBootMaven插件的5个核心目标(repackage、run、start... 目录一 spring-boot-maven-plugin 插件的5个Goals二 应用场景1 重新打包应用

SpringBoot+EasyExcel实现自定义复杂样式导入导出

《SpringBoot+EasyExcel实现自定义复杂样式导入导出》这篇文章主要为大家详细介绍了SpringBoot如何结果EasyExcel实现自定义复杂样式导入导出功能,文中的示例代码讲解详细,... 目录安装处理自定义导出复杂场景1、列不固定,动态列2、动态下拉3、自定义锁定行/列,添加密码4、合并

Spring Boot集成Druid实现数据源管理与监控的详细步骤

《SpringBoot集成Druid实现数据源管理与监控的详细步骤》本文介绍如何在SpringBoot项目中集成Druid数据库连接池,包括环境搭建、Maven依赖配置、SpringBoot配置文件... 目录1. 引言1.1 环境准备1.2 Druid介绍2. 配置Druid连接池3. 查看Druid监控

Java中读取YAML文件配置信息常见问题及解决方法

《Java中读取YAML文件配置信息常见问题及解决方法》:本文主要介绍Java中读取YAML文件配置信息常见问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录1 使用Spring Boot的@ConfigurationProperties2. 使用@Valu

创建Java keystore文件的完整指南及详细步骤

《创建Javakeystore文件的完整指南及详细步骤》本文详解Java中keystore的创建与配置,涵盖私钥管理、自签名与CA证书生成、SSL/TLS应用,强调安全存储及验证机制,确保通信加密和... 目录1. 秘密键(私钥)的理解与管理私钥的定义与重要性私钥的管理策略私钥的生成与存储2. 证书的创建与

浅析Spring如何控制Bean的加载顺序

《浅析Spring如何控制Bean的加载顺序》在大多数情况下,我们不需要手动控制Bean的加载顺序,因为Spring的IoC容器足够智能,但在某些特殊场景下,这种隐式的依赖关系可能不存在,下面我们就来... 目录核心原则:依赖驱动加载手动控制 Bean 加载顺序的方法方法 1:使用@DependsOn(最直

SpringBoot中如何使用Assert进行断言校验

《SpringBoot中如何使用Assert进行断言校验》Java提供了内置的assert机制,而Spring框架也提供了更强大的Assert工具类来帮助开发者进行参数校验和状态检查,下... 目录前言一、Java 原生assert简介1.1 使用方式1.2 示例代码1.3 优缺点分析二、Spring Fr

java使用protobuf-maven-plugin的插件编译proto文件详解

《java使用protobuf-maven-plugin的插件编译proto文件详解》:本文主要介绍java使用protobuf-maven-plugin的插件编译proto文件,具有很好的参考价... 目录protobuf文件作为数据传输和存储的协议主要介绍在Java使用maven编译proto文件的插件

Java中的数组与集合基本用法详解

《Java中的数组与集合基本用法详解》本文介绍了Java数组和集合框架的基础知识,数组部分涵盖了一维、二维及多维数组的声明、初始化、访问与遍历方法,以及Arrays类的常用操作,对Java数组与集合相... 目录一、Java数组基础1.1 数组结构概述1.2 一维数组1.2.1 声明与初始化1.2.2 访问