You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by ta...@apache.org on 2021/03/05 07:22:27 UTC

[skywalking] branch master updated: Support config `agent.span_limit_per_segment` can be changed in the runtime. (#6482)

This is an automated email from the ASF dual-hosted git repository.

tanjian pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git


The following commit(s) were added to refs/heads/master by this push:
     new 80a9a5e  Support config `agent.span_limit_per_segment` can be changed in the runtime. (#6482)
80a9a5e is described below

commit 80a9a5e65e316915d93369222c27b706f7bf48e4
Author: Jared Tan <ji...@daocloud.io>
AuthorDate: Fri Mar 5 15:22:02 2021 +0800

    Support config `agent.span_limit_per_segment` can be changed in the runtime. (#6482)
    
    * CDS: Support config `agent.span_limit_per_segment`
    
    * fix missing logical.
    
    * fix ci
    
    * polish
    
    Co-authored-by: 吴晟 Wu Sheng <wu...@foxmail.com>
---
 CHANGES.md                                         |  1 +
 .../watcher}/IgnoreSuffixPatternsWatcher.java      |  3 ++-
 .../dynamic/watcher}/SamplingRateWatcher.java      |  3 ++-
 .../dynamic/watcher/SpanLimitWatcher.java}         | 29 ++++++++--------------
 .../core/context/ContextManagerExtendService.java  | 17 ++++++++++---
 .../apm/agent/core/context/TracingContext.java     | 11 +++++---
 .../apm/agent/core/sampling/SamplingService.java   |  3 ++-
 .../watcher}/IgnoreSuffixPatternsWatcherTest.java  |  4 ++-
 .../watcher}/SamplingRateWatcherTest.java          |  4 ++-
 .../watcher/SpanLimitWatcherTest.java}             | 25 ++++++++-----------
 .../apm/agent/core/context/TracingContextTest.java |  5 +++-
 .../java-agent/configuration-discovery.md          |  1 +
 12 files changed, 60 insertions(+), 46 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 05e9150..8ebadda 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -18,6 +18,7 @@ Release Notes.
 * Fix lettuce-5.x-plugin get null host in redis sentinel mode.
 * Fix ClassCastException by making CallbackAdapterInterceptor to implement EnhancedInstance interface in the spring-kafka plugin.
 * Fix NullPointerException with KafkaProducer.send(record).
+* Support config `agent.span_limit_per_segment` can be changed in the runtime.
 
 #### OAP-Backend
 * Allow user-defined `JAVA_OPTS` in the startup script.
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/IgnoreSuffixPatternsWatcher.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/dynamic/watcher/IgnoreSuffixPatternsWatcher.java
similarity index 94%
rename from apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/IgnoreSuffixPatternsWatcher.java
rename to apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/dynamic/watcher/IgnoreSuffixPatternsWatcher.java
index cb488f5..5b31241 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/IgnoreSuffixPatternsWatcher.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/dynamic/watcher/IgnoreSuffixPatternsWatcher.java
@@ -16,10 +16,11 @@
  *
  */
 
-package org.apache.skywalking.apm.agent.core.context;
+package org.apache.skywalking.apm.agent.core.conf.dynamic.watcher;
 
 import org.apache.skywalking.apm.agent.core.conf.Config;
 import org.apache.skywalking.apm.agent.core.conf.dynamic.AgentConfigChangeWatcher;
+import org.apache.skywalking.apm.agent.core.context.ContextManagerExtendService;
 import org.apache.skywalking.apm.agent.core.logging.api.ILog;
 import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
 
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/sampling/SamplingRateWatcher.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/dynamic/watcher/SamplingRateWatcher.java
similarity index 95%
copy from apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/sampling/SamplingRateWatcher.java
copy to apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/dynamic/watcher/SamplingRateWatcher.java
index 9a5f346..9dcce2a 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/sampling/SamplingRateWatcher.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/dynamic/watcher/SamplingRateWatcher.java
@@ -16,13 +16,14 @@
  *
  */
 
-package org.apache.skywalking.apm.agent.core.sampling;
+package org.apache.skywalking.apm.agent.core.conf.dynamic.watcher;
 
 import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.skywalking.apm.agent.core.conf.Config;
 import org.apache.skywalking.apm.agent.core.conf.dynamic.AgentConfigChangeWatcher;
 import org.apache.skywalking.apm.agent.core.logging.api.ILog;
 import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
