本文主要是介绍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-boot | 2.5.5 | 版本如果不兼容会出现意想不到的问题。 |
spring-cloud-starter-alibaba-sentinel | 2021.1 | |
spring-cloud | 2020.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、知识拓展
- Developer tools->勾选Lombok, 作用:Lombok 提供了一些注解来帮助我们简化消除一些必须有但显得臃肿的 java 代码,如
getting
、setting、toString、equals等.
- Web->勾选Spring web,作用:Spring-boot-starter-web->提供servlet容器——tomcat、webmvc(restFul api)、spring核心jar、spring的bean装载jar、log日志jar等依赖(没有它,无法启动项目).
- Spring Cloud Discovery->勾选Eureka Discovery client: 注册中心eureka的客户端的依赖jar.
- 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的并发量。
-
滑动窗口限流算法
为了避免计数器中的临界问题,让限制更加平滑,将固定窗口中分割出多个小时间窗口,分别在每个小的时间窗口中记录访问次数,然后根据时间将窗口往前滑动并删除过期的小时间窗口。
优点:实现相对简单,且没有计数器算法的临界问题
缺点:无法应对短时间高并发(突刺现象)
-
漏桶限流算法
漏桶限流算法的核心就是, 不管上面的水流速度有多块, 漏桶水滴的流出速度始终保持不变。
实际应用:消息中间件采用的就是漏桶限流的思想
主要作用:
- 控制数据注入网络的速度
- 平滑网络上的突发流量(类似于电容整流)
不足:无法应对突发的并发流量,因为流出速率一直都是恒定的
-
令牌桶限流算法
令牌桶是网络流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一种算法。速度恒定、令牌桶大小固定,如果令牌桶被填满,则会丢弃生成的令牌,如果桶内没有令牌则出现限流策略。
优点:可以像漏桶那样匀速,也可以像计数器那样突发处理。
五、参考文章
1、控制台 · alibaba/Sentinel Wiki · GitHub
2、常用的四种限流算法图解_July的博客-CSDN博客
这篇关于SpringCloud Netflix集成Sentinel限流的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!