Skip to content

Commit

Permalink
Merge pull request #5096 from akkadotnet/dev
Browse files Browse the repository at this point in the history
v1.4.21 Release
  • Loading branch information
Aaronontheweb committed Jun 16, 2021
2 parents 758590f + 5c9f8a7 commit a8347c5
Show file tree
Hide file tree
Showing 103 changed files with 2,993 additions and 1,165 deletions.
6 changes: 0 additions & 6 deletions ISSUE_TEMPLATE.md

This file was deleted.

90 changes: 90 additions & 0 deletions RELEASE_NOTES.md
@@ -1,3 +1,93 @@
#### 1.4.21 June 16 2021 ####
**Maintenance Release for Akka.NET 1.4**

Akka.NET v1.4.21 is a significant release that includes major performance improvements, bug fixes, and a major update to the [Akka.DependencyInjection NuGet package](https://getakka.net/articles/actors/dependency-injection.html).

**Performance Improvements**
Akka.NET v1.4.21 includes some major performance fixes and improvements:

* [`Ask` is now ~10% faster](https://github.com/akkadotnet/akka.net/pull/5051)
* [`MurmurHash` is 33% faster and allocates 0 memory](https://github.com/akkadotnet/akka.net/pull/5028) - used _heavily_ in DData, Cluster Sharding, and Consistent Hash Routers
* `ActorPath.Parse` went from 1672 ns/op to 527 ns/op - a 68% improvement in throughput and a 50% reduction in memory. See [#5039](https://github.com/akkadotnet/akka.net/pull/5039) and [#5068](https://github.com/akkadotnet/akka.net/pull/5068).
* [Akka.Remote: remove `ActorPath.ToString` call from `ResolveActorRefWithLocalAddress`](https://github.com/akkadotnet/akka.net/pull/5034)
* **Important**: [Revert `ThreadPool.SetMinThreads(0,0)`](https://github.com/akkadotnet/akka.net/pull/5059) - based on the input from users on "[Akka.NET v1.4.19: ChannelExecutor performance data](https://github.com/akkadotnet/akka.net/discussions/4983)"

Our observed performance numbers for Akka.Remote show a significant increase in performance for v1.4.21 over v1.4.20:

*Before*

```
PS> dotnet run -c Release --framework netcoreapp3.1
OSVersion: Microsoft Windows NT 6.2.9200.0
ProcessorCount: 16
ClockSpeed: 0 MHZ
Actor Count: 32
Messages sent/received per client: 200000 (2e5)
Is Server GC: True
Thread count: 109

Num clients, Total [msg], Msgs/sec, Total [ms]
1, 200000, 113379, 1764.56
5, 1000000, 186429, 5364.05
10, 2000000, 185340, 10791.11
15, 3000000, 183218, 16374.06
20, 4000000, 179824, 22244.63
25, 5000000, 182716, 27365.89
30, 6000000, 182039, 32960.61
```

*After*

```
PS> dotnet run -c Release --framework netcoreapp3.1
OSVersion: Microsoft Windows NT 6.2.9200.0
ProcessorCount: 16
ClockSpeed: 0 MHZ
Actor Count: 32
Messages sent/received per client: 200000 (2e5)
Is Server GC: True
Thread count: 111

Num clients, Total [msg], Msgs/sec, Total [ms]
1, 200000, 109770, 1822.14
5, 1000000, 192902, 5184.79
10, 2000000, 191663, 10435.53
15, 3000000, 191339, 15679.11
20, 4000000, 192725, 20755.78
25, 5000000, 189754, 26350.14
30, 6000000, 189772, 31617.20
```

> N.B. these after numbers don't benefit from the performance benefits we observed in v1.4.20 when we invoked `ThreadPool.SetMinThreads(0,0)`, which makes them even more impressive.

**Akka.DependencyInjection Updates**
We had one major issue we implemented in v1.4.21 for Akka.DependencyInjection: [Abstraction of `ServiceProvider`, Improving Akka.DependencyInjection ](https://github.com/akkadotnet/akka.net/pull/4814)

What this change did was:

* Deprecate the `Akka.DependencyInjection.ServiceProvider` class in favor of the `Akka.DependencyInjection.DependencyResolver` class - to avoid namespace collision with Microsoft.Extensions.DependencyInjection.ServiceProvider;
* Deprecates the `Akka.DependencyInjection.ServiceProviderSetup` class in favor of the `Akka.DependencyInjection.DependencyResolverSetup` class for consistency reasons;
* `Akka.DependencyInjection.DependencyResolver` now takes an input of type [`IDependencyResolver`](https://getakka.net/api/Akka.DependencyInjection.IDependencyResolver.html), which allows users to abstract away the `IServiceProvider` and mock / replace it during unit testing; and
* Added some non-generic `Props` methods for dynamically spawning actors via DI.

All of these changes are backwards-compatible with v1.4.20 and earlier - and the deprecation warnings will appear in your code when you upgrade. If you run into any [issues upgrading to Akka.DependencyInjection v1.4.21 please reply on this thread](https://github.com/akkadotnet/akka.net/discussions/5070)!

**Other Changes and Fixes**

* [Akka.Streams: A couple of fixes affecting the `FileSubscriber`](https://github.com/akkadotnet/akka.net/pull/5035)
* [Akka.DistributedData: memory leak when recovering events from LMDB data store](https://github.com/akkadotnet/akka.net/issues/5022)
* [Akka.DistributedData: port `VectorClock` performance optimizations to `VersionVector` and similar types](https://github.com/akkadotnet/akka.net/issues/4956)

To see the [full set of fixes in Akka.NET v1.4.21, please see the milestone on Github](https://github.com/akkadotnet/akka.net/milestone/51).

| COMMITS | LOC+ | LOC- | AUTHOR |
| --- | --- | --- | --- |
| 5 | 34 | 24 | Aaron Stannard |
| 4 | 196 | 77 | Gregorius Soedharmo |
| 3 | 3 | 3 | dependabot[bot] |
| 1 | 2 | 2 | Wessel Kranenborg |
| 1 | 1 | 1 | Martijn Schoemaker |

#### 1.4.20 May 12 2021 ####
**Maintenance Release for Akka.NET 1.4**

Expand Down
5 changes: 1 addition & 4 deletions docs/articles/actors/dispatchers.md
Expand Up @@ -171,7 +171,7 @@ In Akka.NET v1.4.19 we will be introducing an opt-in feature, the `ChannelExecut

During its initial development and benchmarks, we observed the following:

1. The `ChannelExecutor` tremendously reduced idle CPU and max busy CPU even during peak message throughput, primarily as a result of dynamically shrinking the total `ThreadPool` to only the necessary size. This resolves one of the largest complaints large users of Akka.NET have today. However, **in order for this setting to be effective `ThreadPool.SetMin(0,0)` must also be set**. We are considering doing this inside the `ActorSystem.Create` method, those settings don't work for you you can easily override them by simply calling `ThreadPool.SetMin(yourValue, yourValue)` again after `ActorSystem.Create` has exited.
1. The `ChannelExecutor` tremendously reduced idle CPU and max busy CPU even during peak message throughput, primarily as a result of dynamically shrinking the total `ThreadPool` to only the necessary size. This resolves one of the largest complaints large users of Akka.NET have today.
2. The `ChannelExecutor` actually beat the `ForkJoinDispatcher` and others on performance even in environments like Docker and bare metal on Windows.

> [!NOTE]
Expand Down Expand Up @@ -220,9 +220,6 @@ akka.remote.backoff-remote-dispatcher {

This will enable the `ChannelExecutor` to run everywhere and all Akka.NET loads, with the exception of anything you manually allocate onto a `ForkJoinDispatcher` or `PinnedDispatcher`, will be managed by the `ThreadPool`.

> [!IMPORTANT]
> As of Akka.NET v1.4.19, we call `ThreadPool.SetMinThreads(0,0)` inside the `ActorSystem.Create` method as we've found that the default `ThreadPool` minimum values have a negative impact on performance. However, if this causes undesireable side effects for you inside your application you can always override those settings by calling `ThreadPool.SetMinThreads(yourValue, yourValue)` again after you've created your `ActorSystem`.
#### Common Dispatcher Configuration

The following configuration keys are available for any dispatcher configuration:
Expand Down
4 changes: 2 additions & 2 deletions docs/articles/actors/receive-actor-api.md
Expand Up @@ -405,10 +405,10 @@ For more information on Tasks, check out the [MSDN documentation](https://msdn.m
> When using task callbacks inside actors, you need to carefully avoid closing over the containing actor’s reference, i.e. do not call methods or access mutable state on the enclosing actor from within the callback. This would break the actor encapsulation and may introduce synchronization bugs and race conditions because the callback will be scheduled concurrently to the enclosing actor. Unfortunately there is not yet a way to detect these illegal accesses at compile time.
### Forward message
You can forward a message from one actor to another. This means that the original sender address/reference is maintained even though the message is going through a 'mediator'. This can be useful when writing actors that work as routers, load-balancers, replicators etc. You need to pass along your context variable as well.
You can forward a message from one actor to another. This means that the original sender address/reference is maintained even though the message is going through a 'mediator'. This can be useful when writing actors that work as routers, load-balancers, replicators etc.

```csharp
target.Forward(result, Context);
target.Forward(result);
```

## Receive messages
Expand Down
19 changes: 17 additions & 2 deletions src/Akka.sln
Expand Up @@ -240,9 +240,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.DependencyInjection.Te
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AspNetCore", "AspNetCore", "{162F5991-EA57-4221-9B70-F9B6FEC18036}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.Akka.AspNetCore", "examples\AspNetCore\Samples.Akka.AspNetCore\Samples.Akka.AspNetCore.csproj", "{D62F4AD6-318F-4ECC-B875-83FA9933A81B}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Samples.Akka.AspNetCore", "examples\AspNetCore\Samples.Akka.AspNetCore\Samples.Akka.AspNetCore.csproj", "{D62F4AD6-318F-4ECC-B875-83FA9933A81B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SerializationBenchmarks", "benchmark\SerializationBenchmarks\SerializationBenchmarks.csproj", "{2E4B9584-42CC-4D17-B719-9F462B16C94D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SerializationBenchmarks", "benchmark\SerializationBenchmarks\SerializationBenchmarks.csproj", "{2E4B9584-42CC-4D17-B719-9F462B16C94D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DDataStressTest", "examples\Cluster\DData\DDataStressTest\DDataStressTest.csproj", "{44B3DDD6-6103-4E8F-8AC2-0F4BA3CF6B50}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -1123,6 +1125,18 @@ Global
{2E4B9584-42CC-4D17-B719-9F462B16C94D}.Release|x64.Build.0 = Release|Any CPU
{2E4B9584-42CC-4D17-B719-9F462B16C94D}.Release|x86.ActiveCfg = Release|Any CPU
{2E4B9584-42CC-4D17-B719-9F462B16C94D}.Release|x86.Build.0 = Release|Any CPU
{44B3DDD6-6103-4E8F-8AC2-0F4BA3CF6B50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{44B3DDD6-6103-4E8F-8AC2-0F4BA3CF6B50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44B3DDD6-6103-4E8F-8AC2-0F4BA3CF6B50}.Debug|x64.ActiveCfg = Debug|Any CPU
{44B3DDD6-6103-4E8F-8AC2-0F4BA3CF6B50}.Debug|x64.Build.0 = Debug|Any CPU
{44B3DDD6-6103-4E8F-8AC2-0F4BA3CF6B50}.Debug|x86.ActiveCfg = Debug|Any CPU
{44B3DDD6-6103-4E8F-8AC2-0F4BA3CF6B50}.Debug|x86.Build.0 = Debug|Any CPU
{44B3DDD6-6103-4E8F-8AC2-0F4BA3CF6B50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44B3DDD6-6103-4E8F-8AC2-0F4BA3CF6B50}.Release|Any CPU.Build.0 = Release|Any CPU
{44B3DDD6-6103-4E8F-8AC2-0F4BA3CF6B50}.Release|x64.ActiveCfg = Release|Any CPU
{44B3DDD6-6103-4E8F-8AC2-0F4BA3CF6B50}.Release|x64.Build.0 = Release|Any CPU
{44B3DDD6-6103-4E8F-8AC2-0F4BA3CF6B50}.Release|x86.ActiveCfg = Release|Any CPU
{44B3DDD6-6103-4E8F-8AC2-0F4BA3CF6B50}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1230,6 +1244,7 @@ Global
{162F5991-EA57-4221-9B70-F9B6FEC18036} = {D3AF8295-AEB5-4324-AA82-FCC0014AC310}
{D62F4AD6-318F-4ECC-B875-83FA9933A81B} = {162F5991-EA57-4221-9B70-F9B6FEC18036}
{2E4B9584-42CC-4D17-B719-9F462B16C94D} = {73108242-625A-4D7B-AA09-63375DBAE464}
{44B3DDD6-6103-4E8F-8AC2-0F4BA3CF6B50} = {C50E1A9E-820C-4E75-AE39-6F96A99AC4A7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {03AD8E21-7507-4E68-A4E9-F4A7E7273164}
Expand Down
@@ -0,0 +1,57 @@
//-----------------------------------------------------------------------
// <copyright file="ActorMemoryFootprintBenchmarks.cs" company="Akka.NET Project">
// Copyright (C) 2009-2021 Lightbend Inc. <http://www.lightbend.com>
// Copyright (C) 2013-2021 .NET Foundation <https://github.com/akkadotnet/akka.net>
// </copyright>
//-----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Akka.Actor;
using Akka.Benchmarks.Configurations;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Engines;

namespace Akka.Benchmarks.Actor
{
[Config(typeof(MicroBenchmarkConfig))]
[SimpleJob(RunStrategy.Monitoring, targetCount: 25, warmupCount: 5)]
public class ActorMemoryFootprintBenchmark
{
public ActorSystem Sys;
public Props Props;

[Params(10_000)]
public int SpawnCount { get; set; }

[GlobalSetup]
public void Setup()
{
Sys = ActorSystem.Create("Bench");
Props = Props.Create(() => new TempActor());
}

private class TempActor : UntypedActor
{
protected override void OnReceive(object message)
{

}
}

[Benchmark]
public void SpawnActor()
{
for(var i = 0; i < SpawnCount; i++)
Sys.ActorOf(Props);
}

[GlobalCleanup]
public async Task Cleanup()
{
await Sys.Terminate();
}
}
}
22 changes: 19 additions & 3 deletions src/benchmark/Akka.Benchmarks/Actor/ActorPathBenchmarks.cs
Expand Up @@ -16,12 +16,16 @@ public class ActorPathBenchmarks
{
private ActorPath x;
private ActorPath y;
private ActorPath _childPath;
private Address _sysAdr = new Address("akka.tcp", "system", "127.0.0.1", 1337);
private Address _otherAdr = new Address("akka.tcp", "system", "127.0.0.1", 1338);

[GlobalSetup]
public void Setup()
{
x = new RootActorPath(new Address("akka.tcp", "system", "127.0.0.1", 1337), "user");
y = new RootActorPath(new Address("akka.tcp", "system", "127.0.0.1", 1337), "system");
x = new RootActorPath(_sysAdr, "user");
y = new RootActorPath(_sysAdr, "system");
_childPath = x / "parent" / "child";
}

[Benchmark]
Expand All @@ -45,7 +49,19 @@ public bool ActorPath_Equals()
[Benchmark]
public string ActorPath_ToString()
{
return x.ToString();
return _childPath.ToString();
}

[Benchmark]
public string ActorPath_ToSerializationFormat()
{
return _childPath.ToSerializationFormat();
}

[Benchmark]
public string ActorPath_ToSerializationFormatWithAddress()
{
return _childPath.ToSerializationFormatWithAddress(_otherAdr);
}
}
}
34 changes: 34 additions & 0 deletions src/benchmark/Akka.Benchmarks/Actor/NameAndUidBenchmarks.cs
@@ -0,0 +1,34 @@
//-----------------------------------------------------------------------
// <copyright file="NameAndUidBenchmarks.cs" company="Akka.NET Project">
// Copyright (C) 2009-2021 Lightbend Inc. <http://www.lightbend.com>
// Copyright (C) 2013-2021 .NET Foundation <https://github.com/akkadotnet/akka.net>
// </copyright>
//-----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Text;
using Akka.Actor;
using Akka.Benchmarks.Configurations;
using BenchmarkDotNet.Attributes;

namespace Akka.Benchmarks.Actor
{
[Config(typeof(MicroBenchmarkConfig))]
public class NameAndUidBenchmarks
{
public const string ActorPath = "foo#11241311";

[Benchmark]
public NameAndUid ActorCell_SplitNameAndUid()
{
return ActorCell.SplitNameAndUid(ActorPath);
}

[Benchmark]
public (string name, int uid) ActorCell_GetNameAndUid()
{
return ActorCell.GetNameAndUid(ActorPath);
}
}
}
2 changes: 1 addition & 1 deletion src/benchmark/Akka.Benchmarks/Akka.Benchmarks.csproj
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
<PackageReference Include="BenchmarkDotNet" Version="0.13.0" />
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonVersion)" />
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" />
<!-- FluentAssertions is used in some benchmarks to validate internal behaviors -->
Expand Down

0 comments on commit a8347c5

Please sign in to comment.