Alibaba SpringCloud集成Nacos、Sentinel实现服务治理-17

关于服务治理

总体而言,限流和降级作为微服务架构中的重要机制,尽管在实现上可能有多种方式,但它们都着眼于保护服务提供者和消费者,在面对异常情况时确保系统稳定运行。限流关注于保护服务提供者,控制请求流量;而降级则关注于服务消费者,确保在服务不可用或异常情况下提供基本的功能。

  • 限流是一种针对服务提供者的策略,用于控制对特定服务接口或服务实例的访问量。其目的在于保护服务提供者免受过大请求流量的影响,确保服务稳定性。限流措施可以在服务提供者或服务消费者两端实现,通过设定流量阈值并采取排队、拒绝请求或返回错误信息等方式来控制流量,从而保护服务
  • 降级是针对服务消费者的应对策略,在服务出现异常或限流时,通过对服务调用进行降级处理,确保消费者端能够在异常情况下正常工作。降级的目的在于转变为弱依赖状态,使系统能够在服务不可用时提供基本的功能或数据。这种策略可以在服务消费者端实施,通过返回默认值、提供备用数据或简化功能等方式来保证系统的可用性。
  • 断路器:一个自动中断,恢复的功能,实际场景中用的不多。

在这里插入图片描述

1、Sentinel.dashbod 图形化界面安装

  1. 下载地址:https://github.com/alibaba/Sentinel/releases

  2. 启动:下面命令中的端口号可以根据需要修改

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

在这里插入图片描述

  1. 通过 http://localhost:9999 访问图形化界面,密码默认为sentinel。
    在这里插入图片描述

2、alibaba-sentinel-server

服务端主要是限流配置

在这里插入图片描述

pom.xml

在本示例中,主要用到了三个主要组件,nacos服务发现,sentinel,以及nacos配置中心(做为sentinel规则的存储,否则当服务重启后规则就会丢失)

        <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-sentinel-datasource</artifactId></dependency><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId></dependency>

application.properties配置

这里配置比较多,可参考上面jar包引用说明查看,主要是配置了Nacos和Sentinel控制台的地址。

spring.profiles.active = dev
spring.application.name=AlibabaSpringbootSentinelServer
server.port=19504management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=alwaysspring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.fail-fast=true
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacosspring.cloud.sentinel.transport.dashboard=localhost:9999
spring.cloud.sentinel.transport.port=8719 #与sentinel通信的转用端口
spring.cloud.sentinel.eager=true
spring.cloud.sentinel.web-context-unify=truespring.cloud.sentinel.datasource.ds2.nacos.server-addr=127.0.0.1:8848
spring.cloud.sentinel.datasource.ds2.nacos.username=nacos
spring.cloud.sentinel.datasource.ds2.nacos.password=nacos
#需要nocas中配合一个名为 AlibabaSpringbootSentinelServer-sentinel 的文件,这里不需要加-dev啥的,因为这处指定死了名称
spring.cloud.sentinel.datasource.ds2.nacos.dataId=${spring.application.name}-sentinel
spring.cloud.sentinel.datasource.ds2.nacos.groupId=DEFAULT_GROUP
spring.cloud.sentinel.datasource.ds2.nacos.data-type=json
#type=flow 以 JSON 格式返回现有的限流规则,degrade 返回现有生效的降级规则列表,system 则返回系统保护规则。
spring.cloud.sentinel.datasource.ds2.nacos.rule-type=flow

SpringbootApplication启动类

主要是添加了@EnableDiscoveryClient注解,如果不需要服务发现可以去掉。

@Slf4j
@SpringBootApplication(scanBasePackages = {"com.korgs",  "cn.hutool.extra.spring"})
@Configuration
@EnableConfigurationProperties
@ServletComponentScan
@RestController
@EnableDiscoveryClient
public class AlibabaSpringbootSentinelServerApplication {@Value("${server.port}")private String serverPort;public static void main(String[] args) {SpringApplication.run(AlibabaSpringbootSentinelServerApplication.class, args);}@GetMapping("/helloworld/{uuid}")public BaseResponse<String> helloWorld(@PathVariable String uuid){String str = LogGenerator.trackLog()+ " uuid=" + uuid + " I am busy to handle this request."+ " serverPort=" + serverPort;log.info( str );return BaseResponse.success(str);}
}

