概述
- 本次引用版本 1.7.2 目前最新版本为1.8.0 git地址
从 Sentinel 1.4.0 开始,sentinel抽取出了接口用于向远程配置中心推送规则以及拉取规则:1.
DynamicRuleProvider<T>
: 拉取规则 2.DynamicRulePublisher<T>
: 推送规则用户需实现
DynamicRuleProvider
和DynamicRulePublisher
接口,即可实现应用维度推送
第一步,启动redis 从redis官网下载redis
第二步:sentinel-dashboard 配置修改(或者直接下载已经改好的jar )
在: com.alibaba.csp.sentinel.dashboard.rule 目录下添加新的包redis用于存放以下几个类
DegradeRuleRedisProvider.java
package com.alibaba.csp.sentinel.dashboard.rule.redis; import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity; import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.fastjson.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; /** * @package: com.alibaba.csp.sentinel.dashboard.rule.redis * @title: FlowRuleRedisProvider * @projectName: sentinel-parent * @author zhuhongqiang3 * @date: 2020-05-18 10:30 * @version: V1.0 * @retrun com.alibaba.csp.sentinel.dashboard.rule.redis.sentinel-parent */ @Component("degradeRuleRedisProvider") public class DegradeRuleRedisProvider implements DynamicRuleProvider<List<DegradeRuleEntity>> { @Autowired private RedisUtil redisConfigUtil; @Override public List<DegradeRuleEntity> getRules(String appName) throws Exception { String rules = redisConfigUtil.getString(RuleConsts.RULE_DEGRADE + appName); if (StringUtil.isEmpty(rules)) { return new ArrayList<>(); } return JSONObject.parseArray(rules,DegradeRuleEntity.class); } }
package com.alibaba.csp.sentinel.dashboard.rule.redis;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @package: com.alibaba.csp.sentinel.dashboard.rule.redis
* @title: FlowRuleRedisPublisher
* @projectName: sentinel-parent
* @author zhuhongqiang3
* @date: 2020-05-18 10:30
* @version: V1.0
* @retrun com.alibaba.csp.sentinel.dashboard.rule.redis.sentinel-parent
*/
@Component("degradeRuleRedisPublisher")
public class DegradeRuleRedisPublisher implements DynamicRulePublisher<List<DegradeRuleEntity>> {
@Autowired
private RedisUtil redisConfigUtil;
@Override
public void publish(String app, List<DegradeRuleEntity> rules) throws Exception {
AssertUtil.notEmpty(app, "app name cannot be empty");
if (rules == null) {
return;
}
String strs = JSON.toJSONString(rules);
redisConfigUtil.setString(RuleConsts.RULE_DEGRADE + app, strs);
}
}
package com.alibaba.csp.sentinel.dashboard.rule.redis;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @package: com.alibaba.csp.sentinel.dashboard.rule.redis
* @title: FlowRuleRedisProvider
* @projectName: sentinel-parent
* @description: //TODO
* @author zhuhongqiang3
* @date: 2020-05-18 10:30
* @version: V1.0
* @retrun com.alibaba.csp.sentinel.dashboard.rule.redis.sentinel-parent
*/
@Component("flowRuleRedisProvider")
public class FlowRuleRedisProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {
@Autowired
private RedisUtil redisConfigUtil;
@Override
public List<FlowRuleEntity> getRules(String appName) throws Exception {
String rules = redisConfigUtil.getString(RuleConsts.RULE_FLOW + appName);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return JSONObject.parseArray(rules,FlowRuleEntity.class);
}
}
package com.alibaba.csp.sentinel.dashboard.rule.redis;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @package: com.alibaba.csp.sentinel.dashboard.rule.redis
* @title: FlowRuleRedisPublisher
* @projectName: sentinel-parent
* @description: //TODO
* @author zhuhongqiang3
* @date: 2020-05-18 10:30
* @version: V1.0
* @retrun com.alibaba.csp.sentinel.dashboard.rule.redis.sentinel-parent
*/
@Component("flowRuleRedisPublisher")
public class FlowRuleRedisPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
@Autowired
private RedisUtil redisConfigUtil;
@Override
public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
AssertUtil.notEmpty(app, "app name cannot be empty");
if (rules == null) {
return;
}
String strs = JSON.toJSONString(rules);
redisConfigUtil.setString(RuleConsts.RULE_FLOW + app, strs);
}
}
package com.alibaba.csp.sentinel.dashboard.rule.redis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* @author zhuhongqiang3
* @package: com.alibaba.csp.sentinel.dashboard.rule.redis
* @title: RedisUtil
* @projectName: sentinel-parent
* @date: 2020-05-18 10:33
* @version: V1.0
* @retrun com.alibaba.csp.sentinel.dashboard.rule.redis.sentinel-parent
*/
@Component
public class RedisUtil {
@Autowired
private StringRedisTemplate stringRedisTemplate;
public StringRedisTemplate getStringRedisTemplate() {
return stringRedisTemplate;
}
/**
* 存放string类型
*
* @param key
* @param data
* @param timeout
*/
public void setString(String key, String data, Long timeout) {
try {
stringRedisTemplate.opsForValue().set(key, data, 7, TimeUnit.DAYS);
if (timeout != null) {
stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 存放string类型
*
* @param key
* @param data
*/
public void setString(String key, String data) {
setString(key, data, null);
}
/**
* 根据key查询string类型
*
* @param key
* @return
*/
public String getString(String key) {
String value = stringRedisTemplate.opsForValue().get(key);
return value;
}
/**
* 根据对应的key删除key
*
* @param key
*/
public Boolean delKey(String key) {
return stringRedisTemplate.delete(key);
}
}
package com.alibaba.csp.sentinel.dashboard.rule.redis;
/**
* @package: com.alibaba.csp.sentinel.dashboard.rule.redis
* @title: RuleConsts
* @projectName: sentinel-parent
* @description: //TODO
* @author zhuhongqiang3
* @date: 2020-05-18 10:33
* @version: V1.0
* @retrun com.alibaba.csp.sentinel.dashboard.rule.redis.sentinel-parent
*/
public class RuleConsts {
//流控规则key前缀
public static final String RULE_FLOW = "sentinel_rule_flow_";
//限流规则key前缀
public static final String RULE_DEGRADE = "sentinel_rule_degrade_";
//系统规则key前缀
public static final String RULE_SYSTEM = "sentinel_rule_system_";
}
替换com.alibaba.csp.sentinel.dashboard.controller.FlowControllerV1.java 内容改成以下的代码
package com.alibaba.csp.sentinel.dashboard.controller;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.AuthUser;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
import com.alibaba.csp.sentinel.dashboard.domain.Result;
import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemoryRuleRepositoryAdapter;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.fastjson.JSON;
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.*;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
/**
* Flow rule controller.
*
* @author leyou
* @author Eric Zhao
*/
@RestController
@RequestMapping(value = "/v1/flow")
public class FlowControllerV1_Mark {
private final Logger logger = LoggerFactory.getLogger(FlowControllerV1_Mark.class);
@Autowired
private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;
@Autowired
@Qualifier("flowRuleRedisProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("flowRuleRedisPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
@Autowired
private AuthService<HttpServletRequest> authService;
@Autowired
private SentinelApiClient sentinelApiClient;
@GetMapping("/rules")
public Result<List<FlowRuleEntity>> apiQueryMachineRules(HttpServletRequest request, @RequestParam String app) {
logger.info("flow触发rules()>>>>>>>>>>");
AuthUser authUser = authService.getAuthUser(request);
authUser.authTarget(app, PrivilegeType.READ_RULE);
if (StringUtil.isEmpty(app)) {
return Result.ofFail(-1, "app can't be null or empty");
}
try {
List<FlowRuleEntity> rules = ruleProvider.getRules(app);
if (rules != null && !rules.isEmpty()) {
for (FlowRuleEntity entity : rules) {
entity.setApp(app);
if (entity.getClusterConfig() != null && entity.getClusterConfig().getFlowId() != null) {
entity.setId(entity.getClusterConfig().getFlowId());
}
}
}
rules = repository.saveAll(rules);
return Result.ofSuccess(rules);
} catch (Throwable throwable) {
logger.error("Error when querying flow rules", throwable);
return Result.ofThrowable(-1, throwable);
}
}
private <R> Result<R> checkEntityInternal(FlowRuleEntity entity) {
if (entity == null) {
return Result.ofFail(-1, "invalid body");
}
if (StringUtil.isBlank(entity.getApp())) {
return Result.ofFail(-1, "app can't be null or empty");
}
if (StringUtil.isBlank(entity.getLimitApp())) {
return Result.ofFail(-1, "limitApp can't be null or empty");
}
if (StringUtil.isBlank(entity.getResource())) {
return Result.ofFail(-1, "resource can't be null or empty");
}
if (entity.getGrade() == null) {
return Result.ofFail(-1, "grade can't be null");
}
if (entity.getGrade() != 0 && entity.getGrade() != 1) {
return Result.ofFail(-1, "grade must be 0 or 1, but " + entity.getGrade() + " got");
}
if (entity.getCount() == null || entity.getCount() < 0) {
return Result.ofFail(-1, "count should be at lease zero");
}
if (entity.getStrategy() == null) {
return Result.ofFail(-1, "strategy can't be null");
}
if (entity.getStrategy() != 0 && StringUtil.isBlank(entity.getRefResource())) {
return Result.ofFail(-1, "refResource can't be null or empty when strategy!=0");
}
if (entity.getControlBehavior() == null) {
return Result.ofFail(-1, "controlBehavior can't be null");
}
int controlBehavior = entity.getControlBehavior();
if (controlBehavior == 1 && entity.getWarmUpPeriodSec() == null) {
return Result.ofFail(-1, "warmUpPeriodSec can't be null when controlBehavior==1");
}
if (controlBehavior == 2 && entity.getMaxQueueingTimeMs() == null) {
return Result.ofFail(-1, "maxQueueingTimeMs can't be null when controlBehavior==2");
}
if (entity.isClusterMode() && entity.getClusterConfig() == null) {
return Result.ofFail(-1, "cluster config should be valid");
}
return null;
}
@PostMapping("/rule")
public Result<FlowRuleEntity> apiAddFlowRule(HttpServletRequest request, @RequestBody FlowRuleEntity entity) {
logger.info("flow触发rule()>>>>>>>>>>");
AuthUser authUser = authService.getAuthUser(request);
authUser.authTarget(entity.getApp(), PrivilegeType.WRITE_RULE);
Result<FlowRuleEntity> checkResult = checkEntityInternal(entity);
if (checkResult != null) {
return checkResult;
}
entity.setId(null);
Date date = new Date();
entity.setGmtCreate(date);
entity.setGmtModified(date);
entity.setLimitApp(entity.getLimitApp().trim());
entity.setResource(entity.getResource().trim());
try {
entity = repository.save(entity);
} catch (Throwable throwable) {
logger.error("Failed to add flow rule", throwable);
return Result.ofThrowable(-1, throwable);
}
if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
logger.error("Publish flow rules failed after rule add");
}
return Result.ofSuccess(entity);
}
@PutMapping("/save.json")
public Result<FlowRuleEntity> updateIfNotNull(HttpServletRequest request, Long id, String app,
String limitApp, String resource, Integer grade,
Double count, Integer strategy, String refResource,
Integer controlBehavior, Integer warmUpPeriodSec,
Integer maxQueueingTimeMs) {
logger.info("flow触发save.json()>>>>>>>>>>");
AuthUser authUser = authService.getAuthUser(request);
authUser.authTarget(app, PrivilegeType.WRITE_RULE);
if (id == null) {
return Result.ofFail(-1, "id can't be null");
}
FlowRuleEntity entity = repository.findById(id);
if (entity == null) {
return Result.ofFail(-1, "id " + id + " dose not exist");
}
if (StringUtil.isNotBlank(app)) {
entity.setApp(app.trim());
}
if (StringUtil.isNotBlank(limitApp)) {
entity.setLimitApp(limitApp.trim());
}
if (StringUtil.isNotBlank(resource)) {
entity.setResource(resource.trim());
}
if (grade != null) {
if (grade != 0 && grade != 1) {
return Result.ofFail(-1, "grade must be 0 or 1, but " + grade + " got");
}
entity.setGrade(grade);
}
if (count != null) {
entity.setCount(count);
}
if (strategy != null) {
if (strategy != 0 && strategy != 1 && strategy != 2) {
return Result.ofFail(-1, "strategy must be in [0, 1, 2], but " + strategy + " got");
}
entity.setStrategy(strategy);
if (strategy != 0) {
if (StringUtil.isBlank(refResource)) {
return Result.ofFail(-1, "refResource can't be null or empty when strategy!=0");
}
entity.setRefResource(refResource.trim());
}
}
if (controlBehavior != null) {
if (controlBehavior != 0 && controlBehavior != 1 && controlBehavior != 2) {
return Result.ofFail(-1, "controlBehavior must be in [0, 1, 2], but " + controlBehavior + " got");
}
if (controlBehavior == 1 && warmUpPeriodSec == null) {
return Result.ofFail(-1, "warmUpPeriodSec can't be null when controlBehavior==1");
}
if (controlBehavior == 2 && maxQueueingTimeMs == null) {
return Result.ofFail(-1, "maxQueueingTimeMs can't be null when controlBehavior==2");
}
entity.setControlBehavior(controlBehavior);
if (warmUpPeriodSec != null) {
entity.setWarmUpPeriodSec(warmUpPeriodSec);
}
if (maxQueueingTimeMs != null) {
entity.setMaxQueueingTimeMs(maxQueueingTimeMs);
}
}
Date date = new Date();
entity.setGmtModified(date);
try {
entity = repository.save(entity);
if (entity == null) {
return Result.ofFail(-1, "save entity fail");
}
} catch (Throwable throwable) {
logger.error("save error:", throwable);
return Result.ofThrowable(-1, throwable);
}
if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
logger.info("publish flow rules fail after rule update");
}
return Result.ofSuccess(entity);
}
@DeleteMapping("/delete.json")
public Result<Long> delete(HttpServletRequest request, Long id) {
logger.info("flow触发delete.json()>>>>>>>>>>");
AuthUser authUser = authService.getAuthUser(request);
if (id == null) {
return Result.ofFail(-1, "id can't be null");
}
FlowRuleEntity oldEntity = repository.findById(id);
if (oldEntity == null) {
return Result.ofSuccess(null);
}
authUser.authTarget(oldEntity.getApp(), PrivilegeType.DELETE_RULE);
try {
repository.delete(id);
} catch (Exception e) {
return Result.ofFail(-1, e.getMessage());
}
if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) {
logger.info("publish flow rules fail after rule delete");
}
return Result.ofSuccess(id);
}
private boolean publishRules(String app, String ip, Integer port) {
List<FlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
try {
rulePublisher.publish(app, rules);
logger.info("flow添加限流规则成功{}", JSON.toJSONString(rules));
} catch (Exception e) {
e.printStackTrace();
logger.warn("publishRules failed", e);
return false;
}
//核心代码,sentinel-dashboard通过http的形式进行数据推送,客户端接收后将规则保存在本地内存中
return sentinelApiClient.setFlowRuleOfMachine(app, ip, port, rules);
}
}
替换com.alibaba.csp.sentinel.dashboard.controller.DegradeController.java为以下代码
package com.alibaba.csp.sentinel.dashboard.controller; import com.alibaba.csp.sentinel.dashboard.auth.AuthAction; import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType; import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient; import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity; import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity; import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo; import com.alibaba.csp.sentinel.dashboard.domain.Result; import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemDegradeRuleStore; import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher; import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.fastjson.JSON; 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.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.util.Date; import java.util.List; /** * @author leyou */ @Controller @RequestMapping(value = "/degrade", produces = MediaType.APPLICATION_JSON_VALUE) public class DegradeController { private final Logger logger = LoggerFactory.getLogger(DegradeController.class); @Autowired private InMemDegradeRuleStore repository; @Autowired private SentinelApiClient sentinelApiClient; @Autowired @Qualifier("degradeRuleRedisProvider") private DynamicRuleProvider<List<DegradeRuleEntity>> ruleProvider; @Autowired @Qualifier("degradeRuleRedisPublisher") private DynamicRulePublisher<List<DegradeRuleEntity>> rulePublisher; @ResponseBody @RequestMapping("/rules.json") @AuthAction(PrivilegeType.READ_RULE) public Result<List<DegradeRuleEntity>> queryMachineRules(String app, String ip, Integer port) { if (StringUtil.isEmpty(app)) { return Result.ofFail(-1, "app can't be null or empty"); } if (StringUtil.isEmpty(ip)) { return Result.ofFail(-1, "ip can't be null or empty"); } if (port == null) { return Result.ofFail(-1, "port can't be null"); } try { List<DegradeRuleEntity> rules = ruleProvider.getRules(app); rules = repository.saveAll(rules); return Result.ofSuccess(rules); } catch (Throwable throwable) { logger.error("queryApps error:", throwable); return Result.ofThrowable(-1, throwable); } } @ResponseBody @RequestMapping("/new.json") @AuthAction(PrivilegeType.WRITE_RULE) public Result<DegradeRuleEntity> add(String app, String ip, Integer port, String limitApp, String resource, Double count, Integer timeWindow, Integer grade) { if (StringUtil.isBlank(app)) { return Result.ofFail(-1, "app can't be null or empty"); } if (StringUtil.isBlank(ip)) { return Result.ofFail(-1, "ip can't be null or empty"); } if (port == null) { return Result.ofFail(-1, "port can't be null"); } if (StringUtil.isBlank(limitApp)) { return Result.ofFail(-1, "limitApp can't be null or empty"); } if (StringUtil.isBlank(resource)) { return Result.ofFail(-1, "resource can't be null or empty"); } if (count == null) { return Result.ofFail(-1, "count can't be null"); } if (timeWindow == null) { return Result.ofFail(-1, "timeWindow can't be null"); } if (grade == null) { return Result.ofFail(-1, "grade can't be null"); } if (grade < RuleConstant.DEGRADE_GRADE_RT || grade > RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT) { return Result.ofFail(-1, "Invalid grade: " + grade); } DegradeRuleEntity entity = new DegradeRuleEntity(); entity.setApp(app.trim()); entity.setIp(ip.trim()); entity.setPort(port); entity.setLimitApp(limitApp.trim()); entity.setResource(resource.trim()); entity.setCount(count); entity.setTimeWindow(timeWindow); entity.setGrade(grade); Date date = new Date(); entity.setGmtCreate(date); entity.setGmtModified(date); try { entity = repository.save(entity); } catch (Throwable throwable) { logger.error("add error:", throwable); return Result.ofThrowable(-1, throwable); } if (!publishRules(app, ip, port)) { logger.info("publish degrade rules fail after rule add"); } return Result.ofSuccess(entity); } @ResponseBody @RequestMapping("/save.json") @AuthAction(PrivilegeType.WRITE_RULE) public Result<DegradeRuleEntity> updateIfNotNull(Long id, String app, String limitApp, String resource, Double count, Integer timeWindow, Integer grade) { if (id == null) { return Result.ofFail(-1, "id can't be null"); } if (grade != null) { if (grade < RuleConstant.DEGRADE_GRADE_RT || grade > RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT) { return Result.ofFail(-1, "Invalid grade: " + grade); } } DegradeRuleEntity entity = repository.findById(id); if (entity == null) { return Result.ofFail(-1, "id " + id + " dose not exist"); } if (StringUtil.isNotBlank(app)) { entity.setApp(app.trim()); } if (StringUtil.isNotBlank(limitApp)) { entity.setLimitApp(limitApp.trim()); } if (StringUtil.isNotBlank(resource)) { entity.setResource(resource.trim()); } if (count != null) { entity.setCount(count); } if (timeWindow != null) { entity.setTimeWindow(timeWindow); } if (grade != null) { entity.setGrade(grade); } Date date = new Date(); entity.setGmtModified(date); try { entity = repository.save(entity); } catch (Throwable throwable) { logger.error("save error:", throwable); return Result.ofThrowable(-1, throwable); } if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) { logger.info("publish degrade rules fail after rule update"); } return Result.ofSuccess(entity); } @ResponseBody @RequestMapping("/delete.json") @AuthAction(PrivilegeType.DELETE_RULE) public Result<Long> delete(Long id) { if (id == null) { return Result.ofFail(-1, "id can't be null"); } DegradeRuleEntity oldEntity = repository.findById(id); if (oldEntity == null) { return Result.ofSuccess(null); } try { repository.delete(id); } catch (Throwable throwable) { logger.error("delete error:", throwable); return Result.ofThrowable(-1, throwable); } if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) { logger.info("publish degrade rules fail after rule delete"); } return Result.ofSuccess(id); } private boolean publishRules(String app, String ip, Integer port) { List<DegradeRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port)); try { rulePublisher.publish(app, rules); logger.info("Degrade添加规则成功{}", JSON.toJSONString(rules)); } catch (Exception e) { e.printStackTrace(); logger.warn("publishRules failed", e); return false; } //核心代码,sentinel-dashboard通过http的形式进行数据推送,客户端接收后将规则保存在本地内存中 return sentinelApiClient.setDegradeRuleOfMachine(app, ip, port, rules); } }
第三步: 调用端配置修改
添加pom依赖 sentinel.version为1.7.2
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-parameter-flow-control</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-extension</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-web-servlet</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-cluster-server-default</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-cluster-client-default</artifactId>
<version>${sentinel.version}</version>
</dependency>
<!--sentinel end-->
修改配置文件,加入redis信息
server:
port: 9090
spring:
application:
name: sentinelApp
redis:
host: 127.0.0.1
port: 6379
password:
cloud:
sentinel:
transport:
dashboard: localhost:8080
添加初始化redis信息配置类
package com.example.sentinel_demo.config;
import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.redis.RedisDataSource;
import com.alibaba.csp.sentinel.datasource.redis.config.RedisConnectionConfig;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author zhuhongqiang3
* @package: com.example.sentinel_demo.config
* @title: RedisDataSourceConfig
* @projectName: sentinel_demo
* @description: //TODO
* @date: 2020-05-18 10:36
* @version: V1.0
* @retrun com.example.sentinel_demo.config.sentinel_demo
*/
@Component
public class RedisDataSourceConfig implements ApplicationRunner {
private static final Logger log = LoggerFactory.getLogger(RedisDataSourceConfig.class);
@Value("${spring.redis.host}")
public String redisHost;
@Value("${spring.redis.port}")
public int redisPort;
@Value("${spring.redis.password}")
public String redisPass;
//限流规则key前缀
public final String RULE_FLOW = "sentinel_rule_flow_";
public final String RULE_FLOW_CHANNEL = "sentinel_rule_flow_channel";
//降级规则key前缀
public final String RULE_DEGRADE = "sentinel_rule_degrade_";
public final String RULE_DEGRADE_CHANNEL = "sentinel_rule_degrade_channel";
//系统规则key前缀
public final String RULE_SYSTEM = "sentinel_rule_system_";
public final String RULE_SYSTEM_CHANNEL = "sentinel_rule_system_channel";
/**
* ApplicationRunner
* 该接口的方法会在服务启动之后被立即执行
* 主要用来做一些初始化的工作
* 但是该方法的运行是在SpringApplication.run(…) 执行完毕之前执行
*/
@Override
public void run(ApplicationArguments args) {
log.info(">>>>>>>>>执行sentinel规则初始化 start。。。");
RedisConnectionConfig config = RedisConnectionConfig.builder().withHost(redisHost).withPort(redisPort).withPassword(redisPass).build();
Converter<String, List<FlowRule>> parser = source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
});
String ruleAppName = RULE_FLOW + SentinelConfig.getAppName();
log.info("ruleAppName>>>" + ruleAppName);
ReadableDataSource<String, List<FlowRule>> redisDataSourceFlow = new RedisDataSource<>(config, ruleAppName, RULE_FLOW_CHANNEL, parser);
FlowRuleManager.register2Property(redisDataSourceFlow.getProperty());
Converter<String, List<DegradeRule>> parserDegrade = source -> JSON.parseObject(source, new TypeReference<List<DegradeRule>>() {
});
ReadableDataSource<String, List<DegradeRule>> redisDataSourceDegrade = new RedisDataSource<>(config, RULE_DEGRADE + SentinelConfig.getAppName(), RULE_DEGRADE_CHANNEL, parserDegrade);
DegradeRuleManager.register2Property(redisDataSourceDegrade.getProperty());
Converter<String, List<SystemRule>> parserSystem = source -> JSON.parseObject(source, new TypeReference<List<SystemRule>>() {
});
ReadableDataSource<String, List<SystemRule>> redisDataSourceSystem = new RedisDataSource<>(config, RULE_SYSTEM + SentinelConfig.getAppName(), RULE_SYSTEM_CHANNEL, parserSystem);
SystemRuleManager.register2Property(redisDataSourceSystem.getProperty());
log.info(">>>>>>>>>执行sentinel规则初始化 end。。。");
}
}
以下为测试类
package com.example.sentinel_demo.controller;
import com.example.sentinel_demo.service.impl.TestServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
/**
* @author zhuhongqiang3
* @package: com.example.sentinel_demo.controller
* @title: TestContoller
* @projectName: sentinel_demo
* @description: //TODO
* @date: 2020-03-27 14:19
* @version: V1.0
* @retrun com.example.sentinel_demo.controller.sentinel_demo
*/
@RestController
public class TestContoller {
private static final Logger logger = LoggerFactory.getLogger(TestContoller.class);
@Autowired
private TestServiceImpl service;
/**
* 功能描述: <br>
* 〈限流测试〉
*
* @param: [name]
* @return: java.lang.String
* @author: zhuhongqiang3
* @date: 2020/3/30 10:47
*/
@GetMapping(value = "/hello")
public String apiHello(@RequestParam(value = "name") String name) {
return service.sayHello(name);
}
/**
* 功能描述: <br>
* 〈降级〉
*
* @param: [name]
* @return: java.lang.String
* @author: zhuhongqiang3
* @date: 2020/3/30 10:50
*/
@GetMapping(value = "/down")
public String down(Integer name) {
System.out.println(new Date());
return service.downRule(name);
}
}
package com.example.sentinel_demo.service.impl;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.sentinel_demo.util.ExceptionUtil;
import org.springframework.stereotype.Service;
/**
* @author zhuhongqiang3
* @package: com.example.sentinel_demo.service.impl
* @title: TestServiceImpl
* @projectName: sentinel_demo
* @description: //TODO
* @date: 2020-03-30 10:34
* @version: V1.0
* @retrun com.example.sentinel_demo.service.impl.sentinel_demo
*/
@Service
public class TestServiceImpl {
/**
* 功能描述: <br>
* 〈@SentinelRestTemplate 注解的限流(blockHandler, blockHandlerClass)和降级(fallback, fallbackClass)属性不强制填写。〉
* @param:
* @return:
* @author: zhuhongqiang3
* @date: 2020/3/30 14:50
*/
/**
* 功能描述: <br>
* 〈限流策略〉
*
* @param: [name]
* @return: java.lang.String
* @author: zhuhongqiang3
* @date: 2020/3/30 10:49
*/
@SentinelResource(value = "helloRule", blockHandler = "degradeMethod")
public String sayHello(String name) {
return "Hello, " + name;
}
/**
* 限流后应用
*
* @return
*/
public String degradeMethod(String name, BlockException blockException) {
return "请求被限流,触发限流规则=" + blockException.getRule().getResource();
}
/**
* 限流后应用
*
* @return
*/
public String degradeMethod2(String name, BlockException blockException) {
return "请求被熔断,触发熔断规则=" + blockException.getRule().getResource();
}
/**
* 功能描述: <br>
* 〈降级策略〉
* 注:1.6.0 之前的版本 fallback 函数只针对降级异常(DegradeException)进行处理,不能针对业务异常进行处理
*
* @param: [name]
* @return: java.lang.String
* @author: zhuhongqiang3
* @date: 2020/3/30 10:49
*/
@SentinelResource(value = "downRule", fallback = "downMethod")
public String downRule(Integer name) {
int a = 100 / name;
return "downRule Success, " + a;
}
/**
* 降级应用
*
* @return
*/
public String downMethod(Integer name, Throwable throwable) {
throwable.printStackTrace();
System.out.println("downMethod请求被熔断,触发熔断规则=" + throwable.getMessage());
return "downMethod请求被熔断,触发熔断规则=====>>>>";
}
}
至此,步骤完成, 接下来首先启动redis, 再启动sentinel-dashboard,最后启动你自己的项目,就可以去试试配置是不是保存到redis当中了..至此,sentinel中的流量控制规则持久化完成
最后
以上就是醉熏玉米为你收集整理的Sentinel规则配置使用持久化(基于Redis)的全部内容,希望文章能够帮你解决Sentinel规则配置使用持久化(基于Redis)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复