前面我们介绍了sentinel控制台以及客户端的启动,并且实现了在控制台添加流控以及熔断规则,并且将规则发送给客户端。但是,将客户端重启,我们会发现,我们之前设置的规则将会丢失,这是因为客户端将规则保存在内存中,并没有将其持久化,因而,这样并不适用于生产环境。
下面我们介绍一下Sentinel采用Nacos数据源,将规则持久化:
控制台以及Nacos可以按照之前的博客自行启动:
启动Sentinel控制台https://blog.youkuaiyun.com/qq_26932225/article/details/88907123
启动Nacos Server https://blog.youkuaiyun.com/qq_26932225/article/details/86536837
本文的客户端demo:https://github.com/xujingle1995/Learn-SpringCloudAlibaba/tree/master/sentinel-client-nacos
Sentinel数据源
Sentinel的数据源可以通过多种方式加载:json、xml文件;zookeeper;apollo;nacos;并且可以多种数据源同时使用。
动态数据源:DataSource
扩展常见的实现方式有:
- 拉模式:客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件,甚至是 VCS 等。这样做的方式是简单,缺点是无法及时获取变更;
- 推模式:规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。
要具体了解可以查看官网的介绍:https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95
在生产环境下推荐使用推模式, 这需要设置客户端,并且需要修改Sentinel控制台的源码。
我们推荐通过控制台设置规则后将规则推送到统一的规则中心,客户端实现 ReadableDataSource
接口端监听规则中心实时获取变更,流程如下:
下面我们先介绍客户端的Nacos动态数据源配置,Nacos数据源熔断规则发生变化,自动推送到Sentinel客户端:
Sentinel客户端配置
-
引入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- Sentinel --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>0.2.1.RELEASE</version> </dependency> <!-- 用于查看Sentinel客户端相关规则 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--sentinel指定nacos为数据源 --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> <version>1.5.1</version> </dependency>
-
修改配置文件
# 设置sentinel客户端http server与控制台之间通信的端口 spring.cloud.sentinel.transport.port=8731 # 设置控制台地址 spring.cloud.sentinel.transport.dashboard=localhost:8080 # 本工程监听端口 server.port=8090 #本工程名 spring.application.name=sentinel-client # 设置Sentinel Nacos数据源配置;其中ds2是数据源名,可以自行随意修改 # Nacos数据源地址(需要启动一台Nacos Server) spring.cloud.sentinel.datasource.ds2.nacos.server-addr=172.16.10.40:8848 spring.cloud.sentinel.datasource.ds2.nacos.dataId=nacos-datasource.json spring.cloud.sentinel.datasource.ds2.nacos.groupId=DEFAULT_GROUP spring.cloud.sentinel.datasource.ds2.nacos.data-type=json spring.cloud.sentinel.datasource.ds2.nacos.rule-type=flow # 进行该项设置,可以通过http://localhost:8090/actuator/sentinel访问到该客户端的所有规则 management.endpoints.web.exposure.include=*
-
添加Nacos数据源配置类
package com.xjl.sentinel.config; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.alibaba.sentinel.SentinelProperties; import org.springframework.cloud.alibaba.sentinel.datasource.config.NacosDataSourceProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.alibaba.csp.sentinel.datasource.ReadableDataSource; import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; @Configuration public class DataSourceInitFunc { Logger logger = LoggerFactory.getLogger(DataSourceInitFunc.class); @Autowired private SentinelProperties sentinelProperties; @Bean public DataSourceInitFunc init() throws Exception { logger.info("[NacosSource初始化,从Nacos中获取熔断规则]"); sentinelProperties.getDatasource().entrySet().stream().filter(map -> { return map.getValue().getNacos() != null; }).forEach(map -> { NacosDataSourceProperties nacos = map.getValue().getNacos(); ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(nacos.getServerAddr(), nacos.getGroupId(), nacos.getDataId(), source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() { })); FlowRuleManager.register2Property(flowRuleDataSource.getProperty()); }); return new DataSourceInitFunc(); } }
-
添加资源
package com.xjl.sentinel.handler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.csp.sentinel.slots.block.BlockException; public class SentinelExceptionHandler { final static Logger logger = LoggerFactory.getLogger(SentinelExceptionHandler.class); public static String blockExceptionHandle(String name, BlockException exception) { exception.printStackTrace(); logger.info("sentinel 熔断处理 {}", "SentinelExceptionHandler"); return "Sentinel 熔断处理函数"; } }
package com.xjl.sentinel.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.RestController; import com.alibaba.csp.sentinel.EntryType; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException; import com.xjl.sentinel.handler.SentinelExceptionHandler; import com.xjl.sentinel.service.FallbackService; @RestController public class SentinelTestController { @Autowired private FallbackService service; @SentinelResource(value = "hello", entryType = EntryType.OUT, blockHandlerClass = SentinelExceptionHandler.class, blockHandler = "blockExceptionHandle") @GetMapping("/hello/{name}") public String hello(@PathVariable("name") String name) { System.out.println(name); return "hello " + name; } }
-
Nacos中添加熔断规则
规则文件可以是json文件;也可以是text文件。
[ { "app": "sentinel-client", "clusterConfig": { "fallbackToLocalWhenFail": true, "sampleCount": 10, "strategy": 0, "thresholdType": 0, "windowIntervalMs": 1000 }, "clusterMode": false, "controlBehavior": 0, "count": 3.0, "gmtCreate": 1554541390168, "gmtModified": 1554543573961, "grade": 1, "id": 4, "ip": "172.16.10.167", "limitApp": "default", "port": 8731, "resource": "hello", "strategy": 0 } ]
其中:
app的值修改为你的应用名(spring.application.name)
count可以自行修改,我这里是3.0(每秒钟最多请求3次,否则熔断) -
测试
启动客户端,请求http://localhost:8090/hello/xjl,不断刷新,若一秒钟之内点击超过3次,就会熔断
可以自行下载代码查看: https://github.com/xujingle1995/Learn-SpringCloudAlibaba/tree/master/sentinel-client-nacos
后面文章再介绍控制台的修改,实现控制台将熔断规则推送到Nacos数据源