Skip to content

Commit 8c282ae

Browse files
authored
Recycling things (#75)
* - Restoring the ability to enable recycling - Defaults to disabling recycling on .NET 6.0 - Updated README to include details about recycling - Allowing user to specify a `null` recycling time to disable recycling * Fixing typos * Retuning README * More tweaks Co-authored-by: James Luck <[email protected]>
1 parent 4f04cfe commit 8c282ae

File tree

6 files changed

+32
-8
lines changed

6 files changed

+32
-8
lines changed

README.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ These metrics are essential for understanding the performance of any non-trivial
1212

1313
## Using this package
1414
### Requirements
15-
- .NET core 3.1 (runtime version 3.1.11+ is recommended)/ .NET 5.0
15+
- .NET 5.0+ recommended, .NET core 3.1+ is supported
1616
- The [prometheus-net](https://github.com/prometheus-net/prometheus-net) package
1717

1818
### Install it
@@ -61,7 +61,27 @@ The harder you work the .NET core runtime, the more events it generates. Event g
6161
- **GC stats with `CaptureLevel.Verbose`**: every 100KB of allocations, an event is emitted. If you are consistently allocating memory at a rate > 1GB/sec, you might like to disable GC stats.
6262
- **Exception stats with `CaptureLevel.Errors`**: for every exception throw, an event is generated.
6363

64-
There is also a [performance issue present in .NET core 3.1](https://github.com/dotnet/runtime/issues/43985#issuecomment-800629516) that will see CPU consumption grow over time when long-running trace sessions are used.
64+
#### Recycling collectors
65+
There have been long-running [performance issues since .NET core 3.1](https://github.com/dotnet/runtime/issues/43985#issuecomment-800629516) that could see CPU consumption grow over time when long-running trace sessions are used.
66+
While many of the performance issues have been addressed now in .NET 6.0, a workaround was identified: stopping and starting (AKA recycling) collectors periodically helped reduce CPU consumption:
67+
```
68+
IDisposable collector = DotNetRuntimeStatsBuilder.Default()
69+
// Recycles all collectors once every day
70+
.RecycleCollectorsEvery(TimeSpan.FromDays(1))
71+
.StartCollecting()
72+
```
73+
74+
While this [has been observed to reduce CPU consumption](https://github.com/djluck/prometheus-net.DotNetRuntime/issues/6#issuecomment-784540220) this technique has been identified as a [possible culprit that can lead
75+
to application instability](https://github.com/djluck/prometheus-net.DotNetRuntime/issues/72).
76+
77+
Behaviour on different runtime versions is:
78+
- .NET core 3.1: recycling verified to cause massive instability, cannot enable recycling.
79+
- .NET 5.0: recycling verified to be beneficial, recycling every day enabled by default.
80+
- .NET 6.0+: recycling verified to be less necesarry due to long-standing issues being addressed although [some users report recycling to be beneficial](https://github.com/djluck/prometheus-net.DotNetRuntime/pull/73#issuecomment-1308558226),
81+
disabled by default but recycling can be enabled.
82+
83+
> TLDR: If you observe increasing CPU over time, try enabling recycling. If you see unexpected crashes after using this application, try disabling recycling.
84+
6585

6686
## Examples
6787
An example `docker-compose` stack is available in the [`examples/`](examples/) folder. Start it with:

examples/AspNetCoreExample/Startup.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public static IDisposable CreateCollector()
9090
}
9191

9292
builder
93-
#if NET5_0
93+
#if NET5_0_OR_GREATER
9494
.RecycleCollectorsEvery(_options.RecycleEvery)
9595
#endif
9696
.WithErrorHandler(ex => _logger.LogError(ex, "Unexpected exception occurred in prometheus-net.DotNetRuntime"));

src/prometheus-net.DotNetRuntime.Tests/EventListening/EventParserTypes.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public void When_Calling_GetEventInterfacesForCurrentRuntime_On_Net31_Then_Retur
6868
}
6969
#endif
7070

71-
#if NET5_0
71+
#if NET5_0_OR_GREATER
7272

7373
[Test]
7474
public void When_Calling_GetEventInterfacesForCurrentRuntime_On_Net50_Then_Returns_Interfaces_For_Net50_Runtime_And_Below()

src/prometheus-net.DotNetRuntime.Tests/IntegrationTests/JitCompilerTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ protected override DotNetRuntimeStatsBuilder.Builder ConfigureBuilder(DotNetRunt
102102
return toConfigure.WithJitStats(CaptureLevel.Counters, SampleEvery.OneEvent);
103103
}
104104

105-
#if NET5_0
105+
#if NET5_0_OR_GREATER
106106

107107
[Test]
108108
public void When_Running_On_NET50_Then_Counts_Of_Methods_Are_Recorded()

src/prometheus-net.DotNetRuntime/DotNetRuntimeStatsBuilder.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ public Builder WithErrorHandler(Action<Exception> handler)
226226
return this;
227227
}
228228

229-
#if NET5_0
229+
#if NET5_0_OR_GREATER
230230
/// <summary>
231231
/// Specifies a custom interval to recycle collectors. Defaults to 1 day.
232232
/// </summary>
@@ -235,9 +235,9 @@ public Builder WithErrorHandler(Action<Exception> handler)
235235
/// Recycling the event collectors is a workaround, preventing CPU exhaustion (see https://github.com/dotnet/runtime/issues/43985#issuecomment-793187345 for more info).
236236
/// During a recycle, existing metrics will not disappear/ reset but will not be updated for a short period (should be at most a couple of seconds).
237237
/// </remarks>
238-
/// <param name="interval"></param>
238+
/// <param name="interval">The interval to recycle at. Set to null to disable recycling.</param>
239239
/// <returns></returns>
240-
public Builder RecycleCollectorsEvery(TimeSpan interval)
240+
public Builder RecycleCollectorsEvery(TimeSpan? interval)
241241
{
242242
#if DEBUG
243243
// In debug mode, allow more aggressive recycling times to verify recycling works correctly

src/prometheus-net.DotNetRuntime/DotNetRuntimeStatsCollector.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,10 @@ public class Options
202202

203203
public TimeSpan? RecycleListenersEvery { get; set; } =
204204
#if NET5_0
205+
// only default to enabled for .NET 5. .NET 6 had/ has issues where recycling collectors could lead to
206+
// problems, see https://github.com/dotnet/runtime/pull/76431
207+
// HOWEVER, people have mentioned that recycling is still required under .NET 6.0: https://github.com/dotnet/runtime/pull/76431
208+
// As a compromise, we won't enable it by default but will allow people to opt-in
205209
TimeSpan.FromDays(1);
206210
#else
207211
null;

0 commit comments

Comments
 (0)