Controller测试类实现

给普通的uri上添加@SentinelResource(value = "userInfo", blockHandler = "exceptionHandler"),这个注解在文章最后会详细解释。

@Slf4j
@RestController
@RequestMapping("/api/user")
public class UserController {@Value("${server.port}")private String serverPort;@SentinelResource(value = "userInfo", blockHandler = "exceptionHandler")@GetMapping("/userinfo/{uuid}")public BaseResponse<String> userInfo(@PathVariable String uuid){String str = LogGenerator.trackLog()+ " uuid=" + uuid + " I am busy to handle userInfo."+ " serverPort=" + serverPort;log.info( str );return BaseResponse.success(str);}@SentinelResource(value = "userOrder")@GetMapping("/userorderlist/{uuid}")public ListResponse<List<String>> userOrder(@PathVariable String uuid){String str = LogGenerator.trackLog()+ " uuid=" + uuid + " I am busy to handle userInfo."+ " serverPort=" + serverPort;log.info( str );List<String> userOrders = new ArrayList<>();userOrders.add("order1");userOrders.add("order2");userOrders.add("order3");userOrders.add("order4");return ListResponse.success(userOrders);}@SentinelResource(value = "userStatus")@GetMapping("/userstatus/{uuid}")public BaseResponse<String> userStatus(@PathVariable String uuid){String str = LogGenerator.trackLog()+ " uuid=" + uuid + " I am busy to handle userStatus."+ " serverPort=" + serverPort;return BaseResponse.success(str);}public BaseResponse<String> exceptionHandler(long s, BlockException ex) {ex.printStackTrace();return BaseResponse.error(s+"");}
}

3、Sentinel配置限流规则

限流规则配置

  • 配置之前要先启动 alibaba-sentinel-server 服务,然后登陆sentinel客户端,就可以发现此服务,然后在流控规则中新增规则即可。
    在这里插入图片描述
  • 配置规则,规则可以注解的value或uri来配置。
    比如下面这个配置
    @SentinelResource(value = "userInfo", blockHandler = "exceptionHandler")@GetMapping("/userinfo/{uuid}")public BaseResponse<String> userInfo(@PathVariable String uuid){}

资源名可以配置成userInfo,也可以配置成/userinfo/{uuid},一般建议配置成@SentinelResource注解的值,这样也起到了一个解耦的作用。
在这里插入图片描述

Controller限流功能测试

因为上面规则的阈值配置成了1,所以我们快速访问上述的userinfo地址。会发现uri返回时好时坏。在浏览器中打开http://localhost:19504/swagger-ui/index.html,如下:
在这里插入图片描述
上述红框就是限流后的返回结果。


4、alibaba-sentinel-client

客户端主要是降级配置,这个示例中添加了ribbon和RestTemplate支持,前者用于负载,后者用于远程访问。
在这里插入图片描述

pom.xml

    <dependencies><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency></dependencies>

application.properties配置

spring.profiles.active = dev
spring.application.name=AlibabaSpringbootSentinelClient
server.port=19505management.endpoints.web.exposure.include=*spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.fail-fast=true
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos#自定义配置服务端
service-url.nacos-service = http://AlibabaSpringbootSentinelServer

SpringbootApplication启动类

主要是添加了@EnableDiscoveryClient注解,如果不需要服务发现可以去掉。

@Slf4j
@SpringBootApplication(scanBasePackages = {"com.korgs",  "cn.hutool.extra.spring"})
@Configuration
@EnableConfigurationProperties
@ServletComponentScan
@RestController
@EnableDiscoveryClient
public class AlibabaSpringbootSentinelClientApplication {public static void main(String[] args) {SpringApplication.run(AlibabaSpringbootSentinelClientApplication.class, args);}@GetMapping("/helloworld")public String helloWorld(){log.info( LogGenerator.trackLog()+ "msg=" + "I am busy to handle this request.");return "hello world";}
}

配置RestTemplate

添加@SentinelRestTemplate,配置全局降级响应

@Configuration
public class RibbonConfig {@Bean@LoadBalanced@SentinelRestTemplatepublic RestTemplate restTemplate() {return new RestTemplate();}
}

