Dubbo Nacos Sentinel 整合使用
nacos-dubbo-sentinel-provider: 工程 将dubbo 调用接口映射到Sentinel 控制管理后台管理,并且根据nacos 配置进行刷新流控规则
gradle配置
plugins {
id 'org.springframework.boot' version '2.2.11.RELEASE'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
}
ext {
set('springCloudAlibabaVersion', "2.2.1.RELEASE")
}
dependencies {
implementation 'com.alibaba.cloud:spring-cloud-starter-dubbo'
implementation 'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config'
implementation 'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery'
implementation 'com.alibaba.cloud:spring-cloud-starter-alibaba-sentinel'
implementation 'com.alibaba.csp:sentinel-datasource-nacos'
implementation 'com.alibaba.csp:sentinel-apache-dubbo-adapter'
implementation project(':alibb-dubbo-mineserviceapi')//依赖同一个父模块的子模块
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
dependencyManagement {
imports {
mavenBom "com.alibaba.cloud:spring-cloud-alibaba-dependencies:${springCloudAlibabaVersion}"
}
}
boostrap.properties
#bootstrap.properties -> bootstrap.yml -> application.properties -> application.yml ,加载顺序
#因为需要启动的时候初始化(配置中心)配置(因为需要先初始化配置),所以关于配置nacos的配置放在这,这样才能去nacos配置中心拿到相关的数据
#配置中心的地址
spring.cloud.nacos.config.server-addr=ip:port
# DataID属性的值为配置文件名格式为:${prefix}-${spring.profile.active}.${file-extension}
#nacos 配置中心配置的 dataId的命名得加上后缀
#在${prefix} 通过 spring.cloud.nacos.config.prefix 定义,没有定义的时候默认是spring.application.name
#spring.profile.active 当前的环境的配置,没有定义,则对应的连接符- 也不会存在->${prefix}.${file-extension}
#file-extension 配置文件的后缀,也代表了这个配置的配置内容的格式
spring.cloud.nacos.config.file-extension=yaml
#spring.cloud.nacos.config.prefix=nacos-dubbo-sentinel-provider
# nacos 数据模型
#namespace命名空间->Group->services/dataId ,主要的目的都是为了数据隔离(配置的隔离)
#namespace:命名空间,对不同的环境(一定要求)进行隔离
#group:分组,将若干服务或配置集(配置文件)归为一组,通常这些服务或者配置有一定的共同点(按区分的要求)
#service:服务,一个提供服务的应用实例(比如java实例),不同namespace的不能相互调用
#dataId:配置或者一组配置的集合(配置文件)
spring.cloud.nacos.config.namespace=public
spring.cloud.nacos.config.group=DEFULT_GROUP
application.properties
server.port=8082
dubbo.application.id=nacos-dubbo-sentinel-provider
dubbo.application.name=nacos-dubbo-sentinel-provider
spring.application.name=nacos-dubbo-sentinel-provider
#sentinel 控制台地址
spring.cloud.sentinel.transport.dashboard=127.0.0.1:8888
#本地与控制台连接的占用本地的端口
spring.cloud.sentinel.transport.port=9501
#注册地址 nacos 做注册中心
dubbo.protocol.name=dubbo
dubbo.protocol.port=9101
dubbo.registry.address=spring-cloud://ip
spring.cloud.nacos.discovery.server-addr=ip:port
dubbo.cloud.subscribed-services=
#sentinel 数据源配置
#配置流控规则
spring.cloud.sentinel.datasource.flow.nacos.server-addr=ip:port
spring.cloud.sentinel.datasource.flow.nacos.data-id=${spring.application.name}-flow-rules
spring.cloud.sentinel.datasource.flow.nacos.group-id=SENTINEL_GROUP
spring.cloud.sentinel.datasource.flow.nacos.rule-type=flow
package com.study.nacosdubbosentinelprovider;
import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@DubboComponentScan//记得加不然会报一个说 ip 拼写错误的错
@EnableDiscoveryClient
public class NacosDubboSentinelProviderApplication {
public static void main(String[] args) {
SpringApplication.run(NacosDubboSentinelProviderApplication.class, args);
}
}
package com.study.nacosdubbosentinelprovider.sentineldubbo;
import com.study.alibbdubbomineserviceapi.demo.NacosDemoService;
import org.apache.dubbo.config.annotation.Service;
/**
* @Auther: jmx
* @Date: 2020/12/24 01:50
* @Description: NacosDubboProvider
* @Version 1.0.0
*/
@Service(cluster = "failfast",loadbalance="roundrobin",weight = 2)
public class SentinelDubboProvider implements NacosDemoService {
@Override
public String sayHello() {
return "SentinelDubboProvider say hello";
}
}
工程:nacos-dubbo-sentinel-consumer 消费者工程 将dubbo 调用接口映射到Sentinel 控制管理后台管理,并且根据nacos 配置进行刷新流控规则
gradle 配置
plugins {
id 'org.springframework.boot' version '2.2.11.RELEASE'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
}
ext {
set('springCloudAlibabaVersion', "2.2.1.RELEASE")
}
dependencies {
implementation 'com.alibaba.cloud:spring-cloud-starter-dubbo'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config'
implementation 'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery'
implementation 'com.alibaba.cloud:spring-cloud-starter-alibaba-sentinel'
implementation 'com.alibaba.csp:sentinel-datasource-nacos'
implementation project(':alibb-dubbo-mineserviceapi')//依赖同一个父模块的子模块
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
dependencyManagement {
imports {
mavenBom "com.alibaba.cloud:spring-cloud-alibaba-dependencies:${springCloudAlibabaVersion}"
}
}
bootstrap.properties
#bootstrap.properties -> bootstrap.yml -> application.properties -> application.yml ,加载顺序
#因为需要启动的时候初始化(配置中心)配置(因为需要先初始化配置),所以关于配置nacos的配置放在这,这样才能去nacos配置中心拿到相关的数据
#配置中心的地址
spring.cloud.nacos.config.server-addr=ip:port
# DataID属性的值为配置文件名格式为:${prefix}-${spring.profile.active}.${file-extension}
#nacos 配置中心配置的 dataId的命名得加上后缀
#在${prefix} 通过 spring.cloud.nacos.config.prefix 定义,没有定义的时候默认是spring.application.name
#spring.profile.active 当前的环境的配置,没有定义,则对应的连接符- 也不会存在->${prefix}.${file-extension}
#file-extension 配置文件的后缀,也代表了这个配置的配置内容的格式
spring.cloud.nacos.config.file-extension=yaml
#spring.cloud.nacos.config.prefix=nacos-dubbo-sentinel-consumer
# nacos 数据模型
#namespace命名空间->Group->services/dataId ,主要的目的都是为了数据隔离(配置的隔离)
#namespace:命名空间,对不同的环境(一定要求)进行隔离
#group:分组,将若干服务或配置集(配置文件)归为一组,通常这些服务或者配置有一定的共同点(按区分的要求)
#service:服务,一个提供服务的应用实例(比如java实例),不同namespace的不能相互调用
#dataId:配置或者一组配置的集合(配置文件)
spring.cloud.nacos.config.namespace=public
spring.cloud.nacos.config.group=DEFULT_GROUP
application.properties
server.port=8081
spring.application.name=nacos-dubbo-sentinel-consumer
#sentinel
#指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer
spring.cloud.sentinel.transport.port=9500
#spring.cloud.sentinel.transport.client-ip=如果有确认IP最好配置一下,不然是会有问题的
#限流规则的控制台
spring.cloud.sentinel.transport.dashboard=127.0.0.1:8888
#dubbo
dubbo.application.name=nacos-dubbo-sentinel-consumer
dubbo.application.id=nacos-dubbo-sentinel-consumer
dubbo.protocol.name=dubbo
#注册地址 nacos 做注册中心
dubbo.registry.address=spring-cloud://ip
spring.cloud.nacos.discovery.server-addr=ip:port
#关注的服务
dubbo.cloud.subscribed-services=nacos-dubbo-sentinel-provider
#spring.cloud.sentinel.filter.enabled=true
spring.mvc.servlet.load-on-startup=10
#sentinel 数据源配置
#配置流控规则
spring.cloud.sentinel.datasource.flow.nacos.server-addr=ip:port
spring.cloud.sentinel.datasource.flow.nacos.data-id=${spring.application.name}-flow-rules
spring.cloud.sentinel.datasource.flow.nacos.group-id=SENTINEL_GROUP
spring.cloud.sentinel.datasource.flow.nacos.rule-type=flow
#配置降级规则
#spring.cloud.sentinel.datasource.degrade.nacos.server-addr=ip:port
#spring.cloud.sentinel.datasource.degrade.nacos.data-id=${nacos-dubbo-sentinel-consumer}-degrade-rules
#spring.cloud.sentinel.datasource.degrade.nacos.group-id=SENTINEL_GROUP
#spring.cloud.sentinel.datasource.degrade.nacos.rule-type=degrade
#触发限流跳转页面
#spring.cloud.sentinel.block-page=
#定义资源过滤的条件
#spring.cloud.sentinel.filter.url-patterns=/**
package com.study.nacosdubbosentinelconsumer;
import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@DubboComponentScan
@EnableDiscoveryClient
public class NacosDubboSentinelConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(NacosDubboSentinelConsumerApplication.class, args);
}
}
package com.study.nacosdubbosentinelconsumer.sentineldubbo;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.AbstractSentinelInterceptor;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.SentinelWebInterceptor;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.UrlCleaner;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.study.alibbdubbomineserviceapi.demo.NacosDemoService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.HandlerMapping;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @Auther: jmx
* @Date: 2020/12/20 18:30
* @Description: SentinelDubboApi
* @Version 1.0.0
*/
//http 请求的都会被SentinelWebInterceptor 拦截然后定义资源名,所以直接到控制台后面设置规则就好了,AbstractSentinelInterceptor 这里定义资源名
@RequestMapping("/sentineldubbo")
@RefreshScope
@RestController
public class SentinelDubboApi {
@Reference(mock = "com.study.nacosdubbosentinelconsumer.sentineldubbo.mock.SentinelDubboMockProvider")
private NacosDemoService demoService;
@RequestMapping("/sayhello")
public String sayHello(String id,HttpServletRequest request) {
return demoService.sayHello();
}
@GetMapping("/get/{id}")
public String getInfo(@PathVariable("id") int id){
return id+1+ "" ;
}
}
package com.study.nacosdubbosentinelconsumer.sentineldubbo.mock;
import com.study.alibbdubbomineserviceapi.demo.NacosDemoService;
/**
* @Auther: jmx
* @Date: 2020/12/20 18:37
* @Description: SentinelDubboMockProvider NacosDemoService服务方挂掉之后用得降级服务
* @Version 1.0.0
*/
public class SentinelDubboMockProvider implements NacosDemoService {
public SentinelDubboMockProvider() {
System.out.println("SentinelDubboMockProvider created .......");
}
@Override
public String sayHello() {
return "SentinelDubboMockProvider say hello";
}
}
package com.study.nacosdubbosentinelconsumer.sentineldubbo.handler;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.UrlCleaner;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
@Service
public class DefineUrlClean implements UrlCleaner{
//在SentinelWebInterceptor 用于映射解析访问的请求地址,将其定义为正确的资源名称,在1.7版本,主要用于解决 映射/get/{id} 中 /get/1 和 /get/2 属于不同资源
//而Sentinel 默认资源数是6000,超出的将不会生效
//在1.8 中则不会 映射/get/{id} 中 /get/1 和 /get/2 定义的资源名就是 /get/{id}
@Override
public String clean(String originUrl) {
if(StringUtils.isEmpty(originUrl)){
return originUrl;
}
if (originUrl.startsWith("/sentineldubbo/get/{id}")){
return "/sentineldubbo/get/{param}";
}
return originUrl;
}
}
package com.study.nacosdubbosentinelconsumer.sentineldubbo.handler;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Service
public class DefineBlockHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
System.out.println(request.getRequestURI());
e.printStackTrace();
response.setHeader("Content-Type","application/json;charset=UTF-8");
String message = "{\n" +
"\t\"code\":10000,\n" +
"\t\"msg\":\"访问人数过多\n" +
"}";
response.getWriter().write(message);
}
}