Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Span amount control mechanism, also memory limit mechanism #570

Merged
merged 5 commits into from
Nov 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions apm-network/src/main/proto/TraceSegmentService.proto
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ message TraceSegmentObject {
repeated SpanObject spans = 3;
int32 applicationId = 4;
int32 applicationInstanceId = 5;
bool isSizeLimited = 6;
}

message TraceSegmentReference {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,27 @@ public class Config {

public static class Agent {
/**
* Application code is showed in sky-walking-ui.
* Suggestion: set an unique name for each application, one application's nodes share the same code.
* Application code is showed in sky-walking-ui. Suggestion: set an unique name for each application, one
* application's nodes share the same code.
*/
public static String APPLICATION_CODE = "";

/**
* Negative or zero means off, by default.
* {@link #SAMPLE_N_PER_3_SECS} means sampling N {@link TraceSegment} in 10 seconds tops.
* Negative or zero means off, by default. {@link #SAMPLE_N_PER_3_SECS} means sampling N {@link TraceSegment} in
* 10 seconds tops.
*/
public static int SAMPLE_N_PER_3_SECS = -1;

/**
* If the operation name of the first span is included in this set,
* this segment should be ignored.
* If the operation name of the first span is included in this set, this segment should be ignored.
*/
public static String IGNORE_SUFFIX = ".jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg";

/**
* The max number of spans in a single segment. Through this config item, skywalking keep your application
* memory cost estimated.
*/
public static int SPAN_LIMIT_PER_SEGMENT = 300;
}

public static class Collector {
Expand All @@ -63,9 +68,7 @@ public static class Collector {
*/
public static long DISCOVERY_CHECK_INTERVAL = 60;
/**
* Collector REST-Service address.
* e.g.
* SERVERS="127.0.0.1:8080" for single collector node.
* Collector REST-Service address. e.g. SERVERS="127.0.0.1:8080" for single collector node.
* SERVERS="10.2.45.126:8080,10.2.45.127:7600" for multi collector nodes.
*/
public static String SERVERS = "";
Expand Down Expand Up @@ -105,16 +108,15 @@ public static class Logging {
public static String FILE_NAME = "skywalking-api.log";

/**
* Log files directory.
* Default is blank string, means, use "system.out" to output logs.
* Log files directory. Default is blank string, means, use "system.out" to output logs.
*
* @see {@link WriterFactory#getLogWriter()}
*/
public static String DIR = "";

/**
* The max size of log file.
* If the size is bigger than this, archive the current file, and write into a new file.
* The max size of log file. If the size is bigger than this, archive the current file, and write into a new
* file.
*/
public static int MAX_FILE_SIZE = 300 * 1024 * 1024;

Expand All @@ -129,8 +131,7 @@ public static class Logging {
public static class Plugin {
public static class MongoDB {
/**
* If true, trace all the parameters, default is false.
* Only trace the operation, not include parameters.
* If true, trace all the parameters, default is false. Only trace the operation, not include parameters.
*/
public static boolean TRACE_PARAM = false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,32 @@
import java.util.LinkedList;
import java.util.List;
import org.skywalking.apm.agent.core.boot.ServiceManager;
import org.skywalking.apm.agent.core.conf.Config;
import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.skywalking.apm.agent.core.context.trace.EntrySpan;
import org.skywalking.apm.agent.core.context.trace.ExitSpan;
import org.skywalking.apm.agent.core.context.trace.LocalSpan;
import org.skywalking.apm.agent.core.context.trace.NoopExitSpan;
import org.skywalking.apm.agent.core.context.trace.NoopSpan;
import org.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.skywalking.apm.agent.core.context.trace.TraceSegmentRef;
import org.skywalking.apm.agent.core.context.trace.WithPeerInfo;
import org.skywalking.apm.agent.core.dictionary.DictionaryManager;
import org.skywalking.apm.agent.core.dictionary.DictionaryUtil;
import org.skywalking.apm.agent.core.dictionary.PossibleFound;
import org.skywalking.apm.agent.core.sampling.SamplingService;

/**
* The <code>TracingContext</code> represents a core tracing logic controller.
* It build the final {@link TracingContext}, by the stack mechanism,
* which is similar with the codes work.
* The <code>TracingContext</code> represents a core tracing logic controller. It build the final {@link
* TracingContext}, by the stack mechanism, which is similar with the codes work.
*
* In opentracing concept, it means, all spans in a segment tracing context(thread)
* are CHILD_OF relationship, but no FOLLOW_OF.
* In opentracing concept, it means, all spans in a segment tracing context(thread) are CHILD_OF relationship, but no
* FOLLOW_OF.
*
* In skywalking core concept, FOLLOW_OF is an abstract concept
* when cross-process MQ or cross-thread async/batch tasks happen,
* we used {@link TraceSegmentRef} for these scenarios.
* Check {@link TraceSegmentRef} which is from {@link ContextCarrier} or {@link ContextSnapshot}.
* In skywalking core concept, FOLLOW_OF is an abstract concept when cross-process MQ or cross-thread async/batch tasks
* happen, we used {@link TraceSegmentRef} for these scenarios. Check {@link TraceSegmentRef} which is from {@link
* ContextCarrier} or {@link ContextSnapshot}.
*
* @author wusheng
*/
Expand All @@ -60,13 +62,11 @@ public class TracingContext implements AbstractTracerContext {
private TraceSegment segment;

/**
* Active spans stored in a Stack, usually called 'ActiveSpanStack'.
* This {@link LinkedList} is the in-memory storage-structure.
* <p>
* I use {@link LinkedList#removeLast()}, {@link LinkedList#addLast(Object)} and {@link LinkedList#last} instead of
* {@link #pop()}, {@link #push(AbstractTracingSpan)}, {@link #peek()}
* Active spans stored in a Stack, usually called 'ActiveSpanStack'. This {@link LinkedList} is the in-memory
* storage-structure. <p> I use {@link LinkedList#removeLast()}, {@link LinkedList#addLast(Object)} and {@link
* LinkedList#last} instead of {@link #pop()}, {@link #push(AbstractSpan)}, {@link #peek()}
*/
private LinkedList<AbstractTracingSpan> activeSpanStack = new LinkedList<AbstractTracingSpan>();
private LinkedList<AbstractSpan> activeSpanStack = new LinkedList<AbstractSpan>();

/**
* A counter for the next span.
Expand All @@ -93,21 +93,24 @@ public class TracingContext implements AbstractTracerContext {
*/
@Override
public void inject(ContextCarrier carrier) {
AbstractTracingSpan span = this.activeSpan();
AbstractSpan span = this.activeSpan();
if (!span.isExit()) {
throw new IllegalStateException("Inject can be done only in Exit Span");
}
ExitSpan exitSpan = (ExitSpan)span;

WithPeerInfo spanWithPeer = (WithPeerInfo)span;
String peer = spanWithPeer.getPeer();
int peerId = spanWithPeer.getPeerId();

carrier.setTraceSegmentId(this.segment.getTraceSegmentId());
carrier.setSpanId(span.getSpanId());

carrier.setParentApplicationInstanceId(segment.getApplicationInstanceId());

if (DictionaryUtil.isNull(exitSpan.getPeerId())) {
carrier.setPeerHost(exitSpan.getPeer());
if (DictionaryUtil.isNull(peerId)) {
carrier.setPeerHost(peer);
} else {
carrier.setPeerId(exitSpan.getPeerId());
carrier.setPeerId(peerId);
}
List<TraceSegmentRef> refs = this.segment.getRefs();
int operationId;
Expand All @@ -119,7 +122,7 @@ public void inject(ContextCarrier carrier) {
operationName = ref.getEntryOperationName();
entryApplicationInstanceId = ref.getEntryApplicationInstanceId();
} else {
AbstractTracingSpan firstSpan = first();
AbstractSpan firstSpan = first();
operationId = firstSpan.getOperationId();
operationName = firstSpan.getOperationName();
entryApplicationInstanceId = this.segment.getApplicationInstanceId();
Expand Down Expand Up @@ -169,7 +172,7 @@ public ContextSnapshot capture() {
int entryOperationId;
String entryOperationName;
int entryApplicationInstanceId;
AbstractTracingSpan firstSpan = first();
AbstractSpan firstSpan = first();
if (refs != null && refs.size() > 0) {
TraceSegmentRef ref = refs.get(0);
entryOperationId = ref.getEntryOperationId();
Expand Down Expand Up @@ -225,8 +228,12 @@ public String getReadableGlobalTraceId() {
*/
@Override
public AbstractSpan createEntrySpan(final String operationName) {
AbstractTracingSpan entrySpan;
final AbstractTracingSpan parentSpan = peek();
if (isLimitMechanismWorking()) {
NoopSpan span = new NoopSpan();
return push(span);
}
AbstractSpan entrySpan;
final AbstractSpan parentSpan = peek();
final int parentSpanId = parentSpan == null ? -1 : parentSpan.getSpanId();
if (parentSpan == null) {
entrySpan = (AbstractTracingSpan)DictionaryManager.findOperationNameCodeSection()
Expand Down Expand Up @@ -269,7 +276,11 @@ public AbstractSpan createEntrySpan(final String operationName) {
*/
@Override
public AbstractSpan createLocalSpan(final String operationName) {
AbstractTracingSpan parentSpan = peek();
if (isLimitMechanismWorking()) {
NoopSpan span = new NoopSpan();
return push(span);
}
AbstractSpan parentSpan = peek();
final int parentSpanId = parentSpan == null ? -1 : parentSpan.getSpanId();
AbstractTracingSpan span = (AbstractTracingSpan)DictionaryManager.findOperationNameCodeSection()
.findOrPrepare4Register(segment.getApplicationId(), operationName)
Expand Down Expand Up @@ -298,17 +309,21 @@ public Object doProcess() {
*/
@Override
public AbstractSpan createExitSpan(final String operationName, final String remotePeer) {
AbstractTracingSpan exitSpan;
AbstractTracingSpan parentSpan = peek();
AbstractSpan exitSpan;
AbstractSpan parentSpan = peek();
if (parentSpan != null && parentSpan.isExit()) {
exitSpan = parentSpan;
} else {
final int parentSpanId = parentSpan == null ? -1 : parentSpan.getSpanId();
exitSpan = (AbstractTracingSpan)DictionaryManager.findApplicationCodeSection()
exitSpan = (AbstractSpan)DictionaryManager.findApplicationCodeSection()
.find(remotePeer).doInCondition(
new PossibleFound.FoundAndObtain() {
@Override
public Object doProcess(final int peerId) {
if (isLimitMechanismWorking()) {
return new NoopExitSpan(peerId);
}

return DictionaryManager.findOperationNameCodeSection()
.findOnly(segment.getApplicationId(), operationName)
.doInCondition(
Expand All @@ -328,6 +343,10 @@ public Object doProcess() {
new PossibleFound.NotFoundAndObtain() {
@Override
public Object doProcess() {
if (isLimitMechanismWorking()) {
return new NoopExitSpan(remotePeer);
}

return DictionaryManager.findOperationNameCodeSection()
.findOnly(segment.getApplicationId(), operationName)
.doInCondition(
Expand All @@ -354,25 +373,30 @@ public Object doProcess() {
* @return the active span of current context, the top element of {@link #activeSpanStack}
*/
@Override
public AbstractTracingSpan activeSpan() {
AbstractTracingSpan span = peek();
public AbstractSpan activeSpan() {
AbstractSpan span = peek();
if (span == null) {
throw new IllegalStateException("No active span.");
}
return span;
}

/**
* Stop the given span, if and only if this one is the top element of {@link #activeSpanStack}.
* Because the tracing core must make sure the span must match in a stack module, like any program did.
* Stop the given span, if and only if this one is the top element of {@link #activeSpanStack}. Because the tracing
* core must make sure the span must match in a stack module, like any program did.
*
* @param span to finish
*/
@Override
public void stopSpan(AbstractSpan span) {
AbstractTracingSpan lastSpan = peek();
AbstractSpan lastSpan = peek();
if (lastSpan == span) {
if (lastSpan.finish(segment)) {
if (lastSpan instanceof AbstractTracingSpan) {
AbstractTracingSpan toFinishSpan = (AbstractTracingSpan)lastSpan;
if (toFinishSpan.finish(segment)) {
pop();
}
} else {
pop();
}
} else {
Expand All @@ -389,7 +413,7 @@ public void stopSpan(AbstractSpan span) {
* TracingContext.ListenerManager}
*/
private void finish() {
TraceSegment finishedSegment = segment.finish();
TraceSegment finishedSegment = segment.finish(isLimitMechanismWorking());
/**
* Recheck the segment if the segment contains only one span.
* Because in the runtime, can't sure this segment is part of distributed trace.
Expand Down Expand Up @@ -421,9 +445,9 @@ public static synchronized void add(TracingContextListener listener) {
}

/**
* Notify the {@link TracingContext.ListenerManager} about the given {@link TraceSegment} have finished.
* And trigger {@link TracingContext.ListenerManager} to notify all {@link #LISTENERS} 's
* {@link TracingContextListener#afterFinished(TraceSegment)}
* Notify the {@link TracingContext.ListenerManager} about the given {@link TraceSegment} have finished. And
* trigger {@link TracingContext.ListenerManager} to notify all {@link #LISTENERS} 's {@link
* TracingContextListener#afterFinished(TraceSegment)}
*
* @param finishedSegment
*/
Expand All @@ -445,7 +469,7 @@ public static synchronized void remove(TracingContextListener listener) {
/**
* @return the top element of 'ActiveSpanStack', and remove it.
*/
private AbstractTracingSpan pop() {
private AbstractSpan pop() {
return activeSpanStack.removeLast();
}

Expand All @@ -454,22 +478,26 @@ private AbstractTracingSpan pop() {
*
* @param span
*/
private AbstractTracingSpan push(AbstractTracingSpan span) {
private AbstractSpan push(AbstractSpan span) {
activeSpanStack.addLast(span);
return span;
}

/**
* @return the top element of 'ActiveSpanStack' only.
*/
private AbstractTracingSpan peek() {
private AbstractSpan peek() {
if (activeSpanStack.isEmpty()) {
return null;
}
return activeSpanStack.getLast();
}

private AbstractTracingSpan first() {
private AbstractSpan first() {
return activeSpanStack.getFirst();
}

private boolean isLimitMechanismWorking() {
return spanIdGenerator >= Config.Agent.SPAN_LIMIT_PER_SEGMENT;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@
import org.skywalking.apm.network.trace.component.Component;

/**
* The <code>AbstractSpan</code> represents the span's skeleton,
* which contains all open methods.
* The <code>AbstractSpan</code> represents the span's skeleton, which contains all open methods.
*
* @author wusheng
*/
Expand All @@ -37,8 +36,8 @@ public interface AbstractSpan {
AbstractSpan setComponent(Component component);

/**
* Only use this method in explicit instrumentation, like opentracing-skywalking-bridge.
* It it higher recommend don't use this for performance consideration.
* Only use this method in explicit instrumentation, like opentracing-skywalking-bridge. It it higher recommend
* don't use this for performance consideration.
*
* @param componentName
* @return the span for chaining.
Expand Down Expand Up @@ -89,4 +88,24 @@ public interface AbstractSpan {
* @return this Span instance, for chaining
*/
AbstractSpan setOperationName(String operationName);

/**
* Start a span.
*
* @return this Span instance, for chaining
*/
AbstractSpan start();

/**
* Get the id of span
*
* @return id value.
*/
int getSpanId();

int getOperationId();

String getOperationName();

AbstractSpan setOperationId(int operationId);
}