use of com.alibaba.csp.sentinel.cluster.TokenResult in project Sentinel by alibaba.
the class ConcurrentClusterFlowCheckerTest method testEasyAcquireAndRelease.
@Test
public void testEasyAcquireAndRelease() throws InterruptedException {
setCurrentMillis(System.currentTimeMillis());
FlowRule rule = ClusterFlowRuleManager.getFlowRuleById(111L);
ArrayList<Long> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
TokenResult result = ConcurrentClusterFlowChecker.acquireConcurrentToken("127.0.0.1", rule, 1);
Assert.assertTrue("fail to acquire token", result.getStatus() == TokenResultStatus.OK && result.getTokenId() != 0);
list.add(result.getTokenId());
}
for (int i = 0; i < 10; i++) {
TokenResult result = ConcurrentClusterFlowChecker.acquireConcurrentToken("127.0.0.1", rule, 1);
Assert.assertTrue("fail to acquire block token", result.getStatus() == TokenResultStatus.BLOCKED);
}
for (int i = 0; i < 10; i++) {
TokenResult result = ConcurrentClusterFlowChecker.releaseConcurrentToken(list.get(i));
Assert.assertTrue("fail to release token", result.getStatus() == TokenResultStatus.RELEASE_OK);
}
Assert.assertTrue("fail to release token", CurrentConcurrencyManager.get(111L).get() == 0 && TokenCacheNodeManager.getSize() == 0);
}
use of com.alibaba.csp.sentinel.cluster.TokenResult in project Sentinel by alibaba.
the class DefaultClusterTokenClient method requestToken.
@Override
public TokenResult requestToken(Long flowId, int acquireCount, boolean prioritized) {
if (notValidRequest(flowId, acquireCount)) {
return badRequest();
}
FlowRequestData data = new FlowRequestData().setCount(acquireCount).setFlowId(flowId).setPriority(prioritized);
ClusterRequest<FlowRequestData> request = new ClusterRequest<>(ClusterConstants.MSG_TYPE_FLOW, data);
try {
TokenResult result = sendTokenRequest(request);
logForResult(result);
return result;
} catch (Exception ex) {
ClusterClientStatLogUtil.log(ex.getMessage());
return new TokenResult(TokenResultStatus.FAIL);
}
}
use of com.alibaba.csp.sentinel.cluster.TokenResult in project Sentinel by alibaba.
the class ClusterFlowChecker method acquireClusterToken.
static TokenResult acquireClusterToken(/*@Valid*/
FlowRule rule, int acquireCount, boolean prioritized) {
Long id = rule.getClusterConfig().getFlowId();
if (!allowProceed(id)) {
return new TokenResult(TokenResultStatus.TOO_MANY_REQUEST);
}
ClusterMetric metric = ClusterMetricStatistics.getMetric(id);
if (metric == null) {
return new TokenResult(TokenResultStatus.FAIL);
}
double latestQps = metric.getAvg(ClusterFlowEvent.PASS);
double globalThreshold = calcGlobalThreshold(rule) * ClusterServerConfigManager.getExceedCount();
double nextRemaining = globalThreshold - latestQps - acquireCount;
if (nextRemaining >= 0) {
// TODO: checking logic and metric operation should be separated.
metric.add(ClusterFlowEvent.PASS, acquireCount);
metric.add(ClusterFlowEvent.PASS_REQUEST, 1);
if (prioritized) {
// Add prioritized pass.
metric.add(ClusterFlowEvent.OCCUPIED_PASS, acquireCount);
}
// Remaining count is cut down to a smaller integer.
return new TokenResult(TokenResultStatus.OK).setRemaining((int) nextRemaining).setWaitInMs(0);
} else {
if (prioritized) {
// Try to occupy incoming buckets.
double occupyAvg = metric.getAvg(ClusterFlowEvent.WAITING);
if (occupyAvg <= ClusterServerConfigManager.getMaxOccupyRatio() * globalThreshold) {
int waitInMs = metric.tryOccupyNext(ClusterFlowEvent.PASS, acquireCount, globalThreshold);
// waitInMs > 0 indicates pre-occupy incoming buckets successfully.
if (waitInMs > 0) {
ClusterServerStatLogUtil.log("flow|waiting|" + id);
return new TokenResult(TokenResultStatus.SHOULD_WAIT).setRemaining(0).setWaitInMs(waitInMs);
}
// Or else occupy failed, should be blocked.
}
}
// Blocked.
metric.add(ClusterFlowEvent.BLOCK, acquireCount);
metric.add(ClusterFlowEvent.BLOCK_REQUEST, 1);
ClusterServerStatLogUtil.log("flow|block|" + id, acquireCount);
ClusterServerStatLogUtil.log("flow|block_request|" + id, 1);
if (prioritized) {
// Add prioritized block.
metric.add(ClusterFlowEvent.OCCUPIED_BLOCK, acquireCount);
ClusterServerStatLogUtil.log("flow|occupied_block|" + id, 1);
}
return blockedResult();
}
}
use of com.alibaba.csp.sentinel.cluster.TokenResult in project Sentinel by alibaba.
the class ClusterParamFlowChecker method acquireClusterToken.
static TokenResult acquireClusterToken(ParamFlowRule rule, int count, Collection<Object> values) {
Long id = rule.getClusterConfig().getFlowId();
if (!allowProceed(id)) {
return new TokenResult(TokenResultStatus.TOO_MANY_REQUEST);
}
ClusterParamMetric metric = ClusterParamMetricStatistics.getMetric(id);
if (metric == null) {
// Unexpected state, return FAIL.
return new TokenResult(TokenResultStatus.FAIL);
}
if (values == null || values.isEmpty()) {
// Empty parameter list will always pass.
return new TokenResult(TokenResultStatus.OK);
}
double remaining = -1;
boolean hasPassed = true;
Object blockObject = null;
for (Object value : values) {
double latestQps = metric.getAvg(value);
double threshold = calcGlobalThreshold(rule, value);
double nextRemaining = threshold - latestQps - count;
remaining = nextRemaining;
if (nextRemaining < 0) {
hasPassed = false;
blockObject = value;
break;
}
}
if (hasPassed) {
for (Object value : values) {
metric.addValue(value, count);
}
ClusterServerStatLogUtil.log(String.format("param|pass|%d", id));
} else {
ClusterServerStatLogUtil.log(String.format("param|block|%d|%s", id, blockObject));
}
if (values.size() > 1) {
// Remaining field is unsupported for multi-values.
remaining = -1;
}
return hasPassed ? newPassResponse((int) remaining) : newBlockResponse();
}
use of com.alibaba.csp.sentinel.cluster.TokenResult in project Sentinel by alibaba.
the class ConcurrentClusterFlowChecker method acquireConcurrentToken.
public static TokenResult acquireConcurrentToken(/*@Valid*/
String clientAddress, FlowRule rule, int acquireCount) {
long flowId = rule.getClusterConfig().getFlowId();
AtomicInteger nowCalls = CurrentConcurrencyManager.get(flowId);
if (nowCalls == null) {
RecordLog.warn("[ConcurrentClusterFlowChecker] Fail to get nowCalls by flowId<{}>", flowId);
return new TokenResult(TokenResultStatus.FAIL);
}
// check before enter the lock to improve the efficiency
if (nowCalls.get() + acquireCount > calcGlobalThreshold(rule)) {
ClusterServerStatLogUtil.log("concurrent|block|" + flowId, acquireCount);
return new TokenResult(TokenResultStatus.BLOCKED);
}
// lock different nowCalls to improve the efficiency
synchronized (nowCalls) {
// check again whether the request can pass.
if (nowCalls.get() + acquireCount > calcGlobalThreshold(rule)) {
ClusterServerStatLogUtil.log("concurrent|block|" + flowId, acquireCount);
return new TokenResult(TokenResultStatus.BLOCKED);
} else {
nowCalls.getAndAdd(acquireCount);
}
}
ClusterServerStatLogUtil.log("concurrent|pass|" + flowId, acquireCount);
TokenCacheNode node = TokenCacheNode.generateTokenCacheNode(rule, acquireCount, clientAddress);
TokenCacheNodeManager.putTokenCacheNode(node.getTokenId(), node);
TokenResult tokenResult = new TokenResult(TokenResultStatus.OK);
tokenResult.setTokenId(node.getTokenId());
return tokenResult;
}
Aggregations