服务网关
Zuul路由网关(停更)
不学不用!了解一些!
Gateway新一代网关
分布式服务架构、微服务架构与 API 网关
在微服务架构里,服务的粒度被进一步细分,各个业务服务可以被独立的设计、开发、测试、部署和管理。这时,各个独立部署单元可以用不同的开发测试团队维护,可以使用不同的编程语言和技术平台进行设计,这就要求必须使用一种语言和平 台无关的服务协议作为各个单元间的通讯方式。
API 网关的定义
网关的角色是作为一个 API 架构,用来保护、增强和控制对于 API 服务的访问。
API 网关是一个处于应用程序或服务(提供 REST API 接口服务)之前的系统,用来管理授权、访问控制和流量限制等,这样 REST API 接口服务就被 API 网关保护起来,对所有的调用者透明。因此,隐藏在 API 网关后面的业务系统就可以专注于创建和管理服务,而不用去处理这些策略性的基础设施。
Gateway是什么
Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代ZUUL,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。
Gateway9527初步搭建
1、创建cloud_gateway9527
2、依赖 (不需要web和actore依赖)
<dependencies>
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--一般基础配置类-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>
3、配置文件
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
#- After=2020-02-21T15:51:37.485+08:00[Asia/Shanghai]
#- Cookie=username,zzyy
#- Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数的正则表达式
eureka:
instance:
hostname: cloud-gateway-service
client: #服务提供者provider注册进eureka服务列表内
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka
4、主启动类
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class Cloud_GateWay9527 {
public static void main(String[] args) {
SpringApplication.run(Cloud_GateWay9527.class,args);
}
}
路由没有业务类,就是一看门的。
5、测试
我们启动8001、7001和9527
添加网关前:http://localhost:8001/payment/get/4
添加网关后:http://localhost:9527/payment/get/4 这样就可以隐藏微服务的端口号。
路由网关的两种配置方式
1、配置文件的方式,也就是前面的
2、就会说硬编码的方式。RouteLocator的Bean
@Configuration
public class GateWayConfog {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder)
{
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
routes.route("path_route_atguigu",
r -> r.path("/guonei")
.uri("http://news.baidu.com/guonei")).build();
return routes.build();
}
}
Gateway配置动态网关
通过微服务名来实现动态路由
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
#- After=2020-02-21T15:51:37.485+08:00[Asia/Shanghai]
#- Cookie=username,zzyy
#- Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数的正则表达式
eureka:
instance:
hostname: cloud-gateway-service
client: #服务提供者provider注册进eureka服务列表内
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka
Gateway的Filter
自定义全局Filter
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Date;
/**
* @auther zzyy
* @create 2020-02-21 16:40
*/
@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter,Ordered
{
/*
* 访问方法需要验证用户名
* */
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
{
log.info("***********come in MyLogGateWayFilter: "+new Date());
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if(uname == null)
{
log.info("*******用户名为null,非法用户,o(╥﹏╥)o");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
/*
* 加载过滤器的顺序
* */
@Override
public int getOrder()
{
return 0;
}
}
分布式配置中心config
是什么
Spring Cloud Config用来为分布式系统中的基础设施和微服务应用提供集中化的外部配置支持,分为服务端和客户端两个部分。其中服务端又称为分布式配置中心,是一个独立的微服务应用,用来连接配置仓库并为客户端提供获取配置信息;而客户端则是微服务架构中的各个微服务应用或基础设施,它们通过指定配置中心来管理应用资源和业务相关的配置内容。服务器存储后端的默认实现使用git,也可以使用SVN仓库或者本地文件系统。
就是将配置文件统一管理,一处修改处处生效。
服务端----总把头
环境搭建
在自己的gitee账户上创建一个仓库,然后将配置文件上传gitee.com/cbbgs/sprin…
也可以拉取到本地。
配置总控制中心的搭建
1、创建总配置中心cloud_config_center3344
2、导入依赖
<dependencies>
<!--添加消息总线RabbitMQ支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>
3、书写配置文件
server:
port: 3344
spring:
application:
name: cloud-config-center #注册进Eureka服务器的微服务名
cloud:
config:
server:
git:
uri: git@gitee.com:cbbgs/springcloud-config.git #Gitee上面的git仓库名字
####搜索目录
search-paths:
- springcloud-config
####读取分支
label: master
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
4、书写启动类
@SpringBootApplication
/*添加服务端扫描*/
@EnableConfigServer
public class ConfigCenterMain3344 {
public static void main(String[] args) {
SpringApplication.run(ConfigCenterMain3344.class,args);
}
}
5、测试
我们启动7001和3344进行测试
成功访问到我们gitee仓库的配置。
访问规则:/分支/名字-环境.yml
config客服端配置
1、创建客户端配置cloud_config_client3355
2、导入依赖
<dependencies>
<!--添加消息总线RabbitMQ支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>
3、书写客户端配置bootstrap.yml
server:
port: 3355
spring:
application:
name: config-client
cloud:
#Config客户端配置
config:
label: master #分支名称
name: config #配置文件名称
profile: dev #读取后缀名称 上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
uri: http://localhost:3344 #配置中心地址k
#rabbitmq相关配置 15672是Web管理界面的端口;5672是MQ访问的端口
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
4、主启动类
@EnableEurekaClient
@SpringBootApplication
public class ConfigClientMain3355
{
public static void main(String[] args) {
SpringApplication.run(ConfigClientMain3355.class, args);
}
}
5、业务类,打印配置信息
@RestController
public class ConfigClientController
{
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo()
{
return configInfo;
}
}
6、测试
存在的问题:如果在gitee上修改的配置文件,在配置中心的客户端是不能刷新出来的,需要重启客户端。怎么解决呢?
分布式配置客户端动态刷新
修改3355模块
修改yml,暴露监控断点
server:
port: 3355
spring:
application:
name: config-client
cloud:
#Config客户端配置
config:
label: master #分支名称
name: config #配置文件名称
profile: dev #读取后缀名称 上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
uri: http://localhost:3344 #配置中心地址k
#rabbitmq相关配置 15672是Web管理界面的端口;5672是MQ访问的端口
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
##################新增###################################
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
修改controller,添加注解@RefreshScope
@RestController
@RefreshScope //新增
public class ConfigClientController
{
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo()
{
return configInfo;
}
}
手动刷新:curl -X POST "http://localhost:3355/actuator/refresh/"
这就请求到新 的了。避免了服务重启。
但是,如果
该怎么办,目前还办不到,需要我们的服务总线
服务总线Bus
Bus之RabbitMQ环境安装
设计思想1
上面的流程中,虽然我们做到了利用一个消息总线触发刷新,而刷新所有客户端配置的目的,但是这种方式并不合适,如下:
- 打破了微服务的职责单一性。微服务本身是业务模块,它本不应该承担配置刷新的职责。
- 破坏了微服务各节点的对等性。
- 如果客户端ip有变化,这时我们就需要修改WebHook的配置。
设计思想2
我们一般用思想二
Docker安装RabbitMQ
参考地址 blog.csdn.net/qq_34775355…
#拉取镜像 8 d23bdf5b1b1b 4 years ago 643MB
[root@cbbgs ~]# docker pull rabbitmq
Using default tag: latest
latest: Pulling from library/rabbitmq
f22ccc0b8772: Pull complete
3cf8fb62ba5f: Pull complete
e80c964ece6a: Pull complete
c1d2d6c5864b: Pull complete
0adcf6f8f5f2: Pull complete
6d7425e3abe0: Pull complete
b03e46685eee: Pull complete
f83c4b83a829: Pull complete
fab4bdeccdff: Pull complete
02221abafa2c: Pull complete
Digest: sha256:5a6e86289ee2d03a6889341bfb3a76943de1d0c4d01b777c4159a944d8d3e9cd
Status: Downloaded newer image for rabbitmq:latest
docker.io/library/rabbitmq:latest
#查看镜像
[root@cbbgs ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
homemall-h latest 8addc602c1ff 5 days ago 681MB
registry.cn-hangzhou.aliyuncs.com/cbbgs/homemall-h latest 8addc602c1ff 5 days ago 681MB
homemall latest c3dd8526a983 6 days ago 724MB
registry.cn-hangzhou.aliyuncs.com/cbbgs/homemall latest c3dd8526a983 6 days ago 724MB
rabbitmq latest 7471fb821b97 7 days ago 167MB
redis latest 621ceef7494a 10 days ago 104MB
zookeeper latest 28ffb774bc32 10 days ago 253MB
mysql latest d4c3cafb11d5 11 days ago 545MB
consul latest 2823bc69f80f 5 weeks ago 120MB
java 8 d23bdf5b1b1b 4 years ago 643MB
#运行容器
[root@cbbgs ~]# docker run -d -p 5672:5672 -p 15672:15672 rabbitmq
fbc4e7cc162f5476a6b461e2c4a13e7bcd2b87c90774088f8847a060927205ab
#查看后台的容器
[root@cbbgs ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fbc4e7cc162f rabbitmq "docker-entrypoint.s…" 5 seconds ago Up 4 seconds 4369/tcp, 0.0.0.0:5672->5672/tcp, 5671/tcp, 15691-15692/tcp, 25672/tcp, 0.0.0.0:15672->15672/tcp jolly_sinoussi
01b50d91518c consul "docker-entrypoint.s…" 2 days ago Up 36 hours 8300-8302/tcp, 8301-8302/udp, 8600/tcp, 8600/udp, 0.0.0.0:8500->8500/tcp sad_swanson
3d6121d4f2c1 zookeeper "/docker-entrypoint.…" 2 days ago Up 2 days 2888/tcp, 3888/tcp, 0.0.0.0:2181->2181/tcp, 8080/tcp dazzling_leakey
8137393ac557 redis "docker-entrypoint.s…" 4 days ago Up 4 days 0.0.0.0:6379->6379/tcp silly_hoover
dca567a50338 homemall-h "java -jar /app.jar …" 5 days ago Up 5 days 0.0.0.0:8088->8088/tcp objective_kalam
81cda9cbf07b homemall "java -jar /app.jar …" 6 days ago Up 6 days 0.0.0.0:8084->80/tcp #进入rabbitmq
[root@cbbgs ~]# docker exec -it fbc4e7cc162f /bin/bash
root@fbc4e7cc162f:/# rabbitmq-plugins enable rabbitmq_management
Enabling plugins on node rabbit@fbc4e7cc162f:
rabbitmq_management
The following plugins have been configured:
rabbitmq_management
rabbitmq_management_agent
rabbitmq_prometheus
rabbitmq_web_dispatch
Applying plugin configuration to rabbit@fbc4e7cc162f...
The following plugins have been enabled:
rabbitmq_management
started 1 plugins.
就可以访问了
全局动态刷新
1、创建新模块cloud_config_clint3366
2、创建导入依赖
<dependencies>
<!--添加消息总线RabbitMQ支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>
3、书写配置
server:
port: 3366
spring:
application:
name: config-client
cloud:
#Config客户端配置
config:
label: master #分支名称
name: config #配置文件名称
profile: dev #读取后缀名称 上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
uri: http://localhost:3344 #配置中心地址
#rabbitmq相关配置 15672是Web管理界面的端口;5672是MQ访问的端口
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
4、书写启动类
@SpringBootApplication
@EnableEurekaClient
public class Cloud_config_Clent3366 {
public static void main(String[] args) {
SpringApplication.run(Cloud_config_Clent3366.class,args);
}
}
5、书写控制类
@RestController
@RefreshScope
public class ConfigClientController
{
@Value("${server.port}")
private String serverPort;
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String configInfo()
{
return "serverPort: "+serverPort+"\t\n\n configInfo: "+configInfo;
}
}
修改以前配置
1、修改config服务端3344的 依赖
添加rabbitmq相关配置和暴露
server:
port: 3344
spring:
application:
name: cloud-config-center #注册进Eureka服务器的微服务名
cloud:
config:
server:
git:
uri: git@gitee.com:cbbgs/springcloud-config.git #Gitee上面的git仓库名字
####搜索目录
search-paths:
- springcloud-config
####读取分支
label: master
#rabbitmq相关配置
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
##rabbitmq相关配置,暴露bus刷新配置的端点
management:
endpoints: #暴露bus刷新配置的端点
web:
exposure:
include: 'bus-refresh'
修改客户端3355
server:
port: 3355
spring:
application:
name: config-client
cloud:
#Config客户端配置
config:
label: master #分支名称
name: config #配置文件名称
profile: dev #读取后缀名称 上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
uri: http://localhost:3344 #配置中心地址k
#rabbitmq相关配置 15672是Web管理界面的端口;5672是MQ访问的端口
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
修改客户端3366
server:
port: 3355
spring:
application:
name: config-client
cloud:
#Config客户端配置
config:
label: master #分支名称
name: config #配置文件名称
profile: dev #读取后缀名称 上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
uri: http://localhost:3344 #配置中心地址k
#rabbitmq相关配置 15672是Web管理界面的端口;5672是MQ访问的端口
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
这里没有区别,因为我之前导入的是全的。
测试启动 3344 3355 3366 7001
访问:http://localhost:3344/config-dev.yml http://localhost:3355/configInfo http://localhost:3366/configInfo
修改远程仓库的版本。我们将前面的3版本改成4.
我们只刷新一台机器就可以实现全部广播。curl -X POST "http://localhost:3355/actuator/refresh/"
这达到了一次修改,到处通知。
局部动态刷新
我们只想通知3355,不想通知3366
公式:curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:3355"
Stream消息驱动
屏蔽底层消息中间件的差异,降低切换版本,统一消息的编程模型
中文指导手册:m.wang1314.com/doc/webapp/…
Binder可以理解为提供了Middleware操作方法的类。Spring Cloud 提供了Binder抽象接口以及KafKa和Rabbit MQ的Binder的实现。
创建三个项目cloud-stream-rabbitmq-provider8801 cloud-stream-rabbitmq-consumer8802 cloud-stream-rabbitmq-consumer8803
消息驱动之生产者
1、创建cloud-stream-rabbitmq-provider8801
2、导入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</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-stream-rabbit</artifactId>
</dependency>
<!--基础配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.7</version>
</dependency>
</dependencies>
3、导入配置
server:
port: 8801
spring:
application:
name: cloud-stream-provider
cloud:
stream:
binders: # 在此处配置要绑定的rabbitmq的服务信息;
defaultRabbit: # 表示定义的名称,用于于binding整合
type: rabbit # 消息组件类型
environment: # 设置rabbitmq的相关的环境配置
spring:
rabbitmq:
host: 47.93.49.117
port: 5672
username: guest
password: guest
bindings: # 服务的整合处理
output: # 这个名字是一个通道的名称
destination: studyExchange # 表示要使用的Exchange名称定义
content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain”
binder: defaultRabbit # 设置要绑定的消息服务的具体设置
eureka:
client: # 客户端进行Eureka注册的配置
service-url:
defaultZone: http://localhost:7001/eureka
instance:
lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
instance-id: localhost # 在信息列表时显示主机名称
prefer-ip-address: true # 访问的路径变为IP地址
4、启动类
@SpringBootApplication
@EnableEurekaClient
public class Cloud_stream_rabbit_provoder8801 {
public static void main(String[] args) {
SpringApplication.run(Cloud_stream_rabbit_provoder8801.class,args);
}
}
5、业务类
发送消息的接口
public interface IMessageProvider {
public String send();
}
发送消息的实现类
@EnableBinding(Source.class) //定义消息的推送管道
public class MessageProviderImpl implements IMessageProvider
{
@Resource
private MessageChannel output; // 消息发送管道
@Override
public String send()
{
String serial = new Random().toString();
output.send(MessageBuilder.withPayload(serial).build());
System.out.println("*****serial: "+serial);
return null;
}
}
controller
@RestController
public class SendMessageController
{
@Resource
private IMessageProvider messageProvider;
@GetMapping(value = "/sendMessage")
public String sendMessage()
{
return messageProvider.send();
}
}
6、测试
启动7001 和8801
消息驱动的消费者
1、创建 cloud-stream-rabbitmq-consumer8802
2、导入依赖
<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-stream-rabbit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--基础配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>
3、导入配置
server:
port: 8802
spring:
application:
name: cloud-stream-consumer
cloud:
stream:
binders: # 在此处配置要绑定的rabbitmq的服务信息;
defaultRabbit: # 表示定义的名称,用于于binding整合
type: rabbit # 消息组件类型
environment: # 设置rabbitmq的相关的环境配置
spring:
rabbitmq:
host: 47.93.49.117
port: 5672
username: guest
password: guest
bindings: # 服务的整合处理
input: # 这个名字是一个通道的名称
destination: studyExchange # 表示要使用的Exchange名称定义
content-type: application/json # 设置消息类型,本次为对象json,如果是文本则设置“text/plain”
binder: defaultRabbit # 设置要绑定的消息服务的具体设置
eureka:
client: # 客户端进行Eureka注册的配置
service-url:
defaultZone: http://localhost:7001/eureka
instance:
lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
instance-id: localhost # 在信息列表时显示主机名称
prefer-ip-address: true # 访问的路径变为IP地址
4、启动类
@SpringBootApplication
public class Cloud_RabburMQ_Consumer8802 {
public static void main(String[] args)
{
SpringApplication.run(Cloud_RabburMQ_Consumer8802.class,args);
}
}
5、业务类
@Component
@EnableBinding(Sink.class)
public class ReceiveMessageListenerController
{
@Value("${server.port}")
private String serverPort;
@StreamListener(Sink.INPUT)
public void input(Message<String> message)
{
System.out.println("消费者1号,----->接受到的消息: "+message.getPayload()+"\t port: "+serverPort);
}
6、测试
分组消费与持久化
我们新建一个8803与8802一模一样只有端口不同。
测试运行之有两个问题,重复消费和消息持久化的问题。
重复消费
同一个组是竞争关系,不会重复消费。
解决的办法就是分组。
分组
微服务应用放置于同一个group中,就能够保证消息只会被其中一个应用消费一次。不同的组是可以消费的,同一个组内会发生竞争关系,只有其中一个可以消费
修改配置类 ,把8802和8803放在一个组
这样就不会重复消费
持久化
只要分组之后消息 就会持久化。
Sleuth分布式请求链路跟踪
在微服务框架中,一个客户端发起的请求在后端系统中会经过多个不同的服务节点调用来协同产生最后的请求结果,每一个前端请求都会形成一条复杂的分布式服务调用链路,链路中的任何一环出现高延时或错误都会引起整个请求最后的失败。SpringCloud Sleuth 提供了一套完整的服务跟踪的解决方案,在分布式系统中提供追踪解决方案并且兼容支持了zipkin 。官方文档地址:cloud.spring.io/spring-clou… 。一条链路通过Trace Id(类似于树结构的Span集合,表示一条调用链路,存在唯一标识)唯一标识,Span(表示调用链路来源,每个span就是一次请求信息)标识发起的请求信息,各Span通过parent id关联起来
docker安装zipkin
[root@cbbgs ~]# docker pull openzipkin/zipkin
Using default tag: latest
latest: Pulling from openzipkin/zipkin
85c4faba369c: Pull complete
ab3ad91c6210: Pull complete
f1b5a7ad9eac: Pull complete
b537b11d70b5: Pull complete
a950eaa7714c: Pull complete
40c09f4d3bf5: Pull complete
d7ab6ba0c34d: Pull complete
4b755abb84fe: Pull complete
d4d046ad588d: Pull complete
Digest: sha256:1ae0572be3d26fd9ab3fd2da5e8feaa0ca0078dbc31e2ddfb881b1a56bc332b1
Status: Downloaded newer image for openzipkin/zipkin:latest
docker.io/openzipkin/zipkin:latest
[root@cbbgs ~]# docker run -d -p 9411:9411 --name zipkin openzipkin/zipkin
搭建链路监控
SpringCloud从F版起已不需要自己构建Zipkin server了,只需要调用jar包即可。
我们用8001修改
1、修改8 001的依赖
<!--包含了sleuth+zipkin-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
2、修改8001的配置文件
server:
port: 8001
spring:
application:
name: cloud-payment-service
###############新加入的########
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
#采样率值介于 0 到 1 之间,1 则表示全部采集
probability: 1
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作
# driver-class-name: org.gjt.mm.mysql.Driver #mysql驱动包
url: jdbc:mysql://47.93.49.117:3306/db2020?serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
#单机版
defaultZone: http://localhost:7001/eureka
# 集群版
#defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
instance:
instance-id: payment8001
#访问路径可以显示IP地址
prefer-ip-address: true
#Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
#lease-renewal-interval-in-seconds: 1
#Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
#lease-expiration-duration-in-seconds: 2
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.atguigu.springcloud.entity #所有Entity别名类所在的包
3、修改controller
@GetMapping("/payment/zipkin")
public String paymentZipkin()
{
return "hi ,i'am paymentzipkin server fall back,welcome to atguigu,O(∩_∩)O哈哈~";
}
修改80
1、修改80的依赖和配置文件修改和8001相同。
2、修改 80的controller
// ====================> zipkin+sleuth
@GetMapping("/consumer/payment/zipkin")
public String paymentZipkin()
{
String result = restTemplate.getForObject("http://localhost:8001"+"/payment/zipkin/", String.class);
return result;
}
SpringCloud Alibaba
官方文档:spring-cloud-alibaba-group.github.io/github-page…
- 服务限流降级:默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Zuul, Dubbo 和 RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。
- 服务注册与发现:适配 Spring Cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。
- 分布式配置管理:支持分布式系统中的外部化配置,配置更改时自动刷新。
- 消息驱动能力:基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。
- 分布式事务:使用 @GlobalTransactional 注解, 高效并且对业务零侵入地解决分布式事务问题。。
- 阿里云对象存储:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。
- 分布式任务调度:提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。同时提供分布式的任务执行模型,如网格任务。网格任务支持海量子任务均匀分配到所有 Worker(schedulerx-client)上执行。
- 阿里云短信服务:覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道
下载
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Nacos服务注册和配置中心
Nacos:注册中心+配置中心
替代Eureka做注册中心,替代Config做配置中心
官方文档:nacos.io/zh-cn/
Nacos安装
下载地址:github.com/alibaba/nac… 或者百度云下载pan.baidu.com/s/1186nmlqP… 验证码:rest
解压运行即可,验证 http://localhost:8848/nacos
docker安装
[root@cbbgs ~]# docker pull docker.io/nacos/nacos-server
Using default tag: latest
latest: Pulling from nacos/nacos-server
5ad559c5ae16: Pull complete
e6d451344e2a: Pull complete
b4c15146d205: Pull complete
ce7d16db8053: Pull complete
3c588a7e0a56: Pull complete
19c711321114: Pull complete
d5f56a3318c0: Pull complete
4966d7169362: Pull complete
f97f03ae04b8: Pull complete
86b0718f6d82: Pull complete
925ba62ff508: Pull complete
Digest: sha256:c475da3829ff4568668bc47c9136168ffe93b06be8a4271627d68a68e70f5b98
Status: Downloaded newer image for nacos/nacos-server:latest
docker.io/nacos/nacos-server:latest
[root@cbbgs ~]# docker run --env MODE=standalone --name nacos -d -p 8848:8848 nacos/nacos-server
dc4dc9f4b34a7df5d584a2707862ac9636fc9c687ffea3b1dfeaa21c3ede2eeb
[root@cbbgs ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0d671962f6d2 redis "docker-entrypoint.s…" 3 hours ago Up 3 hours 0.0.0.0:6379->6379/tcp distracted_khayyam
824db89b0893 openzipkin/zipkin "start-zipkin" 3 hours ago Up 3 hours (healthy) 9410/tcp, 0.0.0.0:9411->9411/tcp zipkin
2f3d2671aa1a mysql "docker-entrypoint.s…" 3 hours ago Up 3 hours 0.0.0.0:3306->3306/tcp, 33060/tcp mysql8
#我们查看发现并没有运行成功!查看日志发现
docker logs dc4dc9f4b34a
nacos is starting,you can check the /home/nacos/logs/start.out
OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x0000000080000000, 1073741824, 0) failed; error='Cannot allocate memory' (errno=12)
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 1073741824 bytes for committing reserved memory.
# An error report file with more information is saved as:
# /home/nacos/hs_err_pid20.log
###内存不足怎么解决呢?
#删掉,之前容器
#不作任何修改.启动时,默认内存参数是-Xms512m -Xmx512m -Xmn256m
#解决办法:修改内存参数
#重新运行
docker run -e JVM_XMS=256m -e JVM_XMX=256m --env MODE=standalone --name nacos -d -p 8848:8848 nacos/nacos-server
访问测试:http://47.93.49.117:8848/nacos/index.html#/login nacos/nacos
Nacos之服务提供者注册
1、创建cloudalibaba-provider-payment9001
2、父项目依赖加上
<!-- 统一管理jar包版本 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
<mysql.version>8.0.22</mysql.version>
<druid.version>1.1.16</druid.version>
<mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
</properties>
<!-- 子模块继承之后,提供作用:锁定版本+子modlue不用写groupId和version -->
<dependencyManagement>
<dependencies>
<!--spring boot 2.2.2-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--spring cloud Hoxton.SR1-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--spring cloud alibaba 2.1.0.RELEASE-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.spring.boot.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
</dependencyManagement>
3、9001的依赖
<dependencies>
<!--SpringCloud ailibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringBoot整合Web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--日常通用jar包配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>
4、配置文件
server:
port: 9001
spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
server-addr: 47.93.49.117:8848 #配置Nacos地址
management:
endpoints:
web:
exposure:
include: '*'
5、主启动类
@EnableDiscoveryClient
@SpringBootApplication
public class PaymentMain9001
{
public static void main(String[] args) {
SpringApplication.run(PaymentMain9001.class, args);
}
}
6、controller
@RestController
public class PaymentController
{
@Value("${server.port}")
private String serverPort;
@GetMapping(value = "/payment/nacos/{id}")
public String getPayment(@PathVariable("id") Integer id)
{
return "nacos registry, serverPort: "+ serverPort+"\t id"+id;
}
}
6、测试
启动9001,登录nacos http://47.93.49.117:8848/nacos/index.html#/login
我们按照9001,我们再建一个cloudalibaba-provider-payment9002
Nacos消费者注册 和负载
Nacos自带负载均衡
1、创建cloudalibaba-consumer-nacos-order83
2、依赖
<dependencies>
<!--SpringCloud ailibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!-- SpringBoot整合Web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--日常通用jar包配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>
3、配置文件
server:
port: 83
spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: 47.93.49.117:8848
#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)
service-url:
nacos-user-service: http://nacos-payment-provider
4、主启动类
@EnableDiscoveryClient
@SpringBootApplication
public class OrderNacosMain83
{
public static void main(String[] args)
{
SpringApplication.run(OrderNacosMain83.class,args);
}
}
5、controller
@RestController
@Slf4j
public class OrderNacosController
{
@Resource
private RestTemplate restTemplate;
@Value("${service-url.nacos-user-service}")
private String serverURL;
@GetMapping(value = "/consumer/payment/nacos/{id}")
public String paymentInfo(@PathVariable("id") Long id)
{
return restTemplate.getForObject(serverURL+"/payment/nacos/"+id,String.class);
}
}
6、配置类
@Configuration
public class ApplicationContextConfig
{
@Bean
@LoadBalanced
public RestTemplate getRestTemplate()
{
return new RestTemplate();
}
}
7、测试
启动9001,9002,83,登录nacos页面

Nacos之服务配置中心
基础配置
1、新建cloudalibaba-config-nacos-client3377
2、导入依赖
<dependencies>
<!--nacos-config-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--nacos-discovery-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--web + actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--一般基础配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>
3、书写配置文件
bootstrap.yml
# nacos配置
server:
port: 3377
spring:
application:
name: nacos-config-client
cloud:
nacos:
discovery:
server-addr: 47.93.49.117:8848 #Nacos服务注册中心地址
config:
server-addr: 47.93.49.117:8848 #Nacos作为配置中心地址
file-extension: yaml #指定yaml格式的配置
#group: DEV_GROUP
#namespace: 7d8f0f5a-6a53-4785-9686-dd460158e5d4
# ${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}
# nacos-config-client-dev.yaml
# nacos-config-client-test.yaml ----> config.info
application.yml
spring:
profiles:
active: dev # 表示开发环境
#active: test # 表示测试环境
#active: info
4、启动类
@EnableDiscoveryClient
@SpringBootApplication
public class NacosConfigClientMain3377
{
public static void main(String[] args) {
SpringApplication.run(NacosConfigClientMain3377.class, args);
}
}
5、业务类
@RestController
@RefreshScope //支持Nacos的动态刷新功能。
public class ConfigClientController
{
@Value("${config.info}")
private String configInfo;
@GetMapping("/config/info")
public String getConfigInfo() {
return configInfo;
}
}
6、云端配置文件,也就是在nacos面板添加 cbbgs.cn:8848/nacos/index…
7、测试;启动3377
并且nacos自带自动刷新!
只需要在controller添加注解@RefreshScope //支持Nacos的动态刷新功能。
Nacos集群配置和持久化
Nacos集群部署
1个Nginx,三个Nacos,一个mysql
Nacos默认自带 嵌入式数据库derby,如果集群部署数据就会不一致。
1、执行mysql脚本,windows下载的Nacos压缩包就带有mysql脚本。
或者是官方的数据库脚本。
2、修改本地安装的配置文件。我安装的是dockerhttps://github.com/alibaba/nacos/blob/master/distribution/conf/application.properties
找到关于数据库的配置。
#####配置文件application.properties
#
# Copyright 1999-2018 Alibaba Group Holding Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#*************** Spring Boot Related Configurations ***************#
### Default web context path:
server.servlet.contextPath=/nacos
### Default web server port:
server.port=8848
#*************** Network Related Configurations ***************#
### If prefer hostname over ip for Nacos server addresses in cluster.conf:
# nacos.inetutils.prefer-hostname-over-ip=false
### Specify local server's IP:
# nacos.inetutils.ip-address=
#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
spring.datasource.platform=mysql
### Count of DB:
db.num=1
### Connect URL of DB:
db.url.0=jdbc:mysql://192.168.40.128:3306/nacos-mysql?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=123456
### Connection pool configuration: hikariCP
db.pool.config.connectionTimeout=30000
db.pool.config.validationTimeout=10000
db.pool.config.maximumPoolSize=20
db.pool.config.minimumIdle=2
#*************** Naming Module Related Configurations ***************#
### Data dispatch task execution period in milliseconds:
# nacos.naming.distro.taskDispatchPeriod=200
### Data count of batch sync task:
# nacos.naming.distro.batchSyncKeyCount=1000
### Retry delay in milliseconds if sync task failed:
# nacos.naming.distro.syncRetryDelay=5000
### If enable data warmup. If set to false, the server would accept request without local data preparation:
# nacos.naming.data.warmup=true
### If enable the instance auto expiration, kind like of health check of instance:
# nacos.naming.expireInstance=true
nacos.naming.empty-service.auto-clean=true
nacos.naming.empty-service.clean.initial-delay-ms=50000
nacos.naming.empty-service.clean.period-time-ms=30000
#*************** CMDB Module Related Configurations ***************#
### The interval to dump external CMDB in seconds:
# nacos.cmdb.dumpTaskInterval=3600
### The interval of polling data change event in seconds:
# nacos.cmdb.eventTaskInterval=10
### The interval of loading labels in seconds:
# nacos.cmdb.labelTaskInterval=300
### If turn on data loading task:
# nacos.cmdb.loadDataAtStart=false
#*************** Metrics Related Configurations ***************#
### Metrics for prometheus
#management.endpoints.web.exposure.include=*
### Metrics for elastic search
management.metrics.export.elastic.enabled=false
#management.metrics.export.elastic.host=http://localhost:9200
### Metrics for influx
management.metrics.export.influx.enabled=false
#management.metrics.export.influx.db=springboot
#management.metrics.export.influx.uri=http://localhost:8086
#management.metrics.export.influx.auto-create-db=true
#management.metrics.export.influx.consistency=one
#management.metrics.export.influx.compressed=true
#*************** Access Log Related Configurations ***************#
### If turn on the access log:
server.tomcat.accesslog.enabled=true
### The access log pattern:
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i %{Request-Source}i
### The directory of access log:
server.tomcat.basedir=
#*************** Access Control Related Configurations ***************#
### If enable spring security, this option is deprecated in 1.2.0:
#spring.security.enabled=false
### The ignore urls of auth, is deprecated in 1.2.0:
nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
### The auth system to use, currently only 'nacos' is supported:
nacos.core.auth.system.type=nacos
### If turn on auth system:
nacos.core.auth.enabled=false
### The token expiration in seconds:
nacos.core.auth.default.token.expire.seconds=18000
### The default token:
nacos.core.auth.default.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
### Turn on/off caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay.
nacos.core.auth.caching.enabled=true
### Since 1.4.1, Turn on/off white auth for user-agent: nacos-server, only for upgrade from old version.
nacos.core.auth.enable.userAgentAuthWhite=true
### Since 1.4.1, worked when nacos.core.auth.enabled=true and nacos.core.auth.enable.userAgentAuthWhite=false.
### The two properties is the white list for auth and used by identity the request from other server.
nacos.core.auth.server.identity.key=
nacos.core.auth.server.identity.value=
#*************** Istio Related Configurations ***************#
### If turn on the MCP server:
nacos.istio.mcp.server.enabled=false
###*************** Add from 1.3.0 ***************###
#*************** Core Related Configurations ***************#
### set the WorkerID manually
# nacos.core.snowflake.worker-id=
### Member-MetaData
# nacos.core.member.meta.site=
# nacos.core.member.meta.adweight=
# nacos.core.member.meta.weight=
### MemberLookup
### Addressing pattern category, If set, the priority is highest
# nacos.core.member.lookup.type=[file,address-server]
## Set the cluster list with a configuration file or command-line argument
# nacos.member.list=192.168.16.101:8847?raft_port=8807,192.168.16.101?raft_port=8808,192.168.16.101:8849?raft_port=8809
## for AddressServerMemberLookup
# Maximum number of retries to query the address server upon initialization
# nacos.core.address-server.retry=5
## Server domain name address of [address-server] mode
# address.server.domain=jmenv.tbsite.net
## Server port of [address-server] mode
# address.server.port=8080
## Request address of [address-server] mode
# address.server.url=/nacos/serverlist
#*************** JRaft Related Configurations ***************#
### Sets the Raft cluster election timeout, default value is 5 second
# nacos.core.protocol.raft.data.election_timeout_ms=5000
### Sets the amount of time the Raft snapshot will execute periodically, default is 30 minute
# nacos.core.protocol.raft.data.snapshot_interval_secs=30
### raft internal worker threads
# nacos.core.protocol.raft.data.core_thread_num=8
### Number of threads required for raft business request processing
# nacos.core.protocol.raft.data.cli_service_thread_num=4
### raft linear read strategy. Safe linear reads are used by default, that is, the Leader tenure is confirmed by heartbeat
# nacos.core.protocol.raft.data.read_index_type=ReadOnlySafe
### rpc request timeout, default 5 seconds
# nacos.core.protocol.raft.data.rpc_request_timeout_ms=5000
####操作步骤
[root@cbbgs ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5d9a27b9e400 nacos/nacos-server "bin/docker-startup.…" 13 hours ago Up 13 hours 0.0.0.0:8848->8848/tcp nacos
0d671962f6d2 redis "docker-entrypoint.s…" 16 hours ago Up 16 hours 0.0.0.0:6379->6379/tcp distracted_khayyam
824db89b0893 openzipkin/zipkin "start-zipkin" 16 hours ago Up 16 hours (healthy) 9410/tcp, 0.0.0.0:9411->9411/tcp zipkin
2f3d2671aa1a mysql "docker-entrypoint.s…" 16 hours ago Up 16 hours 0.0.0.0:3306->3306/tcp, 33060/tcp mysql8
[root@cbbgs ~]# docker exec -it ^C
[root@cbbgs ~]# docker exec -it 5d9a27b9e400 /bin/bash
[root@5d9a27b9e400 nacos]# cd conf
[root@5d9a27b9e400 conf]# rm -rf application.properties #我们删掉以前的配置
[root@5d9a27b9e400 conf]# ls
1.4.0-ipv6_support-update.sql nacos-logback.xml schema.sql
[root@5d9a27b9e400 conf]# vim application.properties
[root@cbbgs ~]# docker restart 5d9a27b9e400 #重启docker
重新链接 cbbgs.cn:8848/nacos发现以前的数….
这样配置好了一台nacos,我们需要三台,我们紧接着用docke的nacos容器run其余两台不一样的容器
#我们已经安装好了8848,我们接下来安装8847,8849,用配置8848同样的方法安装其余两台nacos
docker run -e JVM_XMS=256m -e JVM_XMX=256m -d -p 8847:8848 nacos/nacos-server
docker run -e JVM_XMS=256m -e JVM_XMX=256m --env MODE=standalone -e NACOS_SERVERS="47.93.49.117:8847 47.93.49.11:8848 47.93.49.11:8849" --name nacos8849 -d -p 8849:8848 nacos/nacos-server
可以配合Nginx使用,学生机无法演示,只能运行一个nacos.采坑。
Sentinel实现熔断与限流
是什么
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。
docker安装sentinel
[root@cbbgs ~]# docker pull anjia0532/sentinel-docker
Using default tag: latest
latest: Pulling from anjia0532/sentinel-docker
e7c96db7181b: Pull complete
f910a506b6cb: Pull complete
c2274a1a0e27: Pull complete
3efee2ecd933: Pull complete
7a4e2dd51bad: Pull complete
Digest: sha256:247b2ddb26de434bb298a9de72713ed2b22047c219eebe37e427281b86449b65
Status: Downloaded newer image for anjia0532/sentinel-docker:latest
docker.io/anjia0532/sentinel-docker:latest
[root@cbbgs ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql latest c8562eaf9d81 6 days ago 546MB
nacos/nacos-server latest 9c0b55a5ab2c 9 days ago 935MB
redis latest 621ceef7494a 11 days ago 104MB
openzipkin/zipkin latest 9b4acc3eb019 4 weeks ago 150MB
anjia0532/sentinel-docker latest 5df305072cec 13 months ago 127MB
[root@cbbgs ~]# docker run -d -p 8858:8080 anjia0532/sentinel-docker
bd9d6cff6bb1a52da72a16044d2d4db42673b67a4b40323c27cf8c34df43bff5
[root@cbbgs ~]# docker ps
访问界面:cbbgs.cn:8858/
百度网盘地址:
部署二:
用Dockerfile和运行的jar包
FROM java:8
COPY *.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
[root@cbbgs sentinel]# docker build -t sentinel .
Sending build context to Docker daemon 21.2MB
Step 1/5 : FROM java:8
8: Pulling from library/java
5040bd298390: Pull complete
fce5728aad85: Pull complete
76610ec20bf5: Pull complete
60170fec2151: Pull complete
e98f73de8f0d: Pull complete
11f7af24ed9c: Pull complete
49e2d6393f32: Pull complete
bb9cdec9c7f3: Pull complete
Digest: sha256:c1ff613e8ba25833d2e1940da0940c3824f03f802c449f3d1815a66b7f8c0e9d
Status: Downloaded newer image for java:8
---> d23bdf5b1b1b
Step 2/5 : COPY *.jar /app.jar
---> e633c39ec4c0
Step 3/5 : CMD ["--server.port=8080"]
---> Running in 82fe8bb195dd
Removing intermediate container 82fe8bb195dd
---> 77603d1b4674
Step 4/5 : EXPOSE 8080
---> Running in 8b0de37000bf
Removing intermediate container 8b0de37000bf
---> ff60683a144a
Step 5/5 : ENTRYPOINT ["java","-jar","/app.jar"]
---> Running in a1bab61e9211
Removing intermediate container a1bab61e9211
---> cecefdcb8491
Successfully built cecefdcb8491
Successfully tagged sentinel:latest
[root@cbbgs sentinel]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
sentinel latest cecefdcb8491 34 seconds ago 664MB
mysql latest c8562eaf9d81 6 days ago 546MB
nacos/nacos-server latest 9c0b55a5ab2c 9 days ago 935MB
redis latest 621ceef7494a 12 days ago 104MB
openzipkin/zipkin latest 9b4acc3eb019 4 weeks ago 150MB
anjia0532/sentinel-docker latest 5df305072cec 13 months ago 127MB
java 8 d23bdf5b1b1b 4 years ago 643MB
[root@cbbgs sentinel]# docker stop 5df305072cec
Error response from daemon: No such container: 5df305072cec
[root@cbbgs sentinel]# docker stop 5df305072cec
Error response from daemon: No such container: 5df305072cec
[root@cbbgs sentinel]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bd9d6cff6bb1 anjia0532/sentinel-docker "/bin/sh -c 'java ${…" 5 hours ago Up 4 hours 0.0.0.0:8858->8080/tcp busy_swartz
6ee306084739 nacos/nacos-server "bin/docker-startup.…" 5 hours ago Up 4 hours 0.0.0.0:8848->8848/tcp nacos
2f3d2671aa1a mysql "docker-entrypoint.s…" 25 hours ago Up 4 hours 0.0.0.0:3306->3306/tcp, 33060/tcp mysql8
[root@cbbgs sentinel]# docker stop bd9d6cff6bb1
bd9d6cff6bb1
[root@cbbgs sentinel]# docker run -d -p 8858:8080 sentinel
e1705e812540dd2737a6d85a0af7514968002160eec52ef32d6a610eafb73b1d
[root@cbbgs sentinel]# docker ps
sentinel初始化监控
1、创建cloudalibaba-sentinel-service8401
2、导入依赖
<dependencies>
<dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--SpringCloud ailibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<!--SpringCloud ailibaba sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- SpringBoot整合Web组件+actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--日常通用jar包配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.6.3</version>
</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>
3、配置文件
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: cbbgs.cn:8848 #Nacos服务注册中心地址
sentinel:
transport:
dashboard: cbbgs.cn:8858 #配置Sentinel dashboard地址
#clientIp: localhost #监控的主机,开发时是本机
port: 8719
eager: true
management:
endpoints:
web:
exposure:
include: '*'
4、启动类
@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401
{
public static void main(String[] args) {
SpringApplication.run(MainApp8401.class, args);
}
}
5、业务类
conrtoller
@RestController
@Slf4j
public class FlowLimitController
{
@GetMapping("/testA")
public String testA()
{
return "------testA";
}
@GetMapping("/testB")
public String testB()
{
log.info(Thread.currentThread().getName()+"\t"+"...testB");
return "------testB";
}
}
6、测试,先访问 http://localhost:8401/testA
因为远程端的sentinel还没有解决,先用本地的sentinel演示
流控规则
流控模式
1、QPS直接失败:每秒请求数

解释
我们设置阈值为1,意思就是每一秒只能请求一次,如果一秒内的请求次数超过阈值就会失败!
2、线程数
是当线程数达到阈值的时候就限流。
将线程数设为1,我们开两个浏览器模拟一下两个线程。在controller里新增一个方法,我们让这个方法延迟执行
@GetMapping("/testD")
public String testD()
{
try { TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("testD 测试RT");
log.info("testD 异常比例");
//int age = 10/0;
return "------testD";
}
3、关联
A惹事,B跟着挂。比如支付接口要崩了,就限制下单的接口不演示。
4、预热
一个系统的访问量突然暴涨,可能会把系统击垮,需要慢慢的上涨,也就是预热。
5、排队
一个一个来执行
sentinel降级

sentinel熔断技术没有半开技术。
1、RT(平均响应时间)
平均响应时间( DEGRADE_GRADE_RT):当1s内持续进入5个请求,对应时刻的平均响应时间(秒 级)均超过阈值(count,以ms为单位),那么在接下的时间窗口(DegradeRule中的timewindow,以s为单位)之内,对这个方法的调用都会自动地熔断(抛出 DegradeException )。注意Sentinel默认统计的RT上限是4900 ms,超出此阈值的都会算作4900 ms,若需要变更此上限可以通过启动配置项-Dcsp.sentinel.statistic.max.rt=x来配置。
我们用testD来测试
一秒打进来10个线程(大于5个)调用D,我们希望200毫秒完成任务。
永远一秒钟打进来10个线程(大于5个了)调用testD,我们希望200毫秒处理完本次任务, 后续我停止jmeter,没有这么大的访问量了,断路器关闭(保险丝恢复),微服务恢复OK 如果超过200毫秒还没处理完,在未来1秒钟的时间窗口内,断路器打开(保险丝跳闸)微服务不可用,保险丝跳闸断电了
2、异常比例
异常比例( DEGRADE_GRADE_EXCEPTION_RATIO):当资源的每秒请求量>=5,并且每秒异常总数占通过量的比值超过阈值(DegradeRule中的count)之后,资源进入降级状态,即在接下的时间窗口( DegradeRule中的 timewindow,以s为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是[0.0,1.0],代表0%- 100%。4900 ms,若需要变更此上限可以通过启动配置项-Dcsp.sentinel.statistic.max.rt=x来配置。
我们新增一个在testD int age = 10/0;
单独访问一次,必然来一次报错一次(int age = 10/0),调一次错一次; 异常比例(DEGRADE_GRADE_EXCEPTION_RATI0 )∶当资源的每秒请求量>=5,并且每秒异常总数占通过量的比值超过阈值(DegradeRule中的count)之后,资源进入降级状态,即在接下的时间窗口( DegradeRule中的timeWindow,以s为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是[0.0,1.0],代表0%- 100%。开启jmeter后,直接高并发发送请求,多次调用达到我们的配置条件了。断路器开启(保险丝跳闸),微服务不可用了,不再报错error而是服务降级了。
3、异常数
异常数(DEGRADF_GRADF_EXCEPTION_COUNT):当资源近1分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若timeWindow 小于60s,则结束熔断状态后仍可能 再进入熔断状态。
我们新增:
@GetMapping("/testE")
public String testE()
{
log.info("testE 测试异常数");
int age = 10/0;
return "------testE 测试异常数";
}
访问错误的数据5次之后进行熔断
热点key
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
- 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
- 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。 热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
兜底的方法:
- 系统默认的方法
- 客户自定义的方法 之前的case,限流出问题后,都是用sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
那么我们能不能自定?类似Hystrix,某个方法出问题了,就找对应的兜底降级方法?
从HystrixCommond到@SentinelResource
Sentinel热点参数限流
在controller新增
/*
* 对 p1,p2进行监控
*
* */
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")//一个是唯一标识,blockHandler是处理的方法,兜底的方法
public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
@RequestParam(value = "p2",required = false) String p2)
{
//int age = 10/0;
return "------testHotKey";
}
//兜底的方法
public String deal_testHotKey (String p1, String p2, BlockException exception)
{
return "------deal_testHotKey,o(╥﹏╥)o"; //sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
}
我猛点,请求次数超过了请求的阈值,发生了错误。直接执行兜底的错误
参数例外项
SentinelResource
增加一个方法:RateLimitController.java
@RestController
public class RateLimitController
{
@GetMapping("/byResource")
@SentinelResource(value = "byResource",blockHandler = "handleException")
public CommonResult byResource()
{
return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
}
public CommonResult handleException(BlockException exception)
{
return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用");
}
@GetMapping("/rateLimit/byUrl")
@SentinelResource(value = "byUrl")
public CommonResult byUrl()
{
return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
}
/* @GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class,
blockHandler = "handlerException2")
public CommonResult customerBlockHandler()
{
return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003"));
}*/
}
这样就算一秒钟请求达到了1,也不会被限。
按资源名称限制没有斜杠
当我们不写兜底方案时,就会用系统自带的。
客户自定义的处理限流逻辑
我自定义一个CustomerBlockHandler类
public class CustomerBlockHandler
{
public static CommonResult handlerException(BlockException exception)
{
return new CommonResult(4444,"按客戶自定义,global handlerException----1");
}
public static CommonResult handlerException2(BlockException exception)
{
return new CommonResult(4444,"按客戶自定义,global handlerException----2");
}
}
在RateLimitController添加方法
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class, //兜底的类在哪里
blockHandler = "handlerException2") //这个兜底类的那个方法
public CommonResult customerBlockHandler()
{
return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003"));
}
服务熔断
不再复制代码!!!
@SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler",
//fallback 是业务异常。 //blockHandler只负责sentinel控制台配置违规
@RequestMapping("/consumer/fallback/{id}")
//@SentinelResource(value = "fallback") //没有配置
//@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
//@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
@SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler",
exceptionsToIgnore = {IllegalArgumentException.class})
public CommonResult<Payment> fallback(@PathVariable Long id)
{
CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);
if (id == 4) {
throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
}else if (result.getData() == null) {
throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
}
return result;
}
//本例是fallback
public CommonResult handlerFallback(@PathVariable Long id,Throwable e) {
Payment payment = new Payment(id,"null");
return new CommonResult<>(444,"兜底异常handlerFallback,exception内容 "+e.getMessage(),payment);
}
//本例是blockHandler
public CommonResult blockHandler(@PathVariable Long id,BlockException blockException) {
Payment payment = new Payment(id,"null");
return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException "+blockException.getMessage(),payment);
}
忽略属性:
//nacos-payment-provider 服务提供者的服务名 PaymentFallbackService 兜底的类
@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)
public interface PaymentService
{
@GetMapping(value = "/paymentSQL/{id}")//需要调用的方法
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}