Nacos学习笔记-Sentinel整合示例

本文介绍了如何将Sentinel与Nacos进行整合,并提供了Sentinel的下载地址和启动Sentinel Dashboard的方法。在Nacos 2.2.5.RELEASE及Sentinel 2.2.5.RELEASE版本下,展示了相关的配置示例。Sentinel支持多种数据源,其规则配置可以通过Nacos进行写入。注意,Sentinel资源名与API路径应区别开,且blockHandler和fallback的处理函数需声明为静态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Sentinel文档地址:

GitHub - alibaba/Sentinel: A powerful flow control component enabling reliability, resilience and monitoring for microservices. (面向云原生微服务的高可用流控防护组件)

介绍 · alibaba/Sentinel Wiki · GitHub

Sentinel下载地址:

https://github.com/alibaba/Sentinel/releases

SentinelDashboard

当前版本 sentinel-dashboard-1.8.1.jar,启动执行以下命令

java -jar -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -Dsentinel.dashboard.auth.username=sentinel  -Dsentinel.dashboard.auth.password=sentinel sentinel-dashboard-1.8.1.jar

浏览器访问http://localhost:8080/即可进入Sentinel控制台界面

整合示例

Nacos依赖版本:2.2.5.RELEASE

Sentinel依赖版本:2.2.5.RELEASE

<!-- Nacos依赖包 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

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

<!-- Sentinel依赖包 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

相关配置如下:

spring.cloud.nacos.discovery.register-enabled=true
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.namespace=public
spring.cloud.nacos.discovery.weight=1

spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.encode=utf-8
spring.cloud.nacos.config.group=DEFAULT_GROUP 
spring.cloud.nacos.config.file-extension=properties

spring.cloud.nacos.discovery.register-enabled=true
spring.cloud.nacos.discovery.namespace=public
spring.cloud.nacos.discovery.weight=1

## Sentinel配置
# HttpServer地址
spring.cloud.sentinel.transport.port=8719
# SentinelDashBoard地址
spring.cloud.sentinel.transport.dashboard=localhost:8080

# sentinel datasource nacos
spring.cloud.sentinel.datasource.ds1.nacos.server-addr=localhost:8848
spring.cloud.sentinel.datasource.ds1.nacos.data-id=microservice-platform-nacos-sentinel-flow-rules
spring.cloud.sentinel.datasource.ds1.nacos.group-id=DEFAULT_GROUP
spring.cloud.sentinel.datasource.ds1.nacos.data-type=json
spring.cloud.sentinel.datasource.ds1.nacos.rule-type=flow

# sentinel datasource file
#spring.cloud.sentinel.datasource.ds2.file.file=classpath:scripts/rule.json
#spring.cloud.sentinel.datasource.ds2.file.data-type=json
#spring.cloud.sentinel.datasource.ds2.file.rule-type=flow

# sentinel datasource zookeeper
#spring.cloud.sentinel.datasource.ds3.zk.path=/sentinel-example/example-flow-rules
#spring.cloud.sentinel.datasource.ds3.zk.server-addr=localhost:2181
#spring.cloud.sentinel.datasource.ds3.zk.rule-type=authority

# sentinel datasource apollo
#spring.cloud.sentinel.datasource.ds4.apollo.namespace-name=application
#spring.cloud.sentinel.datasource.ds4.apollo.flow-rules-key=sentinel
#spring.cloud.sentinel.datasource.ds4.apollo.default-flow-rule-value=test
#spring.cloud.sentinel.datasource.ds4.apollo.rule-type=param-flow

Sentinel可以支持多种数据源,数据格式如下:

[
    {
        "resource":"/user/tmp1",
        "limitAPP":"default",
        "grade":1,
        "count":1,
        "strategy":0,
        "controlBehavior":0,
        "clusterMode":false
    },
    {
        "resource":"/user/tmp2",
        "limitAPP":"default",
        "grade":1,
        "count":1,
        "strategy":0,
        "controlBehavior":0,
        "clusterMode":false
    }
]