Controller测试类实现

配置自定义降级响应,即被服务端限流后的响应

@Slf4j
@RestController
@RequestMapping("/api/load")
public class LoadUserController {@Autowiredprivate RestTemplate restTemplate;@Value("${service-url.nacos-service}")private String ribbonServiceUrl;/*熔断,降级,这里主要用到的是fallback标签*/@GetMapping("/fusing")@SentinelResource(value = "fusing", fallback = "handleFallback")public BaseResponse<String> fusing(String uuid){String result =  restTemplate.getForObject(ribbonServiceUrl + "/api/user/userinfo/{1}", String.class, uuid);return BaseResponse.success(result);}public BaseResponse<String> handleFallback(String uuid, Throwable e) {log.error("handleFallback2 id:{},throwable class:{}", uuid, e.getClass());return BaseResponse.error("服务降级返回");}
}

Controller被限流后的降级测试

  • 先启动 alibaba-sentinel-server
  • 再启动 alibaba-sentinel-client
  • 打开 http://localhost:19505/swagger-ui
    在这里插入图片描述
    当快速访问时就会发现,返回结果变成了自定义的描述了。

5、Sentinel详细使用说明

Sentinel注解

@SentinelRestTemplate注解

此注解的属性支持限流(blockHandler, blockHandlerClass)和降级(fallback, fallbackClass)的处理。下面的示例是演示调用服务时时支持的限流。

即在消费者一端实现的限流配置,但目的也是为了保护服务提供者,一般不太常用,还是在提供者端配置为好。在消费端限流(也称降级)是指在服务提供者发生异常后,客户端的的处理逻辑

//配置全局限流异常
@Bean
@SentinelRestTemplate(blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class)
public RestTemplate restTemplate() {return new RestTemplate();
}

@SentinelRestTemplate注解 中 blockHandler 或 fallback 属性对应的方法必须是对应 blockHandlerClass 或 fallbackClass 属性中的静态方法。
该方法的参数跟返回值跟 org.springframework.http.client.ClientHttpRequestInterceptor#interceptor 方法一致,其中参数多出了一个 BlockException 参数用于获取 Sentinel 捕获的异常。

比如上述 @SentinelRestTemplate 注解中 ExceptionUtil 的 handleException 属性对应的方法声明如下:

public class ExceptionUtil {public static ClientHttpResponse handleException(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException exception) {}public static SentinelClientHttpResponse handleException(HttpRequest request,byte[] body, ClientHttpRequestExecution execution, BlockException ex) {System.out.println("Oops: " + ex.getClass().getCanonicalName());return new SentinelClientHttpResponse("custom block info");}
}

当使用 RestTemplate 调用被 Sentinel 熔断后,会返回 RestTemplate request block by sentinel 信息,或者也可以编写对应的方法自行处理返回信息。这里提供了 SentinelClientHttpResponse 用于构造返回信息。

@SentinelResource 注解

public class TestService {// 原函数@SentinelResource(value = "hello", blockHandler = "exceptionHandler", fallback = "helloFallback")public String hello(long s) {return String.format("Hello at %d", s);}// Fallback 函数,函数签名与原函数一致或加一个 Throwable 类型的参数.public String helloFallback(long s) {return String.format("Halooooo %d", s);}// Block 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.public String exceptionHandler(long s, BlockException ex) {ex.printStackTrace();return "Oops, error occurred at " + s;}// 这里单独演示 blockHandlerClass 的配置.// 对应的 `handleException` 函数需要位于 `ExceptionUtil` 类中,并且必须为 public static 函数.@SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})public void test() {System.out.println("Test");}
}
  • value:资源名称,必需项(不能为空)
  • entryType:entry 类型,可选项(默认为 EntryType.OUT)
  • blockHandler / blockHandlerClass(限流处理): blockHandler 对应处理 BlockException 的函数名称,可选项。blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • fallback / fallbackClass(异常处理):fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:
    • 返回值类型必须与原函数返回值类型一致;
    • 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
    • fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • defaultFallback(since 1.6.0):默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求:
    • 返回值类型必须与原函数返回值类型一致;
    • 方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
    • defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

