Skip to content

Commit

Permalink
Merge pull request #570 from OpenSkywalking/feature/agent-memory-control
Browse files Browse the repository at this point in the history
Add Span amount control mechanism, also memory limit mechanism
  • Loading branch information
wu-sheng committed Nov 15, 2017
2 parents c10b7b1 + 2d80d8d commit 4a2e1bc
Show file tree
Hide file tree
Showing 11 changed files with 251 additions and 116 deletions.
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);
}

0 comments on commit 4a2e1bc

Please sign in to comment.