概述
版本
1.8.1
后端
1、创建zk rule配置
修改ZookeeperConfigUtil.java
com/alibaba/csp/sentinel/dashboard/rule/zookeeper/ZookeeperConfigUtil.java
/*
* 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.
*/
package com.alibaba.csp.sentinel.dashboard.rule.zookeeper;
import org.apache.commons.lang.StringUtils;
public class ZookeeperConfigUtil {
public static final String RULE_ROOT_PATH = "/sentinel_rule_config";
public static final String DEGRADE_ROOT_PATH = "/sentinel_degrade_config";
public static final int RETRY_TIMES = 3;
public static final int SLEEP_TIME = 1000;
//流控规则使用 --把之前的流控规则中的getPath改成这个
public static String getFlowPath(String appName) {
return getPath(RULE_ROOT_PATH,appName);
}
//降级规则使用
public static String getDegradePath(String appName) {
return getPath(DEGRADE_ROOT_PATH,appName);
}
private static String getPath(String root,String appName) {
StringBuilder stringBuilder = new StringBuilder(root);
if (StringUtils.isBlank(appName)) {
return stringBuilder.toString();
}
if (appName.startsWith("/")) {
stringBuilder.append(appName);
} else {
stringBuilder.append("/")
.append(appName);
}
return stringBuilder.toString();
}
}
创建DegradeRuleZookeeperProvider.java
com/alibaba/csp/sentinel/dashboard/rule/zookeeper/degrade/DegradeRuleZookeeperProvider.java
package com.alibaba.csp.sentinel.dashboard.rule.zookeeper.degrade;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.zookeeper.ZookeeperConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.List;
@Component("degradeRuleZookeeperProvider")
public class DegradeRuleZookeeperProvider implements DynamicRuleProvider<List<DegradeRuleEntity>> {
@Autowired
private CuratorFramework zkClient;
@Autowired
private Converter<String, List<DegradeRuleEntity>> converter;
@Override
public List<DegradeRuleEntity> getRules(String appName) throws Exception {
String degradePath = ZookeeperConfigUtil.getDegradePath(appName);
Stat stat = zkClient.checkExists().forPath(degradePath);
if (stat==null) {
return Collections.emptyList();
}
byte[] bytes = zkClient.getData().forPath(degradePath);
if (null == bytes || bytes.length == 0) {
return Collections.emptyList();
}
String s = new String(bytes);
return converter.convert(s);
}
}
创建DegradeRuleZookeeperPublisher.java
com/alibaba/csp/sentinel/dashboard/rule/zookeeper/degrade/DegradeRuleZookeeperPublisher.java
@Component("degradeRuleZookeeperPublisher")
public class DegradeRuleZookeeperPublisher implements DynamicRulePublisher<List<DegradeRuleEntity>> {
@Autowired
private CuratorFramework zkClient;
@Autowired
private Converter<List<DegradeRuleEntity>, String> converter;
@Override
public void publish(String app, List<DegradeRuleEntity> rules) throws Exception {
AssertUtil.notEmpty(app, "app name cannot be empty");
String degradePath = ZookeeperConfigUtil.getDegradePath(app);
Stat stat = zkClient.checkExists().forPath(degradePath);
if (stat ==null) {
zkClient.create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT).forPath(degradePath,null);
}
byte[] data = CollectionUtils.isEmpty(rules) ? "[]".getBytes() : converter.convert(rules).getBytes();
zkClient.setData().forPath(degradePath,data);
}
}
2、创建降级规则的Controller
com/alibaba/csp/sentinel/dashboard/controller/v2/DegradeControllerV2.java
/*
* 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.
*/
package com.alibaba.csp.sentinel.dashboard.controller.v2;
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.RuleRepository;
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.slots.block.degrade.circuitbreaker.CircuitBreakerStrategy;
import com.alibaba.csp.sentinel.util.StringUtil;
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.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
/**
* Controller regarding APIs of degrade rules. Refactored since 1.8.0.
*
* @author Carpenter Lee
* @author Eric Zhao
*/
@RestController
@RequestMapping("/v2/degrade")
public class DegradeControllerV2 {
private final Logger logger = LoggerFactory.getLogger(DegradeControllerV2.class);
@Autowired
private RuleRepository<DegradeRuleEntity, Long> repository;
@Autowired
@Qualifier("degradeRuleZookeeperProvider")
private DynamicRuleProvider<List<DegradeRuleEntity>> ruleProvider;
@Autowired
@Qualifier("degradeRuleZookeeperPublisher")
private DynamicRulePublisher<List<DegradeRuleEntity>> rulePublisher;
@Autowired
private SentinelApiClient sentinelApiClient;
@GetMapping("/rules")
@AuthAction(PrivilegeType.READ_RULE)
public Result<List<DegradeRuleEntity>> apiQueryMachineRules(String app) {
if (StringUtil.isEmpty(app)) {
return Result.ofFail(-1, "app can't be null or empty");
}
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);
}
}
@PostMapping("/rule")
@AuthAction(PrivilegeType.WRITE_RULE)
public Result<DegradeRuleEntity> apiAddRule(@RequestBody DegradeRuleEntity entity) {
Result<DegradeRuleEntity> checkResult = checkEntityInternal(entity);
if (checkResult != null) {
return checkResult;
}
Date date = new Date();
entity.setGmtCreate(date);
entity.setGmtModified(date);
try {
entity = repository.save(entity);
publishRules(entity.getApp());
} catch (Throwable t) {
logger.error("Failed to add new degrade rule, app={}, ip={}", entity.getApp(), entity.getIp(), t);
return Result.ofThrowable(-1, t);
}
return Result.ofSuccess(entity);
}
@PutMapping("/rule/{id}")
@AuthAction(PrivilegeType.WRITE_RULE)
public Result<DegradeRuleEntity> apiUpdateRule(@PathVariable("id") Long id,
@RequestBody DegradeRuleEntity entity) {
if (id == null || id <= 0) {
return Result.ofFail(-1, "id can't be null or negative");
}
DegradeRuleEntity oldEntity = repository.findById(id);
if (oldEntity == null) {
return Result.ofFail(-1, "Degrade rule does not exist, id=" + id);
}
entity.setApp(oldEntity.getApp());
entity.setIp(oldEntity.getIp());
entity.setPort(oldEntity.getPort());
entity.setId(oldEntity.getId());
Result<DegradeRuleEntity> checkResult = checkEntityInternal(entity);
if (checkResult != null) {
return checkResult;
}
entity.setGmtCreate(oldEntity.getGmtCreate());
entity.setGmtModified(new Date());
try {
entity = repository.save(entity);
publishRules(oldEntity.getApp());
} catch (Throwable t) {
logger.error("Failed to save degrade rule, id={}, rule={}", id, entity, t);
return Result.ofThrowable(-1, t);
}
return Result.ofSuccess(entity);
}
@DeleteMapping("/rule/{id}")
@AuthAction(PrivilegeType.DELETE_RULE)
public Result<Long> delete(@PathVariable("id") 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);
publishRules(oldEntity.getApp());
} catch (Throwable throwable) {
logger.error("Failed to delete degrade rule, id={}", id, throwable);
return Result.ofThrowable(-1, throwable);
}
return Result.ofSuccess(id);
}
private void publishRules(String app) throws Exception {
List<DegradeRuleEntity> rules = repository.findAllByApp(app);
rulePublisher.publish(app,rules);
}
private <R> Result<R> checkEntityInternal(DegradeRuleEntity entity) {
if (StringUtil.isBlank(entity.getApp())) {
return Result.ofFail(-1, "app can't be blank");
}
if (StringUtil.isBlank(entity.getIp())) {
return Result.ofFail(-1, "ip can't be null or empty");
}
if (entity.getPort() == null || entity.getPort() <= 0) {
return Result.ofFail(-1, "invalid port: " + entity.getPort());
}
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");
}
Double threshold = entity.getCount();
if (threshold == null || threshold < 0) {
return Result.ofFail(-1, "invalid threshold: " + threshold);
}
Integer recoveryTimeoutSec = entity.getTimeWindow();
if (recoveryTimeoutSec == null || recoveryTimeoutSec <= 0) {
return Result.ofFail(-1, "recoveryTimeout should be positive");
}
Integer strategy = entity.getGrade();
if (strategy == null) {
return Result.ofFail(-1, "circuit breaker strategy cannot be null");
}
if (strategy < CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType()
|| strategy > RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT) {
return Result.ofFail(-1, "Invalid circuit breaker strategy: " + strategy);
}
if (entity.getMinRequestAmount()
== null || entity.getMinRequestAmount() <= 0) {
return Result.ofFail(-1, "Invalid minRequestAmount");
}
if (entity.getStatIntervalMs() == null || entity.getStatIntervalMs() <= 0) {
return Result.ofFail(-1, "Invalid statInterval");
}
if (strategy == RuleConstant.DEGRADE_GRADE_RT) {
Double slowRatio = entity.getSlowRatioThreshold();
if (slowRatio == null) {
return Result.ofFail(-1, "SlowRatioThreshold is required for slow request ratio strategy");
} else if (slowRatio < 0 || slowRatio > 1) {
return Result.ofFail(-1, "SlowRatioThreshold should be in range: [0.0, 1.0]");
}
} else if (strategy == RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO) {
if (threshold > 1) {
return Result.ofFail(-1, "Ratio threshold should be in range: [0.0, 1.0]");
}
}
return null;
}
}
前端
1、创建api Service文件
resources/app/scripts/services/degrade_service_v2.js
var app = angular.module('sentinelDashboardApp');
app.service('DegradeServiceV2', ['$http', function ($http) {
this.queryMachineRules = function (app, ip, port) {
var param = {
app: app,
ip: ip,
port: port
};
return $http({
url: 'v2/degrade/rules',
params: param,
method: 'GET'
});
};
this.newRule = function (rule) {
return $http({
url: 'v2/degrade/rule',
data: rule,
method: 'POST'
});
};
this.saveRule = function (rule) {
var param = {
id: rule.id,
resource: rule.resource,
limitApp: rule.limitApp,
grade: rule.grade,
count: rule.count,
timeWindow: rule.timeWindow,
statIntervalMs: rule.statIntervalMs,
minRequestAmount: rule.minRequestAmount,
slowRatioThreshold: rule.slowRatioThreshold,
};
return $http({
url: 'v2/degrade/rule/' + rule.id,
data: param,
method: 'PUT'
});
};
this.deleteRule = function (rule) {
return $http({
url: 'v2/degrade/rule/' + rule.id,
method: 'DELETE'
});
};
this.checkRuleValid = function (rule) {
if (rule.resource === undefined || rule.resource === '') {
alert('资源名称不能为空');
return false;
}
if (rule.grade === undefined || rule.grade < 0) {
alert('未知的降级策略');
return false;
}
if (rule.count === undefined || rule.count === '' || rule.count < 0) {
alert('降级阈值不能为空或小于 0');
return false;
}
if (rule.timeWindow == undefined || rule.timeWindow === '' || rule.timeWindow <= 0) {
alert('熔断时长必须大于 0s');
return false;
}
if (rule.minRequestAmount == undefined || rule.minRequestAmount <= 0) {
alert('最小请求数目需大于 0');
return false;
}
if (rule.statIntervalMs == undefined || rule.statIntervalMs <= 0) {
alert('统计窗口时长需大于 0s');
return false;
}
if (rule.statIntervalMs !== undefined && rule.statIntervalMs > 60 * 1000 * 2) {
alert('统计窗口时长不能超过 120 分钟');
return false;
}
// 异常比率类型.
if (rule.grade == 1 && rule.count > 1) {
alert('异常比率超出范围:[0.0 - 1.0]');
return false;
}
if (rule.grade == 0) {
if (rule.slowRatioThreshold == undefined) {
alert('慢调用比率不能为空');
return false;
}
if (rule.slowRatioThreshold < 0 || rule.slowRatioThreshold > 1) {
alert('慢调用比率超出范围:[0.0 - 1.0]');
return false;
}
}
return true;
};
}]);
2、 创建api Controller文件
src/main/webapp/resources/app/scripts/controllers/degrade_v2.js
var app = angular.module('sentinelDashboardApp');
app.controller('DegradeCtlV2', ['$scope', '$stateParams', 'DegradeServiceV2', 'ngDialog', 'MachineService',
function ($scope, $stateParams, DegradeService, ngDialog, MachineService) {
//初始化
$scope.app = $stateParams.app;
$scope.rulesPageConfig = {
pageSize: 10,
currentPageIndex: 1,
totalPage: 1,
totalCount: 0,
};
$scope.macsInputConfig = {
searchField: ['text', 'value'],
persist: true,
create: false,
maxItems: 1,
render: {
item: function (data, escape) {
return '<div>' + escape(data.text) + '</div>';
}
},
onChange: function (value, oldValue) {
$scope.macInputModel = value;
}
};
getMachineRules();
function getMachineRules() {
if (!$scope.macInputModel) {
return;
}
var mac = $scope.macInputModel.split(':');
DegradeService.queryMachineRules($scope.app, mac[0], mac[1]).success(
function (data) {
if (data.code == 0 && data.data) {
$scope.rules = data.data;
$scope.rulesPageConfig.totalCount = $scope.rules.length;
} else {
$scope.rules = [];
$scope.rulesPageConfig.totalCount = 0;
}
});
};
$scope.getMachineRules = getMachineRules;
var degradeRuleDialog;
$scope.editRule = function (rule) {
$scope.currentRule = angular.copy(rule);
$scope.degradeRuleDialog = {
title: '编辑降级规则',
type: 'edit',
confirmBtnText: '保存'
};
degradeRuleDialog = ngDialog.open({
template: '/app/views/dialog/degrade-rule-dialog.html',
width: 680,
overlay: true,
scope: $scope
});
};
$scope.addNewRule = function () {
var mac = $scope.macInputModel.split(':');
$scope.currentRule = {
grade: 0,
app: $scope.app,
ip: mac[0],
port: mac[1],
limitApp: 'default',
minRequestAmount: 5,
statIntervalMs: 1000,
};
$scope.degradeRuleDialog = {
title: '新增降级规则',
type: 'add',
confirmBtnText: '新增'
};
degradeRuleDialog = ngDialog.open({
template: '/app/views/dialog/degrade-rule-dialog.html',
width: 680,
overlay: true,
scope: $scope
});
};
$scope.saveRule = function () {
if (!DegradeService.checkRuleValid($scope.currentRule)) {
return;
}
if ($scope.degradeRuleDialog.type === 'add') {
addNewRule($scope.currentRule);
} else if ($scope.degradeRuleDialog.type === 'edit') {
saveRule($scope.currentRule, true);
}
};
function parseDegradeMode(grade) {
switch (grade) {
case 0:
return '慢调用比例';
case 1:
return '异常比例';
case 2:
return '异常数';
default:
return '未知';
}
}
var confirmDialog;
$scope.deleteRule = function (rule) {
$scope.currentRule = rule;
$scope.confirmDialog = {
title: '删除降级规则',
type: 'delete_rule',
attentionTitle: '请确认是否删除如下降级规则',
attention: '资源名: ' + rule.resource +
', 降级模式: ' + parseDegradeMode(rule.grade) + ', 阈值: ' + rule.count,
confirmBtnText: '删除',
};
confirmDialog = ngDialog.open({
template: '/app/views/dialog/confirm-dialog.html',
scope: $scope,
overlay: true
});
};
$scope.confirm = function () {
if ($scope.confirmDialog.type == 'delete_rule') {
deleteRule($scope.currentRule);
} else {
console.error('error');
}
};
function deleteRule(rule) {
DegradeService.deleteRule(rule).success(function (data) {
if (data.code == 0) {
getMachineRules();
confirmDialog.close();
} else {
alert('失败:' + data.msg);
}
});
};
function addNewRule(rule) {
DegradeService.newRule(rule).success(function (data) {
if (data.code == 0) {
getMachineRules();
degradeRuleDialog.close();
} else {
alert('失败:' + data.msg);
}
});
};
function saveRule(rule, edit) {
DegradeService.saveRule(rule).success(function (data) {
if (data.code == 0) {
getMachineRules();
if (edit) {
degradeRuleDialog.close();
} else {
confirmDialog.close();
}
} else {
alert('失败:' + data.msg);
}
});
}
queryAppMachines();
function queryAppMachines() {
MachineService.getAppMachines($scope.app).success(
function (data) {
if (data.code == 0) {
// $scope.machines = data.data;
if (data.data) {
$scope.machines = [];
$scope.macsInputOptions = [];
data.data.forEach(function (item) {
if (item.healthy) {
$scope.macsInputOptions.push({
text: item.ip + ':' + item.port,
value: item.ip + ':' + item.port
});
}
});
}
if ($scope.macsInputOptions.length > 0) {
$scope.macInputModel = $scope.macsInputOptions[0].value;
}
} else {
$scope.macsInputOptions = [];
}
}
);
};
$scope.$watch('macInputModel', function () {
if ($scope.macInputModel) {
getMachineRules();
}
});
}]);
3、修改src/main/webapp/resources/app/scripts/app.js
加入下面代码
.state('dashboard.degradeV2', {
templateUrl: 'app/views/degrade_v2.html',
url: '/v2/degrade/:app',
controller: 'DegradeCtlV2',
resolve: {
loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) {
return $ocLazyLoad.load({
name: 'sentinelDashboardApp',
files: [
'app/scripts/controllers/degrade_v2.js',
]
});
}]
}
})
4、修改src/main/webapp/resources/dist/js/app.js
在.state("dashboard.degrade"后面加入
.state("dashboard.degradeV2", {
templateUrl: "app/views/degrade_v2.html",
url: "/v2/degrade/:app",
controller: "DegradeCtlV2",
resolve: {
loadMyFiles: ["$ocLazyLoad", function (e) {
return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/degrade_v2.js"]})
}]
}
})
在 (app = angular.module(“sentinelDashboardApp”)).service(“DegradeService”,后面加入
, (app = angular.module("sentinelDashboardApp")).service("DegradeServiceV2", ["$http", function (a) {
this.queryMachineRules = function (e, t, r) {
return a({url: "/V2/degrade/rules", params: {app: e, ip: t, port: r}, method: "GET"})
}, this.newRule = function (e) {
return a({url: "/V2/degrade/rule", data: e, method: "POST"})
}, this.saveRule = function (e) {
var t = {
id: e.id,
resource: e.resource,
limitApp: e.limitApp,
grade: e.grade,
count: e.count,
timeWindow: e.timeWindow,
statIntervalMs: e.statIntervalMs,
minRequestAmount: e.minRequestAmount,
slowRatioThreshold: e.slowRatioThreshold
};
return a({url: "/V2/degrade/rule/" + e.id, data: t, method: "PUT"})
}, this.deleteRule = function (e) {
return a({url: "/V2/degrade/rule/" + e.id, method: "DELETE"})
}, this.checkRuleValid = function (e) {
if (void 0 === e.resource || "" === e.resource) return alert("资源名称不能为空"), !1;
if (void 0 === e.grade || e.grade < 0) return alert("未知的降级策略"), !1;
if (void 0 === e.count || "" === e.count || e.count < 0) return alert("降级阈值不能为空或小于 0"), !1;
if (null == e.timeWindow || "" === e.timeWindow || e.timeWindow <= 0) return alert("熔断时长必须大于 0s"), !1;
if (null == e.minRequestAmount || e.minRequestAmount <= 0) return alert("最小请求数目需大于 0"), !1;
if (null == e.statIntervalMs || e.statIntervalMs <= 0) return alert("统计窗口时长需大于 0s"), !1;
if (void 0 !== e.statIntervalMs && 12e4 < e.statIntervalMs) return alert("统计窗口时长不能超过 120 分钟"), !1;
if (1 == e.grade && 1 < e.count) return alert("异常比率超出范围:[0.0 - 1.0]"), !1;
if (0 == e.grade) {
if (null == e.slowRatioThreshold) return alert("慢调用比率不能为空"), !1;
if (e.slowRatioThreshold < 0 || 1 < e.slowRatioThreshold) return alert("慢调用比率超出范围:[0.0 - 1.0]"), !1
}
return !0
}
}])
4、创建降级页面
resources/app/views/degrade_v2.html
<div class="row" style="margin-left: 1px; margin-top:10px; height: 50px;">
<div class="col-md-6" style="margin-bottom: 10px;">
<span style="font-size: 30px;font-weight: bold;">{{app}}</span>
</div>
<div class="col-md-6">
<button class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ng-disabled="!macInputModel" ng-click="addNewRule()">
<i class="fa fa-plus"></i> 新增降级规则</button>
<a class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ui-sref="dashboard.degrade({app: app})">
回到单机页面
</a>
</div>
</div>
<div class="separator"></div>
<div class="container-fluid">
<div class="row" style="margin-top: 20px; margin-bottom: 20px;">
<div class="col-md-12">
<div class="card">
<div class="inputs-header">
<span class="brand" style="font-size: 13px;">降级规则</span>
<!--<button class="btn btn-danger" style="float: right;margin-right: 10px;height: 30px;font-size: 12px;" ng-click="disableAll()">全部禁用</button>-->
<button class="btn btn-primary" style="float: right; margin-right: 10px; height: 30px;font-size: 12px;" ng-click="getMachineRules()">刷新</button>
<input class="form-control witdh-200" placeholder="关键字" ng-model="searchKey">
<<!--
<div class="control-group" style="float:right;margin-right: 10px;margin-bottom: -10px;">-->
<!--
<selectize id="gsInput" class="selectize-input-200" config="macsInputConfig" options="macsInputOptions" ng-model="macInputModel"-->
<!--
placeholder="机器"></selectize>-->
<!--
</div>-->
</div>
<!--.tools-header -->
<div class="card-body" style="padding: 0px 0px;">
<table class="table" style="border-left: none; border-right:none;margin-top: 10px;">
<thead>
<tr style="background: #F3F5F7;">
<td style="width: 40%">
资源名
</td>
<td style="width: 10%;">
降级策略
</td>
<td style="width: 10%;">
阈值
</td>
<td style="width: 10%;">
熔断时长(s)
</td>
<td style="width: 12%;">
操作
</td>
</tr>
</thead>
<tbody>
<tr dir-paginate="rule in rules | filter : searchKey | itemsPerPage: rulesPageConfig.pageSize " current-page="rulesPageConfig.currentPageIndex"
pagination-id="entriesPagination">
<td style="word-wrap:break-word;word-break:break-all;">{{rule.resource}}</td>
<!--<td style="word-wrap:break-word;word-break:break-all;">{{rule.limitApp }}</td>-->
<td>
<span ng-if="rule.grade == 0">慢调用比例</span>
<span ng-if="rule.grade == 1" title="异常比例">异常比例</span>
<span ng-if="rule.grade == 2" title="异常数">异常数</span>
</td>
<td style="word-wrap:break-word;word-break:break-all;">
{{rule.count}}
</td>
<td style="word-wrap:break-word;word-break:break-all;">
{{rule.timeWindow}}s
</td>
<td>
<button class="btn btn-xs btn-default" type="button" ng-click="editRule(rule)" style="font-size: 12px; height:25px;">编辑</button>
<button class="btn btn-xs btn-default" type="button" ng-click="deleteRule(rule)" style="font-size: 12px; height:25px;">删除</button>
</td>
</tr>
</tbody>
</table>
</div>
<!-- .card-body -->
<div class="pagination-footer">
<dir-pagination-controls boundary-links="true" template-url="app/views/pagination.tpl.html" pagination-id="entriesPagination"
on-page-change="">
</dir-pagination-controls>
<div class="tools" style="">
<span>共 {{rulesPageConfig.totalCount}} 条记录, </span>
<span>
每页
<input class="form-control" ng-model="rulesPageConfig.pageSize"> 条记录,
</span>
<span>第 {{rulesPageConfig.currentPageIndex}} / {{rulesPageConfig.totalPage}} 页</span>
</div>
<!-- .tools -->
</div>
<!-- pagination-footer -->
</div>
<!-- .card -->
</div>
<!-- .col-md-12 -->
</div>
<!-- -->
</div>
<!-- .container-fluid -->
5、修改sidebar.html
可以把原有的降级注掉,然后加入下面代码
<li ui-sref-active="active">
<a ui-sref="dashboard.degradeV2({app: entry.app})">
<i class="glyphicon glyphicon-flash"></i> 降级规则V2</a>
</li>
项目重启之后清除一下浏览器缓存,保证使用到的是最新的
客户端配置
见文章流控配置配置的客户端配置 与之类似
最后
以上就是紧张皮卡丘为你收集整理的sentinel使用ZooKeeper配置动态降级规则的全部内容,希望文章能够帮你解决sentinel使用ZooKeeper配置动态降级规则所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复