Update cluster related command APIs and some enhancement and fix for cluster module
Signed-off-by: Eric Zhao <sczyh16@gmail.com>
This commit is contained in:
parent
a5819e092d
commit
2735954afd
|
|
@ -2,3 +2,4 @@ ignore:
|
||||||
- "sentinel-demo/.*"
|
- "sentinel-demo/.*"
|
||||||
- "sentinel-dashboard/.*"
|
- "sentinel-dashboard/.*"
|
||||||
- "sentinel-benchmark/.*"
|
- "sentinel-benchmark/.*"
|
||||||
|
- "sentinel-transport/.*"
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Sentinel Cluster Flow Control
|
||||||
|
|
||||||
|
This is the default implementation of Sentinel cluster flow control.
|
||||||
|
|
||||||
|
- `sentinel-cluster-common-default`: common module for cluster transport and functions
|
||||||
|
- `sentinel-cluster-client-default`: default cluster client module using Netty as underlying transport library
|
||||||
|
- `sentinel-cluster-server-default`: default cluster server module
|
||||||
|
|
@ -55,7 +55,6 @@ public class DefaultClusterTokenClient implements ClusterTokenClient {
|
||||||
changeServer(clusterClientConfig);
|
changeServer(clusterClientConfig);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// TODO: check here, who should start the client?
|
|
||||||
initNewConnection();
|
initNewConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,7 +89,6 @@ public class DefaultClusterTokenClient implements ClusterTokenClient {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// TODO: what if the client is pending init?
|
|
||||||
if (transportClient != null) {
|
if (transportClient != null) {
|
||||||
transportClient.stop();
|
transportClient.stop();
|
||||||
}
|
}
|
||||||
|
|
@ -108,12 +106,14 @@ public class DefaultClusterTokenClient implements ClusterTokenClient {
|
||||||
if (shouldStart.get()) {
|
if (shouldStart.get()) {
|
||||||
if (transportClient != null) {
|
if (transportClient != null) {
|
||||||
transportClient.start();
|
transportClient.start();
|
||||||
|
} else {
|
||||||
|
RecordLog.warn("[DefaultClusterTokenClient] Cannot start transport client: client not created");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopClientIfStarted() throws Exception {
|
private void stopClientIfStarted() throws Exception {
|
||||||
if (shouldStart.get()) {
|
if (shouldStart.compareAndSet(true, false)) {
|
||||||
if (transportClient != null) {
|
if (transportClient != null) {
|
||||||
transportClient.stop();
|
transportClient.stop();
|
||||||
}
|
}
|
||||||
|
|
@ -129,10 +129,8 @@ public class DefaultClusterTokenClient implements ClusterTokenClient {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() throws Exception {
|
public void stop() throws Exception {
|
||||||
if (shouldStart.compareAndSet(true, false)) {
|
|
||||||
stopClientIfStarted();
|
stopClientIfStarted();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TokenServerDescriptor currentServer() {
|
public TokenServerDescriptor currentServer() {
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@ public final class ClusterClientConfigManager {
|
||||||
public static boolean isValidConfig(ClusterClientConfig config) {
|
public static boolean isValidConfig(ClusterClientConfig config) {
|
||||||
return config != null && StringUtil.isNotBlank(config.getServerHost())
|
return config != null && StringUtil.isNotBlank(config.getServerHost())
|
||||||
&& config.getServerPort() > 0
|
&& config.getServerPort() > 0
|
||||||
|
&& config.getServerPort() <= 65535
|
||||||
&& config.getRequestTimeout() > 0;
|
&& config.getRequestTimeout() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,14 +45,13 @@ public class TokenClientHandler extends ChannelInboundHandlerAdapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||||
currentState.compareAndSet(ClientConstants.CLIENT_STATUS_PENDING, ClientConstants.CLIENT_STATUS_STARTED);
|
currentState.set(ClientConstants.CLIENT_STATUS_STARTED);
|
||||||
fireClientPing(ctx);
|
fireClientPing(ctx);
|
||||||
RecordLog.info("[TokenClientHandler] Client handler active, remote address: " + ctx.channel().remoteAddress());
|
RecordLog.info("[TokenClientHandler] Client handler active, remote address: " + ctx.channel().remoteAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||||
System.out.println(String.format("[%s] Client message recv: %s", System.currentTimeMillis(), msg)); // TODO: remove here
|
|
||||||
if (msg instanceof ClusterResponse) {
|
if (msg instanceof ClusterResponse) {
|
||||||
ClusterResponse<?> response = (ClusterResponse) msg;
|
ClusterResponse<?> response = (ClusterResponse) msg;
|
||||||
|
|
||||||
|
|
@ -96,7 +95,7 @@ public class TokenClientHandler extends ChannelInboundHandlerAdapter {
|
||||||
@Override
|
@Override
|
||||||
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
|
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
|
||||||
RecordLog.info("[TokenClientHandler] Client channel unregistered, remote address: " + ctx.channel().remoteAddress());
|
RecordLog.info("[TokenClientHandler] Client channel unregistered, remote address: " + ctx.channel().remoteAddress());
|
||||||
currentState.compareAndSet(ClientConstants.CLIENT_STATUS_STARTED, ClientConstants.CLIENT_STATUS_OFF);
|
currentState.set(ClientConstants.CLIENT_STATUS_OFF);
|
||||||
disconnectCallback.run();
|
disconnectCallback.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ public class ModifyClusterClientConfigHandler implements CommandHandler<String>
|
||||||
ClusterClientConfig clusterClientConfig = JSON.parseObject(data, ClusterClientConfig.class);
|
ClusterClientConfig clusterClientConfig = JSON.parseObject(data, ClusterClientConfig.class);
|
||||||
ClusterClientConfigManager.applyNewConfig(clusterClientConfig);
|
ClusterClientConfigManager.applyNewConfig(clusterClientConfig);
|
||||||
|
|
||||||
return CommandResponse.ofSuccess("ok");
|
return CommandResponse.ofSuccess("success");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
RecordLog.warn("[ModifyClusterClientConfigHandler] Decode client cluster config error", e);
|
RecordLog.warn("[ModifyClusterClientConfigHandler] Decode client cluster config error", e);
|
||||||
return CommandResponse.ofFailure(e, "decode client cluster config error");
|
return CommandResponse.ofFailure(e, "decode client cluster config error");
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package com.alibaba.csp.sentinel.cluster.flow.rule;
|
package com.alibaba.csp.sentinel.cluster.flow.rule;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
@ -163,6 +164,11 @@ public final class ClusterFlowRuleManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove cluster flow rule property for a specific namespace.
|
||||||
|
*
|
||||||
|
* @param namespace valid namespace
|
||||||
|
*/
|
||||||
public static void removeProperty(String namespace) {
|
public static void removeProperty(String namespace) {
|
||||||
AssertUtil.notEmpty(namespace, "namespace cannot be empty");
|
AssertUtil.notEmpty(namespace, "namespace cannot be empty");
|
||||||
synchronized (UPDATE_LOCK) {
|
synchronized (UPDATE_LOCK) {
|
||||||
|
|
@ -189,6 +195,12 @@ public final class ClusterFlowRuleManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get flow rule by rule ID.
|
||||||
|
*
|
||||||
|
* @param id rule ID
|
||||||
|
* @return flow rule
|
||||||
|
*/
|
||||||
public static FlowRule getFlowRuleById(Long id) {
|
public static FlowRule getFlowRuleById(Long id) {
|
||||||
if (!ClusterRuleUtil.validId(id)) {
|
if (!ClusterRuleUtil.validId(id)) {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -196,10 +208,57 @@ public final class ClusterFlowRuleManager {
|
||||||
return FLOW_RULES.get(id);
|
return FLOW_RULES.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<FlowRule> getAllFlowRules() {
|
||||||
|
return new ArrayList<>(FLOW_RULES.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all cluster flow rules within a specific namespace.
|
||||||
|
*
|
||||||
|
* @param namespace valid namespace
|
||||||
|
* @return cluster flow rules within the provided namespace
|
||||||
|
*/
|
||||||
|
public static List<FlowRule> getFlowRules(String namespace) {
|
||||||
|
if (StringUtil.isEmpty(namespace)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
List<FlowRule> rules = new ArrayList<>();
|
||||||
|
Set<Long> flowIdSet = NAMESPACE_FLOW_ID_MAP.get(namespace);
|
||||||
|
if (flowIdSet == null || flowIdSet.isEmpty()) {
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
for (Long flowId : flowIdSet) {
|
||||||
|
FlowRule rule = FLOW_RULES.get(flowId);
|
||||||
|
if (rule != null) {
|
||||||
|
rules.add(rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load flow rules for a specific namespace. The former rules of the namespace will be replaced.
|
||||||
|
*
|
||||||
|
* @param namespace a valid namespace
|
||||||
|
* @param rules rule list
|
||||||
|
*/
|
||||||
|
public static void loadRules(String namespace, List<FlowRule> rules) {
|
||||||
|
AssertUtil.notEmpty(namespace, "namespace cannot be empty");
|
||||||
|
NamespaceFlowProperty<FlowRule> property = PROPERTY_MAP.get(namespace);
|
||||||
|
if (property != null) {
|
||||||
|
property.getProperty().updateValue(rules);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void resetNamespaceFlowIdMapFor(/*@Valid*/ String namespace) {
|
private static void resetNamespaceFlowIdMapFor(/*@Valid*/ String namespace) {
|
||||||
NAMESPACE_FLOW_ID_MAP.put(namespace, new HashSet<Long>());
|
NAMESPACE_FLOW_ID_MAP.put(namespace, new HashSet<Long>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear all rules of the provided namespace and reset map.
|
||||||
|
*
|
||||||
|
* @param namespace valid namespace
|
||||||
|
*/
|
||||||
private static void clearAndResetRulesFor(/*@Valid*/ String namespace) {
|
private static void clearAndResetRulesFor(/*@Valid*/ String namespace) {
|
||||||
Set<Long> flowIdSet = NAMESPACE_FLOW_ID_MAP.get(namespace);
|
Set<Long> flowIdSet = NAMESPACE_FLOW_ID_MAP.get(namespace);
|
||||||
if (flowIdSet != null && !flowIdSet.isEmpty()) {
|
if (flowIdSet != null && !flowIdSet.isEmpty()) {
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package com.alibaba.csp.sentinel.cluster.flow.rule;
|
package com.alibaba.csp.sentinel.cluster.flow.rule;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
@ -217,6 +218,54 @@ public final class ClusterParamFlowRuleManager {
|
||||||
return PARAM_RULES.get(id);
|
return PARAM_RULES.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<ParamFlowRule> getAllParamRules() {
|
||||||
|
return new ArrayList<>(PARAM_RULES.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all cluster parameter flow rules within a specific namespace.
|
||||||
|
*
|
||||||
|
* @param namespace a valid namespace
|
||||||
|
* @return cluster parameter flow rules within the provided namespace
|
||||||
|
*/
|
||||||
|
public static List<ParamFlowRule> getParamRules(String namespace) {
|
||||||
|
if (StringUtil.isEmpty(namespace)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
List<ParamFlowRule> rules = new ArrayList<>();
|
||||||
|
Set<Long> flowIdSet = NAMESPACE_FLOW_ID_MAP.get(namespace);
|
||||||
|
if (flowIdSet == null || flowIdSet.isEmpty()) {
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
for (Long flowId : flowIdSet) {
|
||||||
|
ParamFlowRule rule = PARAM_RULES.get(flowId);
|
||||||
|
if (rule != null) {
|
||||||
|
rules.add(rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load parameter flow rules for a specific namespace. The former rules of the namespace will be replaced.
|
||||||
|
*
|
||||||
|
* @param namespace a valid namespace
|
||||||
|
* @param rules rule list
|
||||||
|
*/
|
||||||
|
public static void loadRules(String namespace, List<ParamFlowRule> rules) {
|
||||||
|
AssertUtil.notEmpty(namespace, "namespace cannot be empty");
|
||||||
|
NamespaceFlowProperty<ParamFlowRule> property = PROPERTY_MAP.get(namespace);
|
||||||
|
if (property != null) {
|
||||||
|
property.getProperty().updateValue(rules);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get connected count for associated namespace of given {@code flowId}.
|
||||||
|
*
|
||||||
|
* @param flowId existing rule ID
|
||||||
|
* @return connected count
|
||||||
|
*/
|
||||||
public static int getConnectedCount(long flowId) {
|
public static int getConnectedCount(long flowId) {
|
||||||
if (flowId <= 0) {
|
if (flowId <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ public class SentinelDefaultTokenServer implements ClusterTokenServer {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (server != null) {
|
if (server != null) {
|
||||||
stopServerIfStarted();
|
stopServer();
|
||||||
}
|
}
|
||||||
this.server = new NettyTransportServer(newPort);
|
this.server = new NettyTransportServer(newPort);
|
||||||
this.port = newPort;
|
this.port = newPort;
|
||||||
|
|
@ -101,8 +101,7 @@ public class SentinelDefaultTokenServer implements ClusterTokenServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopServerIfStarted() throws Exception {
|
private void stopServer() throws Exception {
|
||||||
if (shouldStart.get()) {
|
|
||||||
if (server != null) {
|
if (server != null) {
|
||||||
server.stop();
|
server.stop();
|
||||||
if (embedded) {
|
if (embedded) {
|
||||||
|
|
@ -110,7 +109,6 @@ public class SentinelDefaultTokenServer implements ClusterTokenServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void handleEmbeddedStop() {
|
private void handleEmbeddedStop() {
|
||||||
String namespace = ConfigSupplierRegistry.getNamespaceSupplier().get();
|
String namespace = ConfigSupplierRegistry.getNamespaceSupplier().get();
|
||||||
|
|
@ -136,7 +134,7 @@ public class SentinelDefaultTokenServer implements ClusterTokenServer {
|
||||||
@Override
|
@Override
|
||||||
public void stop() throws Exception {
|
public void stop() throws Exception {
|
||||||
if (shouldStart.compareAndSet(true, false)) {
|
if (shouldStart.compareAndSet(true, false)) {
|
||||||
stopServerIfStarted();
|
stopServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* 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.cluster.server.command.handler;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.cluster.flow.rule.ClusterFlowRuleManager;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandHandler;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandRequest;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandResponse;
|
||||||
|
import com.alibaba.csp.sentinel.command.annotation.CommandMapping;
|
||||||
|
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Eric Zhao
|
||||||
|
* @since 1.4.0
|
||||||
|
*/
|
||||||
|
@CommandMapping(name = "cluster/server/flowRules")
|
||||||
|
public class FetchClusterFlowRulesCommandHandler implements CommandHandler<String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResponse<String> handle(CommandRequest request) {
|
||||||
|
String namespace = request.getParam("namespace");
|
||||||
|
if (StringUtil.isEmpty(namespace)) {
|
||||||
|
return CommandResponse.ofSuccess(JSON.toJSONString(ClusterFlowRuleManager.getAllFlowRules()));
|
||||||
|
} else {
|
||||||
|
return CommandResponse.ofSuccess(JSON.toJSONString(ClusterFlowRuleManager.getFlowRules(namespace)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* 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.cluster.server.command.handler;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.cluster.flow.rule.ClusterParamFlowRuleManager;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandHandler;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandRequest;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandResponse;
|
||||||
|
import com.alibaba.csp.sentinel.command.annotation.CommandMapping;
|
||||||
|
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Eric Zhao
|
||||||
|
* @since 1.4.0
|
||||||
|
*/
|
||||||
|
@CommandMapping(name = "cluster/server/paramRules")
|
||||||
|
public class FetchClusterParamFlowRulesCommandHandler implements CommandHandler<String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResponse<String> handle(CommandRequest request) {
|
||||||
|
String namespace = request.getParam("namespace");
|
||||||
|
if (StringUtil.isEmpty(namespace)) {
|
||||||
|
return CommandResponse.ofSuccess(JSON.toJSONString(ClusterParamFlowRuleManager.getAllParamRules()));
|
||||||
|
} else {
|
||||||
|
return CommandResponse.ofSuccess(JSON.toJSONString(ClusterParamFlowRuleManager.getParamRules(namespace)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* 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.cluster.server.command.handler;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.cluster.server.config.ClusterServerConfigManager;
|
||||||
|
import com.alibaba.csp.sentinel.cluster.server.config.ServerFlowConfig;
|
||||||
|
import com.alibaba.csp.sentinel.cluster.server.config.ServerTransportConfig;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandHandler;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandRequest;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandResponse;
|
||||||
|
import com.alibaba.csp.sentinel.command.annotation.CommandMapping;
|
||||||
|
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Eric Zhao
|
||||||
|
* @since 1.4.0
|
||||||
|
*/
|
||||||
|
@CommandMapping(name = "cluster/server/fetchConfig")
|
||||||
|
public class FetchClusterServerConfigHandler implements CommandHandler<String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResponse<String> handle(CommandRequest request) {
|
||||||
|
String namespace = request.getParam("namespace");
|
||||||
|
if (StringUtil.isEmpty(namespace)) {
|
||||||
|
return globalConfigResult();
|
||||||
|
}
|
||||||
|
return namespaceConfigResult(namespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CommandResponse<String> namespaceConfigResult(/*@NonEmpty*/ String namespace) {
|
||||||
|
ServerFlowConfig flowConfig = new ServerFlowConfig()
|
||||||
|
.setExceedCount(ClusterServerConfigManager.getExceedCount(namespace))
|
||||||
|
.setMaxOccupyRatio(ClusterServerConfigManager.getMaxOccupyRatio(namespace))
|
||||||
|
.setIntervalMs(ClusterServerConfigManager.getIntervalMs(namespace))
|
||||||
|
.setSampleCount(ClusterServerConfigManager.getSampleCount(namespace));
|
||||||
|
JSONObject config = new JSONObject()
|
||||||
|
.fluentPut("flow", flowConfig);
|
||||||
|
return CommandResponse.ofSuccess(config.toJSONString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private CommandResponse<String> globalConfigResult() {
|
||||||
|
ServerTransportConfig transportConfig = new ServerTransportConfig()
|
||||||
|
.setPort(ClusterServerConfigManager.getPort())
|
||||||
|
.setIdleSeconds(ClusterServerConfigManager.getIdleSeconds());
|
||||||
|
ServerFlowConfig flowConfig = new ServerFlowConfig()
|
||||||
|
.setExceedCount(ClusterServerConfigManager.getExceedCount())
|
||||||
|
.setMaxOccupyRatio(ClusterServerConfigManager.getMaxOccupyRatio())
|
||||||
|
.setIntervalMs(ClusterServerConfigManager.getIntervalMs())
|
||||||
|
.setSampleCount(ClusterServerConfigManager.getSampleCount());
|
||||||
|
JSONObject config = new JSONObject()
|
||||||
|
.fluentPut("transport", transportConfig)
|
||||||
|
.fluentPut("flow", flowConfig)
|
||||||
|
.fluentPut("namespaceSet", ClusterServerConfigManager.getNamespaceSet());
|
||||||
|
return CommandResponse.ofSuccess(config.toJSONString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* 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.cluster.server.command.handler;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.cluster.server.config.ClusterServerConfigManager;
|
||||||
|
import com.alibaba.csp.sentinel.cluster.server.config.ServerFlowConfig;
|
||||||
|
import com.alibaba.csp.sentinel.cluster.server.config.ServerTransportConfig;
|
||||||
|
import com.alibaba.csp.sentinel.cluster.server.connection.ConnectionGroup;
|
||||||
|
import com.alibaba.csp.sentinel.cluster.server.connection.ConnectionManager;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandHandler;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandRequest;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandResponse;
|
||||||
|
import com.alibaba.csp.sentinel.command.annotation.CommandMapping;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Eric Zhao
|
||||||
|
* @since 1.4.0
|
||||||
|
*/
|
||||||
|
@CommandMapping(name = "cluster/server/info")
|
||||||
|
public class FetchClusterServerInfoCommandHandler implements CommandHandler<String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResponse<String> handle(CommandRequest request) {
|
||||||
|
JSONObject info = new JSONObject();
|
||||||
|
JSONArray connectionGroups = new JSONArray();
|
||||||
|
Set<String> namespaceSet = ClusterServerConfigManager.getNamespaceSet();
|
||||||
|
for (String namespace : namespaceSet) {
|
||||||
|
ConnectionGroup group = ConnectionManager.getConnectionGroup(namespace);
|
||||||
|
if (group != null) {
|
||||||
|
connectionGroups.add(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerTransportConfig transportConfig = new ServerTransportConfig()
|
||||||
|
.setPort(ClusterServerConfigManager.getPort())
|
||||||
|
.setIdleSeconds(ClusterServerConfigManager.getIdleSeconds());
|
||||||
|
ServerFlowConfig flowConfig = new ServerFlowConfig()
|
||||||
|
.setExceedCount(ClusterServerConfigManager.getExceedCount())
|
||||||
|
.setMaxOccupyRatio(ClusterServerConfigManager.getMaxOccupyRatio())
|
||||||
|
.setIntervalMs(ClusterServerConfigManager.getIntervalMs())
|
||||||
|
.setSampleCount(ClusterServerConfigManager.getSampleCount());
|
||||||
|
|
||||||
|
info.fluentPut("port", ClusterServerConfigManager.getPort())
|
||||||
|
.fluentPut("connection", connectionGroups)
|
||||||
|
.fluentPut("transport", transportConfig)
|
||||||
|
.fluentPut("flow", flowConfig)
|
||||||
|
.fluentPut("namespaceSet", ClusterServerConfigManager.getNamespaceSet());
|
||||||
|
|
||||||
|
return CommandResponse.ofSuccess(info.toJSONString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* 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.cluster.server.command.handler;
|
||||||
|
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.cluster.flow.rule.ClusterFlowRuleManager;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandHandler;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandRequest;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandResponse;
|
||||||
|
import com.alibaba.csp.sentinel.command.annotation.CommandMapping;
|
||||||
|
import com.alibaba.csp.sentinel.log.RecordLog;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||||
|
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Eric Zhao
|
||||||
|
* @since 1.4.0
|
||||||
|
*/
|
||||||
|
@CommandMapping(name = "cluster/server/modifyFlowRules")
|
||||||
|
public class ModifyClusterFlowRulesCommandHandler implements CommandHandler<String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResponse<String> handle(CommandRequest request) {
|
||||||
|
String namespace = request.getParam("namespace");
|
||||||
|
if (StringUtil.isEmpty(namespace)) {
|
||||||
|
return CommandResponse.ofFailure(new IllegalArgumentException("empty namespace"));
|
||||||
|
}
|
||||||
|
String data = request.getParam("data");
|
||||||
|
if (StringUtil.isBlank(data)) {
|
||||||
|
return CommandResponse.ofFailure(new IllegalArgumentException("empty data"));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
data = URLDecoder.decode(data, "UTF-8");
|
||||||
|
RecordLog.info("[ModifyClusterFlowRulesCommandHandler] Receiving cluster flow rules for namespace <{0}>: {1}", namespace, data);
|
||||||
|
|
||||||
|
List<FlowRule> flowRules = JSONArray.parseArray(data, FlowRule.class);
|
||||||
|
ClusterFlowRuleManager.loadRules(namespace, flowRules);
|
||||||
|
|
||||||
|
return CommandResponse.ofSuccess(SUCCESS);
|
||||||
|
} catch (Exception e) {
|
||||||
|
RecordLog.warn("[ModifyClusterFlowRulesCommandHandler] Decode cluster flow rules error", e);
|
||||||
|
return CommandResponse.ofFailure(e, "decode cluster flow rules error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String SUCCESS = "success";
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* 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.cluster.server.command.handler;
|
||||||
|
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.cluster.flow.rule.ClusterParamFlowRuleManager;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandHandler;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandRequest;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandResponse;
|
||||||
|
import com.alibaba.csp.sentinel.command.annotation.CommandMapping;
|
||||||
|
import com.alibaba.csp.sentinel.log.RecordLog;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
|
||||||
|
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Eric Zhao
|
||||||
|
* @since 1.4.0
|
||||||
|
*/
|
||||||
|
@CommandMapping(name = "cluster/server/modifyParamRules")
|
||||||
|
public class ModifyClusterParamFlowRulesCommandHandler implements CommandHandler<String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResponse<String> handle(CommandRequest request) {
|
||||||
|
String namespace = request.getParam("namespace");
|
||||||
|
if (StringUtil.isEmpty(namespace)) {
|
||||||
|
return CommandResponse.ofFailure(new IllegalArgumentException("empty namespace"));
|
||||||
|
}
|
||||||
|
String data = request.getParam("data");
|
||||||
|
if (StringUtil.isBlank(data)) {
|
||||||
|
return CommandResponse.ofFailure(new IllegalArgumentException("empty data"));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
data = URLDecoder.decode(data, "UTF-8");
|
||||||
|
RecordLog.info("[ModifyClusterParamFlowRulesCommandHandler] Receiving cluster param rules for namespace <{0}>: {1}", namespace, data);
|
||||||
|
|
||||||
|
List<ParamFlowRule> flowRules = JSONArray.parseArray(data, ParamFlowRule.class);
|
||||||
|
ClusterParamFlowRuleManager.loadRules(namespace, flowRules);
|
||||||
|
|
||||||
|
return CommandResponse.ofSuccess(SUCCESS);
|
||||||
|
} catch (Exception e) {
|
||||||
|
RecordLog.warn("[ModifyClusterParamFlowRulesCommandHandler] Decode cluster param rules error", e);
|
||||||
|
return CommandResponse.ofFailure(e, "decode cluster param rules error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String SUCCESS = "success";
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* 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.cluster.server.command.handler;
|
||||||
|
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.cluster.server.config.ClusterServerConfigManager;
|
||||||
|
import com.alibaba.csp.sentinel.cluster.server.config.ServerFlowConfig;
|
||||||
|
import com.alibaba.csp.sentinel.cluster.server.config.ServerTransportConfig;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandHandler;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandRequest;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandResponse;
|
||||||
|
import com.alibaba.csp.sentinel.command.annotation.CommandMapping;
|
||||||
|
import com.alibaba.csp.sentinel.log.RecordLog;
|
||||||
|
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Eric Zhao
|
||||||
|
* @since 1.4.0
|
||||||
|
*/
|
||||||
|
@CommandMapping(name = "cluster/server/modifyFlowConfig")
|
||||||
|
public class ModifyClusterServerFlowConfigHandler implements CommandHandler<String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResponse<String> handle(CommandRequest request) {
|
||||||
|
String data = request.getParam("data");
|
||||||
|
if (StringUtil.isBlank(data)) {
|
||||||
|
return CommandResponse.ofFailure(new IllegalArgumentException("empty data"));
|
||||||
|
}
|
||||||
|
String namespace = request.getParam("namespace");
|
||||||
|
try {
|
||||||
|
data = URLDecoder.decode(data, "utf-8");
|
||||||
|
|
||||||
|
if (StringUtil.isEmpty(namespace)) {
|
||||||
|
RecordLog.info("[ModifyClusterServerFlowConfigHandler] Receiving cluster server global flow config: " + data);
|
||||||
|
ServerFlowConfig config = JSON.parseObject(data, ServerFlowConfig.class);
|
||||||
|
ClusterServerConfigManager.loadGlobalFlowConfig(config);
|
||||||
|
} else {
|
||||||
|
RecordLog.info("[ModifyClusterServerFlowConfigHandler] Receiving cluster server flow config for namespace <{0}>: {1}", namespace, data);
|
||||||
|
ServerFlowConfig config = JSON.parseObject(data, ServerFlowConfig.class);
|
||||||
|
ClusterServerConfigManager.loadFlowConfig(namespace, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CommandResponse.ofSuccess("success");
|
||||||
|
} catch (Exception e) {
|
||||||
|
RecordLog.warn("[ModifyClusterServerFlowConfigHandler] Decode cluster server flow config error", e);
|
||||||
|
return CommandResponse.ofFailure(e, "decode cluster server flow config error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* 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.cluster.server.command.handler;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.cluster.server.config.ClusterServerConfigManager;
|
||||||
|
import com.alibaba.csp.sentinel.cluster.server.config.ServerTransportConfig;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandHandler;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandRequest;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandResponse;
|
||||||
|
import com.alibaba.csp.sentinel.command.annotation.CommandMapping;
|
||||||
|
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Eric Zhao
|
||||||
|
* @since 1.4.0
|
||||||
|
*/
|
||||||
|
@CommandMapping(name = "cluster/server/modifyTransportConfig")
|
||||||
|
public class ModifyClusterServerTransportConfigHandler implements CommandHandler<String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResponse<String> handle(CommandRequest request) {
|
||||||
|
String portValue = request.getParam("port");
|
||||||
|
if (StringUtil.isBlank(portValue)) {
|
||||||
|
return CommandResponse.ofFailure(new IllegalArgumentException("invalid empty port"));
|
||||||
|
}
|
||||||
|
String idleSecondsValue = request.getParam("idleSeconds");
|
||||||
|
if (StringUtil.isBlank(idleSecondsValue)) {
|
||||||
|
return CommandResponse.ofFailure(new IllegalArgumentException("invalid empty idleSeconds"));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
int port = Integer.valueOf(portValue);
|
||||||
|
int idleSeconds = Integer.valueOf(idleSecondsValue);
|
||||||
|
|
||||||
|
ClusterServerConfigManager.loadGlobalTransportConfig(new ServerTransportConfig()
|
||||||
|
.setPort(port).setIdleSeconds(idleSeconds));
|
||||||
|
return CommandResponse.ofSuccess("success");
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return CommandResponse.ofFailure(new IllegalArgumentException("invalid parameter"));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return CommandResponse.ofFailure(new IllegalArgumentException("unexpected error"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* 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.cluster.server.command.handler;
|
||||||
|
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.cluster.server.config.ClusterServerConfigManager;
|
||||||
|
import com.alibaba.csp.sentinel.cluster.server.config.ServerTransportConfig;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandHandler;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandRequest;
|
||||||
|
import com.alibaba.csp.sentinel.command.CommandResponse;
|
||||||
|
import com.alibaba.csp.sentinel.command.annotation.CommandMapping;
|
||||||
|
import com.alibaba.csp.sentinel.log.RecordLog;
|
||||||
|
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.TypeReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Eric Zhao
|
||||||
|
* @since 1.4.0
|
||||||
|
*/
|
||||||
|
@CommandMapping(name = "cluster/server/modifyNamespaceSet")
|
||||||
|
public class ModifyServerNamespaceSetHandler implements CommandHandler<String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResponse<String> handle(CommandRequest request) {
|
||||||
|
String data = request.getParam("data");
|
||||||
|
if (StringUtil.isBlank(data)) {
|
||||||
|
return CommandResponse.ofFailure(new IllegalArgumentException("empty data"));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
data = URLDecoder.decode(data, "utf-8");
|
||||||
|
RecordLog.info("[ModifyServerNamespaceSetHandler] Receiving cluster server namespace set: " + data);
|
||||||
|
Set<String> set = JSON.parseObject(data, new TypeReference<Set<String>>() {});
|
||||||
|
ClusterServerConfigManager.loadServerNamespaceSet(set);
|
||||||
|
return CommandResponse.ofSuccess("success");
|
||||||
|
} catch (Exception e) {
|
||||||
|
RecordLog.warn("[ModifyServerNamespaceSetHandler] Decode cluster server namespace set error", e);
|
||||||
|
return CommandResponse.ofFailure(e, "decode client cluster config error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,7 @@ package com.alibaba.csp.sentinel.cluster.server.config;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
@ -110,6 +111,35 @@ public final class ClusterServerConfigManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void loadServerNamespaceSet(Set<String> namespaceSet) {
|
||||||
|
namespaceSetProperty.updateValue(namespaceSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void loadGlobalTransportConfig(ServerTransportConfig config) {
|
||||||
|
transportConfigProperty.updateValue(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void loadGlobalFlowConfig(ServerFlowConfig config) {
|
||||||
|
globalFlowProperty.updateValue(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load server flow config for a specific namespace.
|
||||||
|
*
|
||||||
|
* @param namespace a valid namespace
|
||||||
|
* @param config valid flow config for the namespace
|
||||||
|
*/
|
||||||
|
public static void loadFlowConfig(String namespace, ServerFlowConfig config) {
|
||||||
|
AssertUtil.notEmpty(namespace, "namespace cannot be empty");
|
||||||
|
// TODO: Support namespace-scope server flow config.
|
||||||
|
globalFlowProperty.updateValue(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addTransportConfigChangeObserver(ServerTransportConfigObserver observer) {
|
||||||
|
AssertUtil.notNull(observer, "observer cannot be null");
|
||||||
|
TRANSPORT_CONFIG_OBSERVERS.add(observer);
|
||||||
|
}
|
||||||
|
|
||||||
private static class ServerNamespaceSetPropertyListener implements PropertyListener<Set<String>> {
|
private static class ServerNamespaceSetPropertyListener implements PropertyListener<Set<String>> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -137,6 +167,8 @@ public final class ClusterServerConfigManager {
|
||||||
ClusterServerConfigManager.namespaceSet = Collections.singleton(ServerConstants.DEFAULT_NAMESPACE);
|
ClusterServerConfigManager.namespaceSet = Collections.singleton(ServerConstants.DEFAULT_NAMESPACE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newSet = new HashSet<>(newSet);
|
||||||
newSet.add(ServerConstants.DEFAULT_NAMESPACE);
|
newSet.add(ServerConstants.DEFAULT_NAMESPACE);
|
||||||
|
|
||||||
Set<String> oldSet = ClusterServerConfigManager.namespaceSet;
|
Set<String> oldSet = ClusterServerConfigManager.namespaceSet;
|
||||||
|
|
@ -186,6 +218,19 @@ public final class ClusterServerConfigManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void updateTokenServer(ServerTransportConfig config) {
|
||||||
|
int newPort = config.getPort();
|
||||||
|
AssertUtil.isTrue(newPort > 0, "token server port should be valid (positive)");
|
||||||
|
if (newPort == port) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ClusterServerConfigManager.port = newPort;
|
||||||
|
|
||||||
|
for (ServerTransportConfigObserver observer : TRANSPORT_CONFIG_OBSERVERS) {
|
||||||
|
observer.onTransportConfigChange(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class ServerGlobalFlowPropertyListener implements PropertyListener<ServerFlowConfig> {
|
private static class ServerGlobalFlowPropertyListener implements PropertyListener<ServerFlowConfig> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -197,9 +242,8 @@ public final class ClusterServerConfigManager {
|
||||||
public void configLoad(ServerFlowConfig config) {
|
public void configLoad(ServerFlowConfig config) {
|
||||||
applyGlobalFlowConfig(config);
|
applyGlobalFlowConfig(config);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static synchronized void applyGlobalFlowConfig(ServerFlowConfig config) {
|
private synchronized void applyGlobalFlowConfig(ServerFlowConfig config) {
|
||||||
if (!isValidFlowConfig(config)) {
|
if (!isValidFlowConfig(config)) {
|
||||||
RecordLog.warn(
|
RecordLog.warn(
|
||||||
"[ClusterServerConfigManager] Invalid cluster server global flow config, ignoring: " + config);
|
"[ClusterServerConfigManager] Invalid cluster server global flow config, ignoring: " + config);
|
||||||
|
|
@ -226,33 +270,16 @@ public final class ClusterServerConfigManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void updateTokenServer(ServerTransportConfig config) {
|
|
||||||
int newPort = config.getPort();
|
|
||||||
AssertUtil.isTrue(newPort > 0, "token server port should be valid (positive)");
|
|
||||||
if (newPort == port) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ClusterServerConfigManager.port = newPort;
|
|
||||||
|
|
||||||
for (ServerTransportConfigObserver observer : TRANSPORT_CONFIG_OBSERVERS) {
|
|
||||||
observer.onTransportConfigChange(config);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isValidTransportConfig(ServerTransportConfig config) {
|
public static boolean isValidTransportConfig(ServerTransportConfig config) {
|
||||||
return config != null && config.getPort() > 0;
|
return config != null && config.getPort() > 0 && config.getPort() <= 65535;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isValidFlowConfig(ServerFlowConfig config) {
|
public static boolean isValidFlowConfig(ServerFlowConfig config) {
|
||||||
return config != null && config.getMaxOccupyRatio() >= 0 && config.getExceedCount() >= 0;
|
return config != null && config.getMaxOccupyRatio() >= 0 && config.getExceedCount() >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addTransportConfigChangeObserver(ServerTransportConfigObserver observer) {
|
|
||||||
AssertUtil.notNull(observer, "observer cannot be null");
|
|
||||||
TRANSPORT_CONFIG_OBSERVERS.add(observer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double getExceedCount(String namespace) {
|
public static double getExceedCount(String namespace) {
|
||||||
AssertUtil.notEmpty(namespace, "namespace cannot be empty");
|
AssertUtil.notEmpty(namespace, "namespace cannot be empty");
|
||||||
ServerFlowConfig config = NAMESPACE_CONF.get(namespace);
|
ServerFlowConfig config = NAMESPACE_CONF.get(namespace);
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,12 @@ public final class ConnectionManager {
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ConnectionGroup getConnectionGroup(String namespace) {
|
||||||
|
AssertUtil.assertNotBlank(namespace, "namespace should not be empty");
|
||||||
|
ConnectionGroup group = getOrCreateGroup(namespace);
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
private static final Object CREATE_LOCK = new Object();
|
private static final Object CREATE_LOCK = new Object();
|
||||||
|
|
||||||
private ConnectionManager() {}
|
private ConnectionManager() {}
|
||||||
|
|
|
||||||
|
|
@ -46,13 +46,11 @@ public class TokenServerHandler extends ChannelInboundHandlerAdapter {
|
||||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||||
globalConnectionPool.createConnection(ctx.channel());
|
globalConnectionPool.createConnection(ctx.channel());
|
||||||
String remoteAddress = getRemoteAddress(ctx);
|
String remoteAddress = getRemoteAddress(ctx);
|
||||||
System.out.println("[TokenServerHandler] Connection established, remote client address: " + remoteAddress); //TODO: DEBUG
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||||
String remoteAddress = getRemoteAddress(ctx);
|
String remoteAddress = getRemoteAddress(ctx);
|
||||||
System.out.println("[TokenServerHandler] Connection inactive, remote client address: " + remoteAddress); //TODO: DEBUG
|
|
||||||
globalConnectionPool.remove(ctx.channel());
|
globalConnectionPool.remove(ctx.channel());
|
||||||
ConnectionManager.removeConnection(remoteAddress);
|
ConnectionManager.removeConnection(remoteAddress);
|
||||||
}
|
}
|
||||||
|
|
@ -61,7 +59,6 @@ public class TokenServerHandler extends ChannelInboundHandlerAdapter {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||||
globalConnectionPool.refreshLastReadTime(ctx.channel());
|
globalConnectionPool.refreshLastReadTime(ctx.channel());
|
||||||
System.out.println(String.format("[%s] Server message recv: %s", System.currentTimeMillis(), msg)); //TODO: DEBUG
|
|
||||||
if (msg instanceof ClusterRequest) {
|
if (msg instanceof ClusterRequest) {
|
||||||
ClusterRequest request = (ClusterRequest)msg;
|
ClusterRequest request = (ClusterRequest)msg;
|
||||||
|
|
||||||
|
|
@ -105,8 +102,6 @@ public class TokenServerHandler extends ChannelInboundHandlerAdapter {
|
||||||
int status = ClusterConstants.RESPONSE_STATUS_OK;
|
int status = ClusterConstants.RESPONSE_STATUS_OK;
|
||||||
ClusterResponse<Integer> response = new ClusterResponse<>(request.getId(), request.getType(), status, curCount);
|
ClusterResponse<Integer> response = new ClusterResponse<>(request.getId(), request.getType(), status, curCount);
|
||||||
writeResponse(ctx, response);
|
writeResponse(ctx, response);
|
||||||
|
|
||||||
RecordLog.info("[TokenServerHandler] Client <{0}> registered with namespace <{1}>", clientAddress, namespace);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getRemoteAddress(ChannelHandlerContext ctx) {
|
private String getRemoteAddress(ChannelHandlerContext ctx) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
com.alibaba.csp.sentinel.cluster.server.command.handler.ModifyClusterServerFlowConfigHandler
|
||||||
|
com.alibaba.csp.sentinel.cluster.server.command.handler.FetchClusterFlowRulesCommandHandler
|
||||||
|
com.alibaba.csp.sentinel.cluster.server.command.handler.FetchClusterParamFlowRulesCommandHandler
|
||||||
|
com.alibaba.csp.sentinel.cluster.server.command.handler.FetchClusterServerConfigHandler
|
||||||
|
com.alibaba.csp.sentinel.cluster.server.command.handler.ModifyClusterServerTransportConfigHandler
|
||||||
|
com.alibaba.csp.sentinel.cluster.server.command.handler.ModifyServerNamespaceSetHandler
|
||||||
|
com.alibaba.csp.sentinel.cluster.server.command.handler.ModifyClusterFlowRulesCommandHandler
|
||||||
|
com.alibaba.csp.sentinel.cluster.server.command.handler.ModifyClusterParamFlowRulesCommandHandler
|
||||||
|
com.alibaba.csp.sentinel.cluster.server.command.handler.FetchClusterServerInfoCommandHandler
|
||||||
|
|
@ -32,10 +32,9 @@ import static com.alibaba.csp.sentinel.cluster.ClusterFlowTestUtil.*;
|
||||||
* @author Eric Zhao
|
* @author Eric Zhao
|
||||||
* @since 1.4.0
|
* @since 1.4.0
|
||||||
*/
|
*/
|
||||||
@Ignore
|
|
||||||
public class ClusterFlowCheckerTest {
|
public class ClusterFlowCheckerTest {
|
||||||
|
|
||||||
@Test
|
//@Test
|
||||||
public void testAcquireClusterTokenOccupyPass() {
|
public void testAcquireClusterTokenOccupyPass() {
|
||||||
long flowId = 98765L;
|
long flowId = 98765L;
|
||||||
final int threshold = 5;
|
final int threshold = 5;
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,10 @@ public final class ClusterStateManager {
|
||||||
mode = CLUSTER_CLIENT;
|
mode = CLUSTER_CLIENT;
|
||||||
sleepIfNeeded();
|
sleepIfNeeded();
|
||||||
lastModified = TimeUtil.currentTimeMillis();
|
lastModified = TimeUtil.currentTimeMillis();
|
||||||
|
return startClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean startClient() {
|
||||||
try {
|
try {
|
||||||
EmbeddedClusterTokenServer server = EmbeddedClusterTokenServerProvider.getServer();
|
EmbeddedClusterTokenServer server = EmbeddedClusterTokenServerProvider.getServer();
|
||||||
if (server != null) {
|
if (server != null) {
|
||||||
|
|
@ -104,6 +108,23 @@ public final class ClusterStateManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean stopClient() {
|
||||||
|
try {
|
||||||
|
ClusterTokenClient tokenClient = TokenClientProvider.getClient();
|
||||||
|
if (tokenClient != null) {
|
||||||
|
tokenClient.stop();
|
||||||
|
RecordLog.info("[ClusterStateManager] Stopping the cluster token client");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
RecordLog.warn("[ClusterStateManager] Cannot stop cluster token client (no server SPI found)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
RecordLog.warn("[ClusterStateManager] Error when stopping cluster token client", ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Set current mode to server mode. If Sentinel currently works in client mode,
|
* Set current mode to server mode. If Sentinel currently works in client mode,
|
||||||
|
|
@ -117,6 +138,10 @@ public final class ClusterStateManager {
|
||||||
mode = CLUSTER_SERVER;
|
mode = CLUSTER_SERVER;
|
||||||
sleepIfNeeded();
|
sleepIfNeeded();
|
||||||
lastModified = TimeUtil.currentTimeMillis();
|
lastModified = TimeUtil.currentTimeMillis();
|
||||||
|
return startServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean startServer() {
|
||||||
try {
|
try {
|
||||||
ClusterTokenClient tokenClient = TokenClientProvider.getClient();
|
ClusterTokenClient tokenClient = TokenClientProvider.getClient();
|
||||||
if (tokenClient != null) {
|
if (tokenClient != null) {
|
||||||
|
|
@ -137,6 +162,23 @@ public final class ClusterStateManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean stopServer() {
|
||||||
|
try {
|
||||||
|
EmbeddedClusterTokenServer server = EmbeddedClusterTokenServerProvider.getServer();
|
||||||
|
if (server != null) {
|
||||||
|
server.stop();
|
||||||
|
RecordLog.info("[ClusterStateManager] Stopping the cluster server");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
RecordLog.warn("[ClusterStateManager] Cannot stop server (no server SPI found)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
RecordLog.warn("[ClusterStateManager] Error when stopping server", ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The interval between two change operations should be greater than {@code MIN_INTERVAL} (by default 10s).
|
* The interval between two change operations should be greater than {@code MIN_INTERVAL} (by default 10s).
|
||||||
* Or we need to wait for a while.
|
* Or we need to wait for a while.
|
||||||
|
|
@ -163,12 +205,12 @@ public final class ClusterStateManager {
|
||||||
|
|
||||||
private static class ClusterStatePropertyListener implements PropertyListener<Integer> {
|
private static class ClusterStatePropertyListener implements PropertyListener<Integer> {
|
||||||
@Override
|
@Override
|
||||||
public void configLoad(Integer value) {
|
public synchronized void configLoad(Integer value) {
|
||||||
applyState(value);
|
applyState(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configUpdate(Integer value) {
|
public synchronized void configUpdate(Integer value) {
|
||||||
applyState(value);
|
applyState(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -177,6 +219,9 @@ public final class ClusterStateManager {
|
||||||
if (state == null || state < 0) {
|
if (state == null || state < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (state == mode) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
synchronized (UPDATE_LOCK) {
|
synchronized (UPDATE_LOCK) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case CLUSTER_CLIENT:
|
case CLUSTER_CLIENT:
|
||||||
|
|
@ -190,5 +235,5 @@ public final class ClusterStateManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int MIN_INTERVAL = 10 * 1000;
|
private static final int MIN_INTERVAL = 5 * 1000;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,16 @@ import com.alibaba.csp.sentinel.node.Node;
|
||||||
*/
|
*/
|
||||||
public interface TrafficShapingController {
|
public interface TrafficShapingController {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether given resource entry can pass with provided count.
|
||||||
|
*
|
||||||
|
* @param node resource node
|
||||||
|
* @param acquireCount count to acquire
|
||||||
|
* @param prioritized whether the request is prioritized
|
||||||
|
* @return true if the resource entry can pass; false if it should be blocked
|
||||||
|
*/
|
||||||
|
boolean canPass(Node node, int acquireCount, boolean prioritized);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether given resource entry can pass with provided count.
|
* Check whether given resource entry can pass with provided count.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,11 @@ public class DefaultController implements TrafficShapingController {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canPass(Node node, int acquireCount) {
|
public boolean canPass(Node node, int acquireCount) {
|
||||||
|
return canPass(node, acquireCount, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPass(Node node, int acquireCount, boolean prioritized) {
|
||||||
int curCount = avgUsedTokens(node);
|
int curCount = avgUsedTokens(node);
|
||||||
if (curCount + acquireCount > count) {
|
if (curCount + acquireCount > count) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -51,4 +56,11 @@ public class DefaultController implements TrafficShapingController {
|
||||||
return grade == RuleConstant.FLOW_GRADE_THREAD ? node.curThreadNum() : (int)node.passQps();
|
return grade == RuleConstant.FLOW_GRADE_THREAD ? node.curThreadNum() : (int)node.passQps();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void sleep(int timeMillis) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(timeMillis);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// Ignore.
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,11 @@ public class RateLimiterController implements TrafficShapingController {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canPass(Node node, int acquireCount) {
|
public boolean canPass(Node node, int acquireCount) {
|
||||||
|
return canPass(node, acquireCount, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPass(Node node, int acquireCount, boolean prioritized) {
|
||||||
long currentTime = TimeUtil.currentTimeMillis();
|
long currentTime = TimeUtil.currentTimeMillis();
|
||||||
// Calculate the interval between every two requests.
|
// Calculate the interval between every two requests.
|
||||||
long costTime = Math.round(1.0 * (acquireCount) / count * 1000);
|
long costTime = Math.round(1.0 * (acquireCount) / count * 1000);
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,11 @@ public class WarmUpController implements TrafficShapingController {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canPass(Node node, int acquireCount) {
|
public boolean canPass(Node node, int acquireCount) {
|
||||||
|
return canPass(node, acquireCount, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPass(Node node, int acquireCount, boolean prioritized) {
|
||||||
long passQps = node.passQps();
|
long passQps = node.passQps();
|
||||||
|
|
||||||
long previousQps = node.previousPassQps();
|
long previousQps = node.previousPassQps();
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,11 @@ public class WarmUpRateLimiterController extends WarmUpController {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canPass(Node node, int acquireCount) {
|
public boolean canPass(Node node, int acquireCount) {
|
||||||
|
return canPass(node, acquireCount, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPass(Node node, int acquireCount, boolean prioritized) {
|
||||||
long previousQps = node.previousPassQps();
|
long previousQps = node.previousPassQps();
|
||||||
syncToken(previousQps);
|
syncToken(previousQps);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
package com.alibaba.csp.sentinel.slots.statistic.data;
|
package com.alibaba.csp.sentinel.slots.statistic.data;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.Constants;
|
import com.alibaba.csp.sentinel.Constants;
|
||||||
|
import com.alibaba.csp.sentinel.slots.statistic.MetricEvent;
|
||||||
import com.alibaba.csp.sentinel.slots.statistic.base.LongAdder;
|
import com.alibaba.csp.sentinel.slots.statistic.base.LongAdder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -26,15 +27,16 @@ import com.alibaba.csp.sentinel.slots.statistic.base.LongAdder;
|
||||||
*/
|
*/
|
||||||
public class MetricBucket {
|
public class MetricBucket {
|
||||||
|
|
||||||
private final LongAdder pass = new LongAdder();
|
private final LongAdder[] counters;
|
||||||
private final LongAdder block = new LongAdder();
|
|
||||||
private final LongAdder exception = new LongAdder();
|
|
||||||
private final LongAdder rt = new LongAdder();
|
|
||||||
private final LongAdder success = new LongAdder();
|
|
||||||
|
|
||||||
private volatile long minRt;
|
private volatile long minRt;
|
||||||
|
|
||||||
public MetricBucket() {
|
public MetricBucket() {
|
||||||
|
MetricEvent[] events = MetricEvent.values();
|
||||||
|
this.counters = new LongAdder[events.length];
|
||||||
|
for (MetricEvent event : events) {
|
||||||
|
counters[event.ordinal()] = new LongAdder();
|
||||||
|
}
|
||||||
initMinRt();
|
initMinRt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,29 +50,36 @@ public class MetricBucket {
|
||||||
* @return new metric bucket in initial state
|
* @return new metric bucket in initial state
|
||||||
*/
|
*/
|
||||||
public MetricBucket reset() {
|
public MetricBucket reset() {
|
||||||
pass.reset();
|
for (MetricEvent event : MetricEvent.values()) {
|
||||||
block.reset();
|
counters[event.ordinal()].reset();
|
||||||
exception.reset();
|
}
|
||||||
rt.reset();
|
|
||||||
success.reset();
|
|
||||||
initMinRt();
|
initMinRt();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long get(MetricEvent event) {
|
||||||
|
return counters[event.ordinal()].sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MetricBucket add(MetricEvent event, long n) {
|
||||||
|
counters[event.ordinal()].add(n);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public long pass() {
|
public long pass() {
|
||||||
return pass.sum();
|
return get(MetricEvent.PASS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long block() {
|
public long block() {
|
||||||
return block.sum();
|
return get(MetricEvent.BLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long exception() {
|
public long exception() {
|
||||||
return exception.sum();
|
return get(MetricEvent.EXCEPTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long rt() {
|
public long rt() {
|
||||||
return rt.sum();
|
return get(MetricEvent.RT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long minRt() {
|
public long minRt() {
|
||||||
|
|
@ -78,27 +87,27 @@ public class MetricBucket {
|
||||||
}
|
}
|
||||||
|
|
||||||
public long success() {
|
public long success() {
|
||||||
return success.sum();
|
return get(MetricEvent.SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addPass() {
|
public void addPass() {
|
||||||
pass.add(1L);
|
add(MetricEvent.PASS, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addException() {
|
public void addException() {
|
||||||
exception.add(1L);
|
add(MetricEvent.EXCEPTION, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addBlock() {
|
public void addBlock() {
|
||||||
block.add(1L);
|
add(MetricEvent.BLOCK, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSuccess() {
|
public void addSuccess() {
|
||||||
success.add(1L);
|
add(MetricEvent.SUCCESS, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addRT(long rt) {
|
public void addRT(long rt) {
|
||||||
this.rt.add(rt);
|
add(MetricEvent.RT, rt);
|
||||||
|
|
||||||
// Not thread-safe, but it's okay.
|
// Not thread-safe, but it's okay.
|
||||||
if (rt < minRt) {
|
if (rt < minRt) {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.alibaba.csp.sentinel.command.handler;
|
package com.alibaba.csp.sentinel.command.handler.cluster;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.cluster.ClusterStateManager;
|
import com.alibaba.csp.sentinel.cluster.ClusterStateManager;
|
||||||
import com.alibaba.csp.sentinel.cluster.client.TokenClientProvider;
|
import com.alibaba.csp.sentinel.cluster.client.TokenClientProvider;
|
||||||
|
|
@ -13,13 +13,14 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.alibaba.csp.sentinel.command.handler;
|
package com.alibaba.csp.sentinel.command.handler.cluster;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.cluster.ClusterStateManager;
|
import com.alibaba.csp.sentinel.cluster.ClusterStateManager;
|
||||||
import com.alibaba.csp.sentinel.command.CommandHandler;
|
import com.alibaba.csp.sentinel.command.CommandHandler;
|
||||||
import com.alibaba.csp.sentinel.command.CommandRequest;
|
import com.alibaba.csp.sentinel.command.CommandRequest;
|
||||||
import com.alibaba.csp.sentinel.command.CommandResponse;
|
import com.alibaba.csp.sentinel.command.CommandResponse;
|
||||||
import com.alibaba.csp.sentinel.command.annotation.CommandMapping;
|
import com.alibaba.csp.sentinel.command.annotation.CommandMapping;
|
||||||
|
import com.alibaba.csp.sentinel.log.RecordLog;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Eric Zhao
|
* @author Eric Zhao
|
||||||
|
|
@ -32,6 +33,7 @@ public class ModifyClusterModeCommandHandler implements CommandHandler<String> {
|
||||||
public CommandResponse<String> handle(CommandRequest request) {
|
public CommandResponse<String> handle(CommandRequest request) {
|
||||||
try {
|
try {
|
||||||
int mode = Integer.valueOf(request.getParam("mode"));
|
int mode = Integer.valueOf(request.getParam("mode"));
|
||||||
|
RecordLog.info("[ModifyClusterModeCommandHandler] Modifying cluster mode to: " + mode);
|
||||||
if (ClusterStateManager.applyState(mode)) {
|
if (ClusterStateManager.applyState(mode)) {
|
||||||
return CommandResponse.ofSuccess("success");
|
return CommandResponse.ofSuccess("success");
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -12,5 +12,5 @@ com.alibaba.csp.sentinel.command.handler.OnOffGetCommandHandler
|
||||||
com.alibaba.csp.sentinel.command.handler.OnOffSetCommandHandler
|
com.alibaba.csp.sentinel.command.handler.OnOffSetCommandHandler
|
||||||
com.alibaba.csp.sentinel.command.handler.SendMetricCommandHandler
|
com.alibaba.csp.sentinel.command.handler.SendMetricCommandHandler
|
||||||
com.alibaba.csp.sentinel.command.handler.VersionCommandHandler
|
com.alibaba.csp.sentinel.command.handler.VersionCommandHandler
|
||||||
com.alibaba.csp.sentinel.command.handler.FetchClusterModeCommandHandler
|
com.alibaba.csp.sentinel.command.handler.cluster.FetchClusterModeCommandHandler
|
||||||
com.alibaba.csp.sentinel.command.handler.ModifyClusterModeCommandHandler
|
com.alibaba.csp.sentinel.command.handler.cluster.ModifyClusterModeCommandHandler
|
||||||
Loading…
Reference in New Issue