一,spring-cloud搭建开发环境相关:
搭建springbot工程所需的步骤
pom.xml的导包
配置文件
主启动类
1,创建一个空的父工程,
2,在fileEncoding里设置为相应的编码需求,(utf-8),
3,Maven设置为自己的本地镜像仓库,
4,搭建父工程:
<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 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.chenshi</groupId>
<artifactId>spring-cloud-parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>eureka-provider</module>
<module>eureka-consumer</module>
<module>eureka-server</module>
</modules>
<!--spring-boot环境-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.11.RELEASE</version>
</parent>
<!--配置cloud版本-->
<properties>
<spring-cloud.version>Hoxton.SR12</spring-cloud.version>
</properties>
<!--依赖管理-->
<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>
</project>
5,根据实际情况搭建相应的子工程
二,eureka注册中心相关:
注册中心的核心功能:
1,服务注册,
2,服务发现,
3,服务维护
-
eureka微服务实现方式(三步走):
1, 在pom中导入eureka依赖,搭建eureka-server:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.chenshi</groupId>
<artifactId>spring-cloud-parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>eureka-server</artifactId>
<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-server</artifactId>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
2,在pom.xml文件中导入依赖
#在yml文件配置eureka服务
eureka:
instance:
hostname: localhost
client:
service-url:
defaultZone: http://localhost:8761/eureka/ #注册中心的地址
spring:
application:
name: eureka-provider #给当前的(微服务)application取名字,方便在注册中心方便管理
3,在主启动类中加入注解:
package com.chenshi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient//启动eureka服务
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class,args);
}
}
三,eureka部署相关:
-
生产端或者消费端的部署相关:
instance:
#instance内容:
prefer-ip-address: true #将自己的ip地址注册到eureka上
ip-address: 127.0.0.1 #这个ip地址为多少,
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}#该服务在注册中心的名字,
lease-renewal-interval-in-seconds: 30 #每30秒发送一次心跳,向注册中心确定存活
lease-expiration-duration-in-seconds: 90 #如果90秒没有发送心跳就挂掉,则注销服务
#如果实现了高可用集群配置,不能用localhost而是配置的域名,有几台机器就写几台机器上,消费端和生产端都需要。
defaultZone: http://eureka-server1:8762/eureka,http://eureka-server2:8763/eureka
client:
#client内容:
registry-with-eureka: true #是否将自己的路径注册到eureka上,默认为true
fetch-registry: true #是否需要从eureka中抓取数据,供消费端使用
-
eureka服务器的部署相关:
server:
#server内容:
enable-self-preservation : true #是否开启自我保护模式,默认开启
eviction-interval-timer-in-ms: 120000 #如果超过这个时间才算彻底过期,,默认是90000毫秒
#仪表板:
dashboard:
enabled: true
path: /
四,eureka高可用集群配置:
高可用本质: 就是启动多个服务,以防单一个挂掉,导致整个服务挂掉
- eureka高可用实现步骤:
1,搭建环境:
第一台机器:
server:
port: 8762
eureka:
instance:
hostname: eureka-server1
client:
service-url:
defaultZone: http://eureka-server2:8762/eureka #eureka服务端地址
register-with-eureka: false #是否将自己的路径注册到eureka上,服务端不需要,客户端需要。
fetch-registry: false #是否需要从eureka抓取路径,服务端不需要,客户端需要。
spring:
application:
name: eureka-server-ha #服务名可以一样
第二台机器:
server:
port: 8763
eureka:
instance:
hostname: eureka-server2
client:
service-url:
defaultZone: http://eureka-server1:8762/eureka #eureka服务端地址
register-with-eureka: false #是否将自己的路径注册到eureka上,服务端不需要,客户端需要。
fetch-registry: false #是否需要从eureka抓取路径,服务端不需要,客户端需要。
spring:
application:
name: eureka-server-ha #服务名可以一样
2,让这几台机器相互注册对方,
3,启动这几台机器
本地修改hosts文件,添加eureka域名,
windows路径:C:\Windows\System32\drivers\etc\hosts
五,nacos注册中心相关:
分布式和微服务的区别:
微服务:是指系统架构的一种设计方式,将复杂的业务拆分成多个微小的服务,让这些服务可以单独运行和部署。
分布式:是指系统的部署方式,将同一个服务拆分部署到多台机器上,用于分摊单台机器的负载压力,一般是采用集群,主备来部署
共同点:分布式和微服务都尤其注重一致性和负载均衡
-
什么是Naocs:
nacos = eureka + config + bus
代替Eureka做服务中心,代替config做配置中心。
1,服务端配置详情:
-
spring-nacos搭建环境:
1,下载nacos服务,在nacos.io前往 官方文档快速开始查看最新nacos版本以及下载。
2,下载解压压缩包之后,执行startup命名启动nacos服务。
#单机模式启动
startup.cmd -m standalone
#关闭nacos服务
shutdown.cmd
3,启动nacos服务之后,前往控制台:http://192.168.28.1:8848/nacos/index.html ,如果有账户密码即默认都是nacos。
-
spring-cloud搭建环境:
1,搭建父工程:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--spring-boot版本一定要在2.6以上-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.17</version>
</parent>
<groupId>com.chenshi</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<!--子类-->
<modules>
<module>nacos-provider8000</module>
</modules>
<!--依赖控制-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
2,子工程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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--继承父工程,实现版本统一-->
<parent>
<groupId>com.chenshi</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>nacos-provider8000</artifactId>
<!--导入相关依赖-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--导入spring-cloud-nacos依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
3,yml文件:
server:
port: 8000
spring:
application:
name: nacos-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848
4,搭建三层架构,实现后端接口(模拟):
package com.chenshi.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/goods")
public class GoodsController {
@Value("${server.port}")
Integer serverPort;
@GetMapping("/findById/{id}")
public String findById(@PathVariable("id") Integer id){
//模拟业务逻辑
return "nacos-provider.port:" + serverPort + ",: id:" + id;
}
}
5,重复再搭建一个nacos-provider8001,并且使他们application.name不变就能实现在一个集群内方便管理。
2,消费端配置详情:
-
首先要搭建一个消费端框架:
1,由于spring-cloud-alibaba完全脱离了spring-cloud-starter-netflix-ribbon所以加载依赖要排除掉,
2,导入loadbalancer依赖。
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.chenshi</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>nacos-consumer9000</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--导入loadbalancer依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
3,消费端yml文件:
server:
port: 9000
spring:
application:
name: nacos-consumer
cloud:
loadbalancer:
ribbon:
enabled: false
nacos:
discovery:
server-addr: localhost:8848
4,主启动类:
package com.chenshi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class NacosConsumer9000App {
public static void main(String[] args) {
SpringApplication.run(NacosConsumer9000App.class, args);
}
}
5,配置类:
package com.chenshi.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced//ribbon 负载均衡的客户端
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
6,搭建三层架构,最后调用服务端接口(模拟代码):
package com.chenshi.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired RestTemplate restTemplate;
@GetMapping("/add/{id}")
public String add(@PathVariable("id") Integer id){
//业务逻辑
String url = "http://nacos-provider/goods/findById" + id;
return restTemplate.getForObject(url, String.class);
}
}
六,使用feign调用微服务:
1,导入相关依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2,在启动类上加上注解开启 Feign功能
@SpringBootApplication
@EnableDiscoveryClient//开启服务发现功能
@EnableFeignClients//开启Feign功能
public class NacosConsumer9001App {
public static void main(String[] args) {
SpringApplication.run(NacosConsumer9001App.class,args);
}
}
3,创建一个Feign接口,用于调用服务
package com.chenshi.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
//写入服务端的application.name
@FeignClient("nacos-provider")
public interface GoodsFeign {
@GetMapping("/order/findById/{id}")
String findById(@PathVariable("id")Integer id);
}
4,controller层,注入Feign,并调用该接口
package com.chenshi.controller;
import com.chenshi.feign.GoodsFeign;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
@RequestMapping("/order")
public class OrderController {
@Resource RestTemplate restTemplate;
@Resource GoodsFeign goodsFeign;
@GetMapping("/add2/{id}")
public String add2(@PathVariable("id")Integer id){
//业务逻辑
return goodsFeign.findById(id);
}
}
七,nacos配置中心相关:
1,导入相关依赖
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.chenshi</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>nacos-client7777</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--配置中心客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--和nacos相连接-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--导入bootstap相关依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
2,application.yml配置文件:
spring:
profiles:
active: dev #开发环境
3,bootstrap.yml配置文件:
#nacos配置
server:
port: 7777
spring:
application:
name: nacos-config-client
cloud:
nacos:
discovery:
server-addr: localhost:8848 #nacos注册中心的地址
config:
server-addr: localhost:8848 #将nacos作为配置中心的地址
file-extension: yaml #指定yaml格式为配置
4,主启动类:
@SpringBootApplication
@EnableDiscoveryClient//开启服务发现客户端
public class NacosClient7777App {
public static void main(String[] args) {
SpringApplication.run(NacosClient7777App.class, args);
}
}
5,在nacos面板里新建配置并发布:
${prefix}-${spring.profiles.active}.${file-extension}#DataId的标准格式
nacos-config-client-dev.yaml
{名字}-{环境}.{文件类型}
6,在需要刷新配置的地方加入自动刷新注解:
package com.chenshi.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/config")
@RefreshScope//开启自动刷新功能
public class ConfigClientController {
//从nacos配置中心取的值
@Value("${name}")
String name;
@GetMapping("/name")
public String getName() {
return name;
}
}
7,nacos配置中心的值一改变访问的服务也会立即随着改变,相当于bus
8,N G D/S规则的使用
八, nacos集群和持久化配置:
目的:将nacos本身的derby-data数据库切换存储到MySQL数据库中,实现多个nacos可以同时使用一个数据库。
-
单机模式:
1,在nacos目录中找到如下文件
mysql-schema.sql
2,在dbeaver可视化工具中创建一个nacos数据库,nacos_devtest再将 mysql-schema.sql 文件放入数据库执行:
3,修改conf/application.properties文件,增加支持mysql数据源配置,添加mysql数据源的url、用户名和密码。
-
集群模式:
集群需要3台或以上的nacos机器才能组成一个集群。
1,使用虚拟机搭建nacos环境
九,sentinel的使用相关:
1,sentinel的控制台下载
Release v1.8.7 · alibaba/Sentinel · GitHub
2,在cmd控制台中写入,启动运行jar包
java -jar sentinel-dashboard-1.8.7.jar
3,搭建sentinel的环境,新建模块(导入依赖)
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.chenshi</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>1.0.0</version>
<relativePath>/pom.xml</relativePath>
</parent>
<artifactId>cloud-sentinel-service8000</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
4,application.yml配置详细:
server:
port: 8000
spring:
application:
name: cloud-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719 # sentinel默认8719端口,会自动扫描是否占用,占用会向后+1直到找到未被占用的端口
5,主启动类:
package com.chenshi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
*
* @author chenyq
* @date 2024/1/29
*/
@SpringBootApplication
@EnableDiscoveryClient
public class SentinelService8000App {
public static void main(String[] args) {
SpringApplication.run(SentinelService8000App.class, args);
}
}
6,启动端口,
由于sentinel是懒加载策略,需要调用接口才能加载到sentinel控制台。
规则的配置是热加载,无需重启服务即可修改规则。
1,流控规则:
7,流控规则:
簇点电路里可以配置,流控,熔断, 热点,授权
在新增流控规则中有以下配置信息可供配置:
-
资源名:
来访问的路径 -
针对来源:
默认为:
default,可以指定特定的来源来源进行流控。 -
阈值类型:
QPS:每秒请求量并发线程数:达到某个线程数进行限流 -
单机阈值:
阈值/s -
是否集群:
true/false -
流控模式:
直接,该资源名到达阈值,直接访问失败关联:列如A关联B,A或B访问失败都会导致任意一方无法访问。链路:具体给某个链路上的资源限流,列如:下单操作goodsService限流,减库存操作goodsService不进行限流。 -
流控效果:
快速失败:直接访问失败。Warm Up: 冷启动,默认为QPS/3 及为3,当达到预热时间,3/s逐渐升至阈值/s。排队等待:让请求匀速访问,列如每10000ms执行一次,相当于一个消息队列PS: QPS阈值 >= 2时,排队等待才会生效,目前匀速排队不支持QPS > 1000
20240130。 -
几种流控情况:
1,QPS,直接,快速失败:访问端口时当QPS大于阈值,直接访问失败。
2,QPS,关联,快速失败:访问端口时当资源A失败,B也会无法访问,当B失败时,A也会访问失败。
3,并发线程,直接:访问端口时当并发线程到达阈值时,再次访问都会被直接阻拦。
4,QPS,链路,快速失败:当入口资源URL访问超过阈值后,该资源名也会一起失效无法访问。
5,QPS,直接,Warm Up:假设 设置QPS阈值为10,当冷启动达到5s,接口访问从原先的3/s,到达10/s。
8,在service层, 里面的方法加上注解 @SentinelResource即被视为入口资源。
package com.chenshi.service;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Service;
/**
*
* @author chenyq
* @date 2024/1/29
*/
@Service
public class GoodsService {
@SentinelResource("querygoods")
public void query(){
System.out.println("查询商品");
}
}
9,配置文件关闭收敛URL
sentinel:
transport:
dashboard: localhost:8080
port: 8719 # sentinel默认8719端口,会自动扫描是否占用,占用会向后+1直到找到未被占用的端口
web-context-unify: false #关闭收敛URL
2,熔断降级:
熔断降级作为保护自身的手段,避免局部不稳定导致整体的雪崩,通常在客户端(调用端)进行配置。
-
资源名:
访问的接口 -
熔断策略:
慢调用比列:在统计时长内,请求数量 > 最小请求数,并且慢调用比例 > 阈值,则熔断器生效。异常比列:在统计时长内,请求数量 > 设置的最小请求数量,并且异常的比例 > 阈值,则熔断器生效。异常数: -
最大RT:
Round Trip Time(相应时间)。
-
比例阈值:
比例阈值范围为:[0.0,1.0],例如0.5 为 50%。
-
熔断时长:
保险的熔断持续多久
-
最小请求数:
设置一个应该达到最小的请求数量,大于这个数量保险丝就会勘测是否熔断。
-
统计时长:
在这个时长之间,就会到达熔断策略例如1000ms内。
-
几种熔断情况(例子):
1,慢调用,最大RT:500,阈值:0.5,熔断时长:1s,最小请求数:6,统计时长1000ms;
在统计时长1000ms内最小请求数:6 有0.5(50%)的比率失败,及熔断器生效,时长为1s。
2,异常比例,比例阈值:0.2,熔断时长:2s,最小请求数:5,统计时长1000ms;
在统计时长1000ms内最小请求数:5有0.2(20%)的异常,及熔断器生效,时长为2s。
3,异常数,异常数:2,熔断时长:5s,最小请求数:6,统计时长1000ms;
在统计时长1000ms内最小请求数:6有 2次异常错误,及熔断器生效,时长为5s;
3,热点参数:
经常被访问的数据,可以是对商品访问频次最好的TOP数据,也可以是用户频繁访问的数据,来进行限流。
1,pom文件中导入依赖:
<!--热点参数限流-依赖-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-parameter-flow-control</artifactId>
<version>1.8.6</version>
</dependency>
2,controller层代码:
/*热点参数限流*/
@GetMapping("/order")//问号传参
@SentinelResource(value = "hotKey")
public String order(@RequestParam(value = "goodsId",required = false) String goodsId,
@RequestParam(value = "userId",required = false) String userId){
//业务逻辑
return "用户下单: success";
}
3,热点规则的限流模式,目前只有QPS模式,
-
几种热点参数限流情况(例子):
1,QPS,参数索引(从0开始):0,阈值:1,统计窗口时间:1s; ps:该参数为源代码中的参数索引为准,而非用户访问的参数索引
对传入参数0限流,访问 > 阈值 1,则熔断器生效,1s;
4,自定义回显内容,代码如下:
/*热点参数限流*/
@GetMapping("/order")//问号传参
@SentinelResource(value = "hotKey",blockHandler = "orderBlock")//一旦出错,给前端页面返回一个blockHandler
public String order(@RequestParam(value = "goodsId",required = false) String goodsId,
@RequestParam(value = "userId",required = false) String userId){
//业务逻辑
return "用户下单: success";
}
/*自定义回显内容*/
public String orderBlock(@RequestParam(value = "goodsId",required = false) String goodsId,
@RequestParam(value = "userId",required = false) String userId, BlockException e){
//以形参方式传入blockException,日后记录报错日志。
return "用户: + userId +下单失败,请稍后重试";
}
ps:自定义回显内容只会回显sentinel自身的错误,代码中的业务错误并不会调用该回显。
5,热点参数例外情况:
例如在商品秒杀情况下,为某个参数单独设置一个阈值。
-
热带参数列外情况(例子):
1,参数索引为 0 的情况,参数类型 string,参数值:99,限流阈值:1000;
访问该地址时,当索引为 0 的参数 == 99,限流阈值从原来的10,会改变为1000;
4,系统自适应:
结合应用的load,cpu使用率,总体平均RT,入口QPS和并发线程等几个维度的监控指标,让系统保证最大吞吐量的同时,保证系统的稳定性。
-
LOAD:
仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的
maxQps * minRt估算得出。设定参考值一般是CPU cores * 2.5。
-
RT:
平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
-
线程数:
并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
-
入口QPS:
入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
-
CPU使用率:
CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
6,@SentinelResource注解相关:
1,value = "{resouceName}":
因为在sentinel控制面板中资源名都是以order/add/vip/goodsId/1的形式,为了方便辨识在value中写入自定义的资源名。
2,blockHandler = "{methodName}":
创建一个blockHandler方法名,当触发blockHandler后,返回一个自定义的回显内容。
3,blockHandlerClass = {class对象}
/*减库存*/
@GetMapping("/resume")//问号传参
@SentinelResource(value = "resume",blockHandlerClass = CommonBlockHandler.class,blockHandler = "blockHandler0")//
public String resume(@RequestParam(value = "goodsId",required = false) String goodsId){
//业务逻辑
//int a = 1 / 0;
return "减库存成功: success";
}
4,一个blockHandler的公共返回类。
ps:blockHanlder的方法一定要是 static 修饰的
package com.chenshi.ExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.RequestParam;
//一个公共的sentinel错误回显类;
public class CommonBlockHandler {
//根据接口的不同,形参要和调用接口保持一致
public static String blockHandler0(@RequestParam(value = "goodsId",required = false) String goodsId,BlockException e){
//记录报错日志
//给用户回显一个自定义内容;
return "系统出错了,请稍后重试";
}
//没有形参则只需要一个BlockException e的形参;
public static String blockHandler1(BlockException e){
//记录报错日志
//给用户回显一个自定义内容;
return "系统出错了,请稍后重试";
}
}
5,服务降级:
1,熔断/限流:微服务自己限流,使其不可用。
2,降级:调用方,提供方出错异常,需要返回给用户一个友好对象。
3,搭建3个微服务工程使其相互调用。
4,一个商品不可能id < 0 ,这属于业务逻辑出错所以需要对其服务降级,使用@sentinelResource注解的: fallback
package com.chenshi.controler;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.chenshi.domain.Goods;
import com.chenshi.exception.BlockHandler;
import com.chenshi.exception.FallbackHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
@RequestMapping("/order")
public class OrderController {
@Resource RestTemplate restTemplate;
@GetMapping("/add/{id}")
//回显的blockHandler方法必须是static修饰的
//@SentinelResource(value = "order",blockHandlerClass = BlockHandler.class,blockHandler = "orderHandler")
@SentinelResource(value = "order",fallbackClass = FallbackHandler.class,fallback = "orderFallback")
public Goods order(@PathVariable("id") Integer id){
//使用ribbon时,调用的应该是这个在nacos中声明的服务名,而不是固定地址。
String url = "http://cloud-sentinel-provider/goods/findById/" + id;
if (0 > id) {
throw new IllegalArgumentException("非法参数,警告你");
}else if (id > 100){
throw new NullPointerException("查无此商品");
}
return restTemplate.getForObject(url,Goods.class);
}
}
5,使用一个函数类来提供fallback
package com.chenshi.exception;
import com.chenshi.domain.Goods;
import org.springframework.web.bind.annotation.PathVariable;
/*业务错误,走fallback*/
public class FallbackHandler {
public static Goods orderFallback(@PathVariable(value = "id",required = false) Integer id,Throwable e){
return new Goods(id,"商品:极光pro业务逻辑出错",5799.00,20);
}
}
6,@sentinelResource中可以同时使用fallback,blockhandler且两者都能使用生效。
@SentinelResource(value = "order",blockHandlerClass = BlockHandler.class,blockHandler = "orderHandler",
fallbackClass = FallbackHandler.class,fallback = "orderFallback")
public Goods order(@PathVariable("id") Integer id){
//使用ribbon时,调用的应该是这个在nacos中声明的服务名,而不是固定地址。
String url = "http://cloud-sentinel-provider/goods/findById/" + id;
if (0 > id) {
throw new IllegalArgumentException("非法参数,警告你");
}else if (id > 100){
throw new NullPointerException("查无此商品");
}
return restTemplate.getForObject(url,Goods.class);
}
7,@sentinelResource中的exceptionsToIgnore,可以忽略某个业务上的异常。
@SentinelResource(value = "order",blockHandlerClass = BlockHandler.class,blockHandler = "orderHandler",
fallbackClass = FallbackHandler.class,fallback = "orderFallback",
exceptionsToIgnore = {IllegalArgumentException.class})//忽略掉IllegalArgumentException的异常
public Goods order(@PathVariable("id") Integer id){
//使用ribbon时,调用的应该是这个在nacos中声明的服务名,而不是固定地址。
String url = "http://cloud-sentinel-provider/goods/findById/" + id;
if (0 > id) {
throw new IllegalArgumentException("非法参数,警告你");
}else if (id > 100){
throw new NullPointerException("查无此商品");//
}
return restTemplate.getForObject(url,Goods.class);
}
8,在sentinel中使用feign功能,导入依赖。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
9,yml文件中启用feign功能。
#在sentinel中启动feign服务
feign:
sentinel:
enabled: true
10,主启动类中加上@EnableFeignClients注解
package com.chenshi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients//开启feign功能
public class ConsumerApp8090 {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp8090.class, args);
}
}
11,新建feign接口。
package com.chenshi.feign;
import com.chenshi.domain.Goods;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
//feign失败后走向fallback
@FeignClient(value = "cloud-sentinel-provider",fallback = GoodsFeignImpl.class)//这是一个Feign客户端
public interface GoodsFeign {
@GetMapping("/goods/findById/{id}")
Goods findById(@PathVariable("id") Integer id);
}
12,feignImpl实现类。
package com.chenshi.feign;
import com.chenshi.domain.Goods;
//feign接口调用失败,返回一个自定义对象
@Serivce
public class GoodsFeignImpl implements GoodsFeign {
@Override
public Goods findById(Integer id) {
return new Goods(id,"feign接口调用出错,这是一个回显",6799.00,20);
}
}
13,controller层使用feign调用微服务代码。
@Resource GoodsFeign goodsFeign;
@GetMapping("/add1/{id}")
@SentinelResource(value = "order",blockHandlerClass = BlockHandler.class,blockHandler = "orderHandler",
fallbackClass = FallbackHandler.class,fallback = "orderFallback",
exceptionsToIgnore = {IllegalArgumentException.class})
public Goods order1(@PathVariable("id") Integer id){
//使用feign远程调用
return goodsFeign.findById(id);
}
6,sentinel配置持久化:
目的是将sentinel的配置持久化到nacos配置中心里。
1,导入依赖;
<!--sentinel配置持久化到nacos上-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
2,yml文件:
spring:
application:
name: cloud-consumer-nacos-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719
web-context-unify: false
datasource: #和trasnport同级,加入datasource
ds1:
nacos:
server-addr: localhost:8848
data-id: ${spring.application.name} #项目名
group-id: DEFAULT_GROUP
data-type: json #数据类型
rule-type: flow #流控规则
3,nacos配置中心的配置内容:
#json字符串放入nacos配置中心
[
{
"resource": "/order/add1/{id}",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]#中括号
4,参数含义:
* "resource": 资源名;
"limitApp": 来源应用;
"grade": 阈值类型(0:线程数,1:QPS);
"count": 单机阈值;
"strategy": 流控模式,0:直接,1:关联,2:链路;
"controlBehavior": 流控效果,0:快速失败,1:Warm Up,2:排队等待;
"clusterMode": 集群模式true/false