配置全局异常处理

Sentinel内置的 URL 限流触发后默认处理逻辑是,直接返回 “Blocked by Sentinel (flow limiting)”。 如果需要自定义处理逻辑,实现的方式如下:

public class CustomUrlBlockHandler implements UrlBlockHandler {@Overridepublic void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {// todo add your logic}
}WebCallbackManager.setUrlBlockHandler(new CustomUrlBlockHandler());

Sentinel中配置限流规则

可以sentinel图形化界面中配置限流规则,可以用资源名,也可以添加相对的url路径,比如下面例子,在资源名对话框中可以配置userInfo 或 /api/user/userinfo

@RestController("/api/user")
public class UserController{@SentinelResource(value = "userInfo", blockHandler = "exceptionHandler")@GetMapping("/userinfo")public BaseResponse<String> userInfo(String uuid){String str = LogGenerator.trackLog()+ " uuid=" + uuid + " I am busy to handle userInfo."+ " serverPort=" + serverPort;log.info( str );return BaseResponse.success(str);}
}

给sentinel提供 ReadableDataSource 存储支持

默认情况下,当我们在Sentinel控制台中配置规则时,控制台推送规则方式是通过API将规则推送至客户端并直接更新到内存中。一旦我们重启应用,规则将消失。

Sentinel starter 整合了目前存在的几类 ReadableDataSource。只需要在配置文件中进行相关配置,即可在 Spring 容器中自动注册 DataSource。 下面我们介绍下如何将配置规则进行持久化,以存储到Nacos为例。

spring.cloud.sentinel.datasource.ds2.nacos.server-addr=127.0.0.1:8848
spring.cloud.sentinel.datasource.ds2.nacos.username=nacos
spring.cloud.sentinel.datasource.ds2.nacos.password=nacos#需要nocas中配合一个名为 AlibabaSpringbootSentinelServer-sentinel 的文件,这里不需要加-dev啥的,因为这处指定死了名称
spring.cloud.sentinel.datasource.ds2.nacos.dataId=${spring.application.name}-sentinel
spring.cloud.sentinel.datasource.ds2.nacos.groupId=DEFAULT_GROUP
spring.cloud.sentinel.datasource.ds2.nacos.data-type=json#type=flow 以 JSON 格式返回现有的限流规则,degrade 返回现有生效的降级规则列表,system 则返回系统保护规则。
spring.cloud.sentinel.datasource.ds2.nacos.rule-type=flow

然后在nacos中配置一外名为AlibabaSpringbootSentinelServer-sentinel的文件,这样就会在sentinel中存储了。文件内容如下:

[{"resource": "userInfo", //资源名称"limitApp": "default", //来源应用"grade": 1,   //阈值类型,0表示线程数,1表示QPS"count": 1,    //单机阈值"strategy": 0,  //流控模式,0表示直接,1表示关联,2表示链路"controlBehavior": 0,  //流控效果,0表示快速失败,1表示Warm Up,2表示排队等待"clusterMode": false  //是否集群}
]

6、与openFeign配合实现降级

  • alibaba-sentinel-openFeign-client:19508

此服务和上面的是alibaba-sentinel-client功能一样,只不过把ribbon换成了openFiegn实现,测试方法也完全一样,不详细说了。

但在业务实现中建议使用openFiegn。

在这里插入图片描述

源码下载

涉及模块:

  • alibaba-sentinel-server:19501,服务端
  • alibaba-sentinel-client : 19506, ribbon实现的客户端
  • alibaba-sentinel-openFeign-client: 19508,openFeign实现的客户端

源码下载:

  • 基础框架源码下载
  • Alibaba SpringCloud集成Nacos、Sentinel实现服务治理

源码运行方法:

  • 模块详细功能说明和运行测试方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/700260.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI助力内容创作:让效率与质量齐飞

简述&#xff1a; 本文介绍了AI如何帮助创作者在保持内容质量的同时&#xff0c;大幅度提升生产效率的一些方法&#xff0c;希想 对大家有帮助。 一、自动化内容生成 1. 文本内容生成 使用GPT等模型&#xff1a;利用如GPT-3或GPT-4等大型语言模型&#xff0c;可以直接输入关…

凸优化理论学习三|凸优化问题(一)

系列文章目录 凸优化理论学习一|最优化及凸集的基本概念 凸优化理论学习二|凸函数及其相关概念 文章目录 系列文章目录一、优化问题&#xff08;一&#xff09;标准形式的优化问题&#xff08;二&#xff09;可行点和最优点&#xff08;三&#xff09;局部最优点&#xff08;四…

【java-数据结构15-模拟实现栈的方法】

上篇文章中&#xff0c;我们已经手动实现了栈&#xff0c;下面&#xff0c;我们将继续手动实现栈的方法~ 1.在栈中存放元素 1.定义一个usedsize&#xff0c;用来临时存放下标 2.当存放一个元素后&#xff0c;下标加一 3.不要忘记判满 如图 代码如下 判满方法 public boolea…

BLDC电机基础知识

1、电机工作原理 电机输入的是电能输出机械能&#xff0c;即电机是一种将电能转换为机械能的装置。电机利用磁场的同名磁极互相排斥以及电磁场原理完成电能与机械能的转换。 由物理电磁场理论知识我们知道&#xff0c;磁铁周围存在磁场&#xff0c;同时运动的电荷或通电导线周…

【Cesium解读】Cesium中primitive/entity贴地

官方案例 Cesium Sandcastle Cesium Sandcastle scene.globe.depthTestAgainstTerrain true; True if primitives such as billboards, polylines, labels, etc. should be depth-tested against the terrain surface, or false if such primitives should always be draw…

C语言笔记15

指针2 1.数组名的理解 int arr[ 10 ] { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }; int *p &arr[ 0 ];17391692786 arr是数组名&#xff0c;数组名是首元素地址&#xff0c;&arr[0]就是取出首元素的地址放在指针变量p中。 #include <stdio.h> int main()…

Oracle 临时表空间的管理

Oracle 临时表空间的管理 临时表空间的处理 1.创建一个新的temporary tablespace; create temporary tablespace tp tempfile ...... size 10m autoextend on; 2.改变数据库的默认临时表空间 alter database default temporary tablespace tp; 3。drop tablespace temp; …

Python数据分析常用模块的介绍与使用

Python数据分析模块 前言一、Numpy模块Numpy介绍Numpy的使用Numpy生成数组ndarrayarray生成数组arange生成数组random生成数组其他示例 关于randint示例1示例2 关于rand Numpy数组统计方法示例 二、Pandas模块pandas介绍Series示例 DataFrame示例 三、其他模块Matplotlib/Seabo…

【JAVA】数组的定义与使用

前一篇我们讲述了方法的使用和递归&#xff0c;这一讲 我们来叙述一下数组相关知识点。最近更新较快&#xff0c;大家紧跟步伐哦~~ 1. 数组的基本概念 1.1 为什么要使用数组 假设现在要存5个学生的javaSE考试成绩&#xff0c;并对其进行输出&#xff0c;按照之前掌握的知识点&…

uniapp的底部弹出层实现保姆式教程

实现照片&#xff1a; 此过程先进入uniapp官网&#xff0c;找到扩展组件 打开找到里面的uni-popup和uni-icons 点击进入&#xff0c;下载&安装 点击下载并导入HBuilderX 导入到你使用的目录&#xff0c;如test目录 同样将uni-icons点击下载并导入HBuilderX 点击合并 此时te…

运输层(计算机网络谢希仁第八版)——学习笔记五

课件&#xff1a;课程包列表 (51zhy.cn) 目录 运输层协议概述 用户报协议UDP 传输控制协议TCP概述 可靠传输的工作原理 TCP可靠传输的实现 TCP的流量控制 TCP的拥塞控制 TCP的运输连接管理 运输层协议概述 进程之间的通信 运输层的位置——只有位于网络边缘部分的主机的协议栈才…

Jmeter+Grafana+Prometheus搭建压测监控平台

本文不介绍压测的规范与技术指标&#xff0c;本文是演示针对Jmeter如何将压测过程中的数据指标&#xff0c;通过Prometheus采集存储&#xff0c;并在Granfan平台进行仪表盘展示; 介绍 系统压测属于日常项目开发中的一个测试环节&#xff0c;使用测试工具模拟真实用户行为&…