示例代码:

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.platform.modules.user.service.IUserRemoteService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

	private Logger LOG = LoggerFactory.getLogger(UserController.class);

	@Autowired
	@Qualifier("userRemoteService")
	private IUserRemoteService userRemoteService = null;

	@RequestMapping(value = "/api/v1/user/tmp1", method = RequestMethod.GET)
	@SentinelResource(value = "/user/tmp1", blockHandler = "readUserTmp1BlockHandler", fallback = "readUserTmp1FallbackHandler")
	public Object readUserTmp1(String account, String password) {
		System.out.println(String.format("sentienl user tmp1 account:%s password:%s", account, password));
		System.out.println(1/0);
		return String.format("sentienl user tmp1 account:%s password:%s", account, password);
	}

	public Object readUserTmp1BlockHandler(String account, String password, BlockException be) {
		LOG.error(String.format("BlockHandler:%s %s %s", account, password, be.getMessage()), be);
		return String.format("BlockHandler:%s %s", account, password);
	}

	public Object readUserTmp1FallbackHandler(String account, String password, Throwable e) {
		LOG.error(String.format("FallbackHandler:%s %s %s", account, password, e.getMessage()), e);
		return String.format("FallbackHandler:%s %s", account, password);
	}

	@RequestMapping(value = "/api/v1/user/tmp2", method = RequestMethod.GET)
	@SentinelResource(value = "/user/tmp2", blockHandler = "useBlockHandler", blockHandlerClass = UserSentinelExceptionHandler.class,
		fallback = "useFallbackHandler", fallbackClass = UserSentinelExceptionHandler.class)
	public Object readUserTmp2(String account, String password) {
		System.out.println(String.format("sentienl user tmp2 account:%s password:%s", account, password));
		System.out.println(1/0);
		return String.format("sentienl user tmp2 account:%s password:%s", account, password);
	}

	@RequestMapping(value = "/api/v1/user/tmp3", method = RequestMethod.GET)
	@SentinelResource(value = "/user/tmp3", blockHandler = "useBlockHandler", blockHandlerClass = UserSentinelExceptionHandler.class,
		defaultFallback = "useDefaultFallbackHandler", fallbackClass = UserSentinelExceptionHandler.class)
	public Object readUserTmp3(String account, String password) {
		System.out.println(String.format("sentienl user tmp3 account:%s password:%s", account, password));
		System.out.println(1/0);
		return String.format("sentienl user tmp3 account:%s password:%s", account, password);
	}

	@RequestMapping(value = "/api/v1/user/tmp4", method = RequestMethod.GET)
	@SentinelResource(value = "/user/tmp4", blockHandler = "useBlockHandler", blockHandlerClass = UserSentinelExceptionHandler.class,
		fallback = "useFallbackHandler", fallbackClass = UserSentinelExceptionHandler.class)
	public Object readUserTmp4(String account, String password) {
		System.out.println(String.format("sentienl user tmp4 account:%s password:%s", account, password));
		System.out.println(1/0);
		return userRemoteService.readUser(account, password);
	}

}
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UserSentinelExceptionHandler {

    private static Logger LOG = LoggerFactory.getLogger(UserSentinelExceptionHandler.class);

    public static Object useBlockHandler(String account, String password, BlockException be) {
        LOG.error(String.format("BlockHandler:%s %s %s", account, password, be.getMessage()), be);
        return String.format("BlockHandler:%s %s %s", account, password, be.getMessage());
    }

    public static Object useFallbackHandler(String account, String password, Throwable e) {
        LOG.error(String.format("FallbackHandler:%s %s %s", account, password, e.getMessage()), e);
        return String.format("FallbackHandler:%s %s %s", account, password, e.getMessage());
    }

    public static Object useDefaultFallbackHandler(Throwable e) {
        LOG.error(String.format("DefaultFallbackHandler:%s", e.getMessage()), e);
        return String.format("DefaultFallbackHandler %s", e.getMessage());
    }

}

Sentinel规则配置写入Nacos

import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.WritableDataSource;
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.csp.sentinel.transport.util.WritableDataSourceRegistry;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Properties;

@Component
public class SentinelDataSourceNacosWriter {

    private Logger LOG = LoggerFactory.getLogger(SentinelDataSourceNacosWriter.class);

    @Value("${spring.cloud.sentinel.datasource.ds1.nacos.server-addr}")
    private String serverAddr = null;
    @Value("${spring.cloud.sentinel.datasource.ds1.nacos.group-id}")
    private String groupId = null;
    @Value("${spring.cloud.sentinel.datasource.ds1.nacos.data-id}")
    private String dataId = null;

    @PostConstruct
    public void postConstruct() throws NacosException {
        // 从Nacos配置中心读取限流规则
        // 创建NacosDataSource并将其注册至对应的RuleManager上
        ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<List<FlowRule>>(
            serverAddr, groupId, dataId, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>(){}));
        FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
        LOG.info("flow rule data source property {}", flowRuleDataSource.getProperty());
        // 自动写入 Sentinel Dashboard中修改规则同步到Nacos
        WritableDataSource writableDataSource = new NacosWritableDataSource<List<FlowRule>>(serverAddr, groupId, dataId);
        WritableDataSourceRegistry.registerFlowDataSource(writableDataSource);
    }

    /**
     * 手动写入规则
     *    "[\n"
     *    + "  {\n"
     *    + "    \"resource\": \"login\",\n"
     *    + "    \"controlBehavior\": 0,\n"
     *    + "    \"count\": 5.0,\n"
     *    + "    \"grade\": 1,\n"
     *    + "    \"limitApp\": \"default\",\n"
     *    + "    \"strategy\": 0\n"
     *    + "  }\n"
     *  + "]";
     * @param rule
     */
    public void manualWriteRule(String rule) {
        try {
            ConfigService configService = NacosFactory.createConfigService(serverAddr);
            boolean isPublish = configService.publishConfig(dataId, groupId, rule);
            LOG.info("nacos config public {} {}", rule, isPublish);
        } catch (NacosException e) {
            LOG.error(e.getMessage(), e);
        }
    }

}

class NacosWritableDataSource<T> implements WritableDataSource<T> {

    private Logger LOG = LoggerFactory.getLogger(NacosWritableDataSource.class);

    private String serverAddr = null;
    private String groupId = null;
    private String dataId = null;

    public NacosWritableDataSource(String serverAddr, String groupId, String dataId) {
        this.serverAddr = serverAddr;
        this.groupId = groupId;
        this.dataId = dataId;
    }

    //Sentinel更新的时候
    @Override
    public void write(T value) throws Exception {
        String rule = JSON.toJSONString(value);
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
        properties.put(PropertyKeyConst.NAMESPACE, "public");
        ConfigService configService = NacosFactory.createConfigService(properties);
        boolean isPublish = configService.publishConfig(dataId, groupId, rule);
        LOG.info("nacos config public {} {}", rule, isPublish);
    }

    @Override
    public void close() throws Exception {
    }

}

注意事项:

@SentinelResource的value值不要和@GetMapping的value值一样,配置Sentinel的流控或者降级的资源名应和@SentinelResource的value值一样,不要再同时配置@GetMapping中value的资源名。

blockHandler的类。对应的处理函数必须static修饰,否则无法解析。

fallback的类。对应的处理函数必须static修饰,否则无法解析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值