+import org.apache.skywalking.apm.agent.core.sampling.SamplingService;
 
 public class SamplingRateWatcher extends AgentConfigChangeWatcher {
     private static final ILog LOGGER = LogManager.getLogger(SamplingRateWatcher.class);
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/sampling/SamplingRateWatcher.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/dynamic/watcher/SpanLimitWatcher.java
similarity index 67%
rename from apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/sampling/SamplingRateWatcher.java
rename to apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/dynamic/watcher/SpanLimitWatcher.java
index 9a5f346..79d834b 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/sampling/SamplingRateWatcher.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/dynamic/watcher/SpanLimitWatcher.java
@@ -16,7 +16,7 @@
  *
  */
 
-package org.apache.skywalking.apm.agent.core.sampling;
+package org.apache.skywalking.apm.agent.core.conf.dynamic.watcher;
 
 import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.skywalking.apm.agent.core.conf.Config;
@@ -24,16 +24,14 @@ import org.apache.skywalking.apm.agent.core.conf.dynamic.AgentConfigChangeWatche
 import org.apache.skywalking.apm.agent.core.logging.api.ILog;
 import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
 
-public class SamplingRateWatcher extends AgentConfigChangeWatcher {
-    private static final ILog LOGGER = LogManager.getLogger(SamplingRateWatcher.class);
+public class SpanLimitWatcher extends AgentConfigChangeWatcher {
+    private static final ILog LOGGER = LogManager.getLogger(SpanLimitWatcher.class);
 
-    private final AtomicInteger samplingRate;
-    private final SamplingService samplingService;
+    private final AtomicInteger spanLimit;
 
-    public SamplingRateWatcher(final String propertyKey, SamplingService samplingService) {
+    public SpanLimitWatcher(final String propertyKey) {
         super(propertyKey);
-        this.samplingRate = new AtomicInteger(getDefaultValue());
-        this.samplingService = samplingService;
+        this.spanLimit = new AtomicInteger(getDefaultValue());
     }
 
     private void activeSetting(String config) {
@@ -41,12 +39,7 @@ public class SamplingRateWatcher extends AgentConfigChangeWatcher {
             LOGGER.debug("Updating using new static config: {}", config);
         }
         try {
-            this.samplingRate.set(Integer.parseInt(config));
-
-            /*
-             * We need to notify samplingService the samplingRate changed.
-             */
-            samplingService.handleSamplingRateChanged();
+            this.spanLimit.set(Integer.parseInt(config));
         } catch (NumberFormatException ex) {
             LOGGER.error(ex, "Cannot load {} from: {}", getPropertyKey(), config);
         }
@@ -63,14 +56,14 @@ public class SamplingRateWatcher extends AgentConfigChangeWatcher {
 
     @Override
     public String value() {
-        return String.valueOf(samplingRate.get());
+        return String.valueOf(spanLimit.get());
     }
 
     private int getDefaultValue() {
-        return Config.Agent.SAMPLE_N_PER_3_SECS;
+        return Config.Agent.SPAN_LIMIT_PER_SEGMENT;
     }
 
-    public int getSamplingRate() {
-        return samplingRate.get();
+    public int getSpanLimit() {
+        return spanLimit.get();
     }
 }
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManagerExtendService.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManagerExtendService.java
index f91d2c4..1e408df 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManagerExtendService.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManagerExtendService.java
@@ -24,6 +24,8 @@ import org.apache.skywalking.apm.agent.core.boot.DefaultImplementor;
 import org.apache.skywalking.apm.agent.core.boot.ServiceManager;
 import org.apache.skywalking.apm.agent.core.conf.Config;
 import org.apache.skywalking.apm.agent.core.conf.dynamic.ConfigurationDiscoveryService;
+import org.apache.skywalking.apm.agent.core.conf.dynamic.watcher.IgnoreSuffixPatternsWatcher;
+import org.apache.skywalking.apm.agent.core.conf.dynamic.watcher.SpanLimitWatcher;
 import org.apache.skywalking.apm.agent.core.remote.GRPCChannelListener;
 import org.apache.skywalking.apm.agent.core.remote.GRPCChannelManager;
 import org.apache.skywalking.apm.agent.core.remote.GRPCChannelStatus;
@@ -39,6 +41,8 @@ public class ContextManagerExtendService implements BootService, GRPCChannelList
 
     private IgnoreSuffixPatternsWatcher ignoreSuffixPatternsWatcher;
 
+    private SpanLimitWatcher spanLimitWatcher;
+
     @Override
     public void prepare() {
         ServiceManager.INSTANCE.findService(GRPCChannelManager.class).addChannelListener(this);
@@ -48,8 +52,13 @@ public class ContextManagerExtendService implements BootService, GRPCChannelList
     public void boot() {
         ignoreSuffixArray = Config.Agent.IGNORE_SUFFIX.split(",");
         ignoreSuffixPatternsWatcher = new IgnoreSuffixPatternsWatcher("agent.ignore_suffix", this);
-        ServiceManager.INSTANCE.findService(ConfigurationDiscoveryService.class)
-                               .registerAgentConfigChangeWatcher(ignoreSuffixPatternsWatcher);
+        spanLimitWatcher = new SpanLimitWatcher("agent.span_limit_per_segment");
+
+        ConfigurationDiscoveryService configurationDiscoveryService = ServiceManager.INSTANCE.findService(
+            ConfigurationDiscoveryService.class);
+        configurationDiscoveryService.registerAgentConfigChangeWatcher(spanLimitWatcher);
+        configurationDiscoveryService.registerAgentConfigChangeWatcher(ignoreSuffixPatternsWatcher);
+
         handleIgnoreSuffixPatternsChanged();
     }
 
@@ -79,7 +88,7 @@ public class ContextManagerExtendService implements BootService, GRPCChannelList
         } else {
             SamplingService samplingService = ServiceManager.INSTANCE.findService(SamplingService.class);
             if (forceSampling || samplingService.trySampling(operationName)) {
-                context = new TracingContext(operationName);
+                context = new TracingContext(operationName, spanLimitWatcher);
             } else {
                 context = new IgnoredTracerContext();
             }
@@ -93,7 +102,7 @@ public class ContextManagerExtendService implements BootService, GRPCChannelList
         this.status = status;
     }
 
-    void handleIgnoreSuffixPatternsChanged() {
+    public void handleIgnoreSuffixPatternsChanged() {
         if (StringUtil.isNotBlank(ignoreSuffixPatternsWatcher.getIgnoreSuffixPatterns())) {
             ignoreSuffixArray = ignoreSuffixPatternsWatcher.getIgnoreSuffixPatterns().split(",");
         }
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java
index b0c04f0..7bdec3d 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java
@@ -26,6 +26,7 @@ import lombok.AccessLevel;
 import lombok.Getter;
 import org.apache.skywalking.apm.agent.core.boot.ServiceManager;
 import org.apache.skywalking.apm.agent.core.conf.Config;
+import org.apache.skywalking.apm.agent.core.conf.dynamic.watcher.SpanLimitWatcher;
 import org.apache.skywalking.apm.agent.core.context.ids.DistributedTraceId;
 import org.apache.skywalking.apm.agent.core.context.ids.PropagatedTraceId;
 import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
@@ -110,10 +111,13 @@ public class TracingContext implements AbstractTracerContext {
     @Getter(AccessLevel.PACKAGE)
     private final ExtensionContext extensionContext;
 
+    //CDS watcher
+    private final SpanLimitWatcher spanLimitWatcher;
+
     /**
      * Initialize all fields with default value.
      */
-    TracingContext(String firstOPName) {
+    TracingContext(String firstOPName, SpanLimitWatcher spanLimitWatcher) {
         this.segment = new TraceSegment();
         this.spanIdGenerator = 0;
         isRunningInAsyncMode = false;
@@ -129,6 +133,7 @@ public class TracingContext implements AbstractTracerContext {
 
         this.correlationContext = new CorrelationContext();
         this.extensionContext = new ExtensionContext();
+        this.spanLimitWatcher = spanLimitWatcher;
     }
 
     /**
@@ -541,12 +546,12 @@ public class TracingContext implements AbstractTracerContext {
     }
 
     private boolean isLimitMechanismWorking() {
-        if (spanIdGenerator >= Config.Agent.SPAN_LIMIT_PER_SEGMENT) {
+        if (spanIdGenerator >= spanLimitWatcher.getSpanLimit()) {
             long currentTimeMillis = System.currentTimeMillis();
             if (currentTimeMillis - lastWarningTimestamp > 30 * 1000) {
                 LOGGER.warn(
                     new RuntimeException("Shadow tracing context. Thread dump"),
-                    "More than {} spans required to create", Config.Agent.SPAN_LIMIT_PER_SEGMENT
+                    "More than {} spans required to create", spanLimitWatcher.getSpanLimit()
                 );
                 lastWarningTimestamp = currentTimeMillis;
             }
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/sampling/SamplingService.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/sampling/SamplingService.java
index 8ca63e9..5777a04 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/sampling/SamplingService.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/sampling/SamplingService.java
@@ -29,6 +29,7 @@ import org.apache.skywalking.apm.agent.core.boot.DefaultNamedThreadFactory;
 import org.apache.skywalking.apm.agent.core.boot.ServiceManager;
 import org.apache.skywalking.apm.agent.core.conf.Config;
 import org.apache.skywalking.apm.agent.core.conf.dynamic.ConfigurationDiscoveryService;
+import org.apache.skywalking.apm.agent.core.conf.dynamic.watcher.SamplingRateWatcher;
 import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
 import org.apache.skywalking.apm.agent.core.logging.api.ILog;
 import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
@@ -109,7 +110,7 @@ public class SamplingService implements BootService {
     /**
      * Handle the samplingRate changed.
      */
-    void handleSamplingRateChanged() {
+    public void handleSamplingRateChanged() {
         if (samplingRateWatcher.getSamplingRate() > 0) {
             if (!on) {
                 on = true;
diff --git a/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/context/IgnoreSuffixPatternsWatcherTest.java b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/conf/watcher/IgnoreSuffixPatternsWatcherTest.java
similarity index 92%
rename from apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/context/IgnoreSuffixPatternsWatcherTest.java
rename to apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/conf/watcher/IgnoreSuffixPatternsWatcherTest.java
index a0b2ede..a2e7108 100644
--- a/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/context/IgnoreSuffixPatternsWatcherTest.java
+++ b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/conf/watcher/IgnoreSuffixPatternsWatcherTest.java
@@ -16,10 +16,12 @@
  *
  */
 
-package org.apache.skywalking.apm.agent.core.context;
+package org.apache.skywalking.apm.agent.core.conf.watcher;
 
 import org.apache.skywalking.apm.agent.core.boot.ServiceManager;
 import org.apache.skywalking.apm.agent.core.conf.dynamic.AgentConfigChangeWatcher;
+import org.apache.skywalking.apm.agent.core.conf.dynamic.watcher.IgnoreSuffixPatternsWatcher;
+import org.apache.skywalking.apm.agent.core.context.ContextManagerExtendService;
 import org.apache.skywalking.apm.agent.core.test.tools.AgentServiceRule;
 import org.junit.AfterClass;
 import org.junit.Assert;
diff --git a/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/sampling/SamplingRateWatcherTest.java b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/conf/watcher/SamplingRateWatcherTest.java
similarity index 92%
copy from apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/sampling/SamplingRateWatcherTest.java
copy to apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/conf/watcher/SamplingRateWatcherTest.java
index cf5393f..ab30946 100644
--- a/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/sampling/SamplingRateWatcherTest.java
+++ b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/conf/watcher/SamplingRateWatcherTest.java
@@ -16,10 +16,12 @@
  *
  */
 
-package org.apache.skywalking.apm.agent.core.sampling;
+package org.apache.skywalking.apm.agent.core.conf.watcher;
 
 import org.apache.skywalking.apm.agent.core.boot.ServiceManager;
 import org.apache.skywalking.apm.agent.core.conf.dynamic.AgentConfigChangeWatcher;
+import org.apache.skywalking.apm.agent.core.conf.dynamic.watcher.SamplingRateWatcher;
+import org.apache.skywalking.apm.agent.core.sampling.SamplingService;
 import org.apache.skywalking.apm.agent.core.test.tools.AgentServiceRule;
 import org.junit.AfterClass;
 import org.junit.Assert;
diff --git a/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/sampling/SamplingRateWatcherTest.java b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/conf/watcher/SpanLimitWatcherTest.java
similarity index 63%
rename from apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/sampling/SamplingRateWatcherTest.java
rename to apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/conf/watcher/SpanLimitWatcherTest.java
index cf5393f..9efb11a 100644
--- a/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/sampling/SamplingRateWatcherTest.java
+++ b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/conf/watcher/SpanLimitWatcherTest.java
@@ -16,28 +16,27 @@
  *
  */
 
-package org.apache.skywalking.apm.agent.core.sampling;
+package org.apache.skywalking.apm.agent.core.conf.watcher;
 
 import org.apache.skywalking.apm.agent.core.boot.ServiceManager;
 import org.apache.skywalking.apm.agent.core.conf.dynamic.AgentConfigChangeWatcher;
+import org.apache.skywalking.apm.agent.core.conf.dynamic.watcher.SpanLimitWatcher;
 import org.apache.skywalking.apm.agent.core.test.tools.AgentServiceRule;
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
-import org.powermock.reflect.Whitebox;
 
-public class SamplingRateWatcherTest {
+public class SpanLimitWatcherTest {
 
     @Rule
     public AgentServiceRule agentServiceRule = new AgentServiceRule();
 
-    private SamplingService samplingService;
+    private final SpanLimitWatcher spanLimitWatcher = new SpanLimitWatcher("agent.span_limit_per_segment");
 
     @Before
     public void setUp() {
-        samplingService = ServiceManager.INSTANCE.findService(SamplingService.class);
     }
 
     @AfterClass
@@ -47,24 +46,20 @@ public class SamplingRateWatcherTest {
 
     @Test
     public void testConfigModifyEvent() {
-        SamplingRateWatcher samplingRateWatcher = Whitebox.getInternalState(
-            samplingService, "samplingRateWatcher");
-        samplingRateWatcher.notify(new AgentConfigChangeWatcher.ConfigChangeEvent(
-            "10",
+        spanLimitWatcher.notify(new AgentConfigChangeWatcher.ConfigChangeEvent(
+            "400",
             AgentConfigChangeWatcher.EventType.MODIFY
         ));
-        Assert.assertEquals(10, samplingRateWatcher.getSamplingRate());
-        Assert.assertEquals("agent.sample_n_per_3_secs", samplingRateWatcher.getPropertyKey());
+        Assert.assertEquals(400, spanLimitWatcher.getSpanLimit());
+        Assert.assertEquals("agent.span_limit_per_segment", spanLimitWatcher.getPropertyKey());
     }
 
     @Test
     public void testConfigDeleteEvent() {
-        SamplingRateWatcher samplingRateWatcher = Whitebox.getInternalState(
-            samplingService, "samplingRateWatcher");
-        samplingRateWatcher.notify(new AgentConfigChangeWatcher.ConfigChangeEvent(
+        spanLimitWatcher.notify(new AgentConfigChangeWatcher.ConfigChangeEvent(
             null,
             AgentConfigChangeWatcher.EventType.DELETE
         ));
-        Assert.assertEquals("agent.sample_n_per_3_secs", samplingRateWatcher.getPropertyKey());
+        Assert.assertEquals("agent.span_limit_per_segment", spanLimitWatcher.getPropertyKey());
     }
 }
diff --git a/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/context/TracingContextTest.java b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/context/TracingContextTest.java
index e4e1243..ed282f3 100644
--- a/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/context/TracingContextTest.java
+++ b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/context/TracingContextTest.java
@@ -20,6 +20,7 @@ package org.apache.skywalking.apm.agent.core.context;
 
 import org.apache.skywalking.apm.agent.core.boot.ServiceManager;
 import org.apache.skywalking.apm.agent.core.conf.Config;
+import org.apache.skywalking.apm.agent.core.conf.dynamic.watcher.SpanLimitWatcher;
 import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
 import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
 import org.apache.skywalking.apm.agent.core.test.tools.AgentServiceRule;
@@ -33,6 +34,8 @@ public class TracingContextTest {
     @Rule
     public AgentServiceRule serviceRule = new AgentServiceRule();
 
+    private final SpanLimitWatcher spanLimitWatcher = new SpanLimitWatcher("agent.span_limit_per_segment");
+
     @BeforeClass
     public static void beforeClass() {
         Config.Agent.KEEP_TRACING = true;
@@ -55,7 +58,7 @@ public class TracingContextTest {
         };
         TracingContext.ListenerManager.add(listener);
         try {
-            TracingContext tracingContext = new TracingContext("/url");
+            TracingContext tracingContext = new TracingContext("/url", spanLimitWatcher);
             AbstractSpan span = tracingContext.createEntrySpan("/url");
 
             for (int i = 0; i < 10; i++) {
diff --git a/docs/en/setup/service-agent/java-agent/configuration-discovery.md b/docs/en/setup/service-agent/java-agent/configuration-discovery.md
index 65423f6..b860e35 100644
--- a/docs/en/setup/service-agent/java-agent/configuration-discovery.md
+++ b/docs/en/setup/service-agent/java-agent/configuration-discovery.md
@@ -27,5 +27,6 @@ Java agent supports the following dynamic configurations.
 | agent.sample_n_per_3_secs |          The number of sampled traces per 3 seconds          |          -1           | - |
 | agent.ignore_suffix       |          If the operation name of the first span is included in this set, this segment should be ignored. Multiple values should be separated by `,`        |          `.txt,.log`         | - |
 | agent.trace.ignore_path   |          The value is the path that you need to ignore, multiple paths should be separated by `,` [more details](./agent-optional-plugins/trace-ignore-plugin.md)         |          `/your/path/1/**,/your/path/2/**`         | `apm-trace-ignore-plugin` |
+| agent.span_limit_per_segment   |           The max number of spans per segment.        |         `300`        | - |
 
 * `Required plugin(s)`, the configuration affects only when the required plugins activated.