版本
1.8.1
后端
1、创建zk rule配置
修改ZookeeperConfigUtil.java
com/alibaba/csp/sentinel/dashboard/rule/zookeeper/ZookeeperConfigUtil.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46/* * 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33package 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20@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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200/* * 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93var 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195var 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
加入下面代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16.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"后面加入
1
2
3
4
5
6
7
8
9
10
11.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”,后面加入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37, (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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102<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
可以把原有的降级注掉,然后加入下面代码
1
2
3
4
5
6<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配置动态降级规则内容请搜索靠谱客的其他文章。
发表评论 取消回复