Refactor the mechanism of recording error in Entry and StatisticSlot

* Also polish related complete callbacks

Signed-off-by: Eric Zhao <sczyh16@gmail.com>
This commit is contained in:
Eric Zhao 2020-04-26 20:59:29 +08:00
parent 7f0771df5c
commit 7f3165740a
5 changed files with 71 additions and 47 deletions

View File

@ -15,6 +15,7 @@
*/
package com.alibaba.csp.sentinel;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.util.TimeUtil;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.node.Node;
@ -44,6 +45,7 @@ import com.alibaba.csp.sentinel.context.Context;
* @author qinan.qn
* @author jialiang.linjl
* @author leyou(lihao)
* @author Eric Zhao
* @see SphU
* @see Context
* @see ContextUtil
@ -52,18 +54,23 @@ public abstract class Entry implements AutoCloseable {
private static final Object[] OBJECTS0 = new Object[0];
private long createTime;
private final long createTimestamp;
private long completeTimestamp;
private Node curNode;
/**
* {@link Node} of the specific origin, Usually the origin is the Service Consumer.
*/
private Node originNode;
private Throwable error;
protected ResourceWrapper resourceWrapper;
private BlockException blockError;
protected final ResourceWrapper resourceWrapper;
public Entry(ResourceWrapper resourceWrapper) {
this.resourceWrapper = resourceWrapper;
this.createTime = TimeUtil.currentTimeMillis();
this.createTimestamp = TimeUtil.currentTimeMillis();
}
public ResourceWrapper getResourceWrapper() {
@ -119,8 +126,17 @@ public abstract class Entry implements AutoCloseable {
*/
public abstract Node getLastNode();
public long getCreateTime() {
return createTime;
public long getCreateTimestamp() {
return createTimestamp;
}
public long getCompleteTimestamp() {
return completeTimestamp;
}
public Entry setCompleteTimestamp(long completeTimestamp) {
this.completeTimestamp = completeTimestamp;
return this;
}
public Node getCurNode() {
@ -131,6 +147,15 @@ public abstract class Entry implements AutoCloseable {
this.curNode = node;
}
public BlockException getBlockError() {
return blockError;
}
public Entry setBlockError(BlockException blockError) {
this.blockError = blockError;
return this;
}
public Throwable getError() {
return error;
}

View File

@ -14,14 +14,22 @@ import com.alibaba.csp.sentinel.util.TimeUtil;
* @since 1.6.1
*/
public class MetricExitCallback implements ProcessorSlotExitCallback {
@Override
public void onExit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
for (MetricExtension m : MetricExtensionProvider.getMetricExtensions()) {
if (context.getCurEntry().getError() == null) {
long realRt = TimeUtil.currentTimeMillis() - context.getCurEntry().getCreateTime();
m.addRt(resourceWrapper.getName(), realRt, args);
m.addSuccess(resourceWrapper.getName(), count, args);
m.decreaseThreadNum(resourceWrapper.getName(), args);
if (context.getCurEntry().getBlockError() != null) {
continue;
}
String resource = resourceWrapper.getName();
long realRt = TimeUtil.currentTimeMillis() - context.getCurEntry().getCreateTimestamp();
m.addRt(resource, realRt, args);
m.addSuccess(resource, count, args);
m.decreaseThreadNum(resource, args);
Throwable ex = context.getCurEntry().getError();
if (ex != null) {
m.addException(resource, count, ex);
}
}
}

View File

@ -17,7 +17,7 @@ package com.alibaba.csp.sentinel.slots.statistic;
import java.util.Collection;
import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.node.Node;
import com.alibaba.csp.sentinel.slotchain.ProcessorSlotEntryCallback;
import com.alibaba.csp.sentinel.slotchain.ProcessorSlotExitCallback;
import com.alibaba.csp.sentinel.slots.block.flow.PriorityWaitException;
@ -95,7 +95,7 @@ public class StatisticSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
}
} catch (BlockException e) {
// Blocked, set block exception to current entry.
context.getCurEntry().setError(e);
context.getCurEntry().setBlockError(e);
// Add block count.
node.increaseBlockQps(count);
@ -115,52 +115,31 @@ public class StatisticSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
throw e;
} catch (Throwable e) {
// Unexpected error, set error to current entry.
// Unexpected internal error, set error to current entry.
context.getCurEntry().setError(e);
// This should not happen.
node.increaseExceptionQps(count);
if (context.getCurEntry().getOriginNode() != null) {
context.getCurEntry().getOriginNode().increaseExceptionQps(count);
}
if (resourceWrapper.getEntryType() == EntryType.IN) {
Constants.ENTRY_NODE.increaseExceptionQps(count);
}
throw e;
}
}
@Override
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
DefaultNode node = (DefaultNode)context.getCurNode();
Node node = context.getCurNode();
if (context.getCurEntry().getError() == null) {
// Calculate response time (max RT is statisticMaxRt from SentinelConfig).
long rt = TimeUtil.currentTimeMillis() - context.getCurEntry().getCreateTime();
int maxStatisticRt = SentinelConfig.statisticMaxRt();
if (rt > maxStatisticRt) {
rt = maxStatisticRt;
}
if (context.getCurEntry().getBlockError() == null) {
// Calculate response time (use completeStatTime as the time of completion).
long completeStatTime = TimeUtil.currentTimeMillis();
context.getCurEntry().setCompleteTimestamp(completeStatTime);
long rt = completeStatTime - context.getCurEntry().getCreateTimestamp();
Throwable error = context.getCurEntry().getError();
// Record response time and success count.
node.addRtAndSuccess(rt, count);
if (context.getCurEntry().getOriginNode() != null) {
context.getCurEntry().getOriginNode().addRtAndSuccess(rt, count);
}
node.decreaseThreadNum();
if (context.getCurEntry().getOriginNode() != null) {
context.getCurEntry().getOriginNode().decreaseThreadNum();
}
recordCompleteFor(node, count, rt, error);
recordCompleteFor(context.getCurEntry().getOriginNode(), count, rt, error);
if (resourceWrapper.getEntryType() == EntryType.IN) {
Constants.ENTRY_NODE.addRtAndSuccess(rt, count);
Constants.ENTRY_NODE.decreaseThreadNum();
recordCompleteFor(Constants.ENTRY_NODE, count, rt, error);
}
} else {
// Error may happen.
}
// Handle exit event with registered exit callback handlers.
@ -171,4 +150,16 @@ public class StatisticSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
fireExit(context, resourceWrapper, count);
}
private void recordCompleteFor(Node node, int batchCount, long rt, Throwable error) {
if (node == null) {
return;
}
node.addRtAndSuccess(rt, batchCount);
node.decreaseThreadNum();
if (error != null && !(error instanceof BlockException)) {
node.increaseExceptionQps(batchCount);
}
}
}

View File

@ -55,7 +55,7 @@ public class MetricExitCallbackTest extends AbstractTimeBasedTest {
int deltaMs = 100;
when(entry.getError()).thenReturn(null);
when(entry.getCreateTime()).thenReturn(curMillis - deltaMs);
when(entry.getCreateTimestamp()).thenReturn(curMillis - deltaMs);
when(context.getCurEntry()).thenReturn(entry);
exitCallback.onExit(context, resourceWrapper, count, args);
Assert.assertEquals(prevRt + deltaMs, extension.rt);

View File

@ -29,7 +29,7 @@ public class ParamFlowStatisticExitCallback implements ProcessorSlotExitCallback
@Override
public void onExit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
if (context.getCurEntry().getError() == null) {
if (context.getCurEntry().getBlockError() == null) {
ParameterMetric parameterMetric = ParameterMetricStorage.getParamMetric(resourceWrapper);
if (parameterMetric != null) {