Skip to content

Commit 193c74e

Browse files
Merge pull request #5305 from akkadotnet/dev
v1.4.27 Release
2 parents 2f92a5a + e575a8a commit 193c74e

File tree

30 files changed

+1295
-766
lines changed

30 files changed

+1295
-766
lines changed

RELEASE_NOTES.md

+76
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,79 @@
1+
#### 1.4.27 October 11 2021 ####
2+
**Maintenance Release for Akka.NET 1.4**
3+
Akka.NET v1.4.27 is a small release that contains some _major_ performance improvements for Akka.Remote.
4+
5+
**Performance Fixes**
6+
In [RemoteActorRefProvider address paring, caching and resolving improvements](https://github.com/akkadotnet/akka.net/pull/5273) Akka.NET contributor @Zetanova introduced some major changes that make the entire `ActorPath` class much more reusable and more parse-efficient.
7+
8+
Our last major round of Akka.NET performance improvements in Akka.NET v1.4.25 produced the following:
9+
10+
```
11+
OSVersion: Microsoft Windows NT 6.2.9200.0
12+
ProcessorCount: 16
13+
ClockSpeed: 0 MHZ
14+
Actor Count: 32
15+
Messages sent/received per client: 200000 (2e5)
16+
Is Server GC: True
17+
Thread count: 111
18+
19+
Num clients, Total [msg], Msgs/sec, Total [ms]
20+
1, 200000, 130634, 1531.54
21+
5, 1000000, 246975, 4049.20
22+
10, 2000000, 244499, 8180.16
23+
15, 3000000, 244978, 12246.39
24+
20, 4000000, 245159, 16316.37
25+
25, 5000000, 243333, 20548.09
26+
30, 6000000, 241644, 24830.55
27+
```
28+
29+
In Akka.NET v1.4.27 those numbers now look like:
30+
31+
```
32+
OSVersion: Microsoft Windows NT 6.2.9200.
33+
ProcessorCount: 16
34+
ClockSpeed: 0 MHZ
35+
Actor Count: 32
36+
Messages sent/received per client: 200000 (2e5)
37+
Is Server GC: True
38+
Thread count: 111
39+
40+
Num clients, Total [msg], Msgs/sec, Total [ms]
41+
1, 200000, 105043, 1904.29
42+
5, 1000000, 255494, 3914.73
43+
10, 2000000, 291843, 6853.30
44+
15, 3000000, 291291, 10299.75
45+
20, 4000000, 286513, 13961.68
46+
25, 5000000, 292569, 17090.64
47+
30, 6000000, 281492, 21315.35
48+
```
49+
50+
To put these numbers in comparison, here's what Akka.NET's performance looked like as of v1.4.0:
51+
52+
```
53+
Num clients (actors) Total [msg] Msgs/sec Total [ms]
54+
1 200000 69736 2868.60
55+
5 1000000 141243 7080.98
56+
10 2000000 136771 14623.27
57+
15 3000000 38190 78556.49
58+
20 4000000 32401 123454.60
59+
25 5000000 33341 149967.08
60+
30 6000000 126093 47584.92
61+
```
62+
63+
64+
We've made Akka.Remote consistently faster, more predictable, and reduced total memory consumption significantly in the process.
65+
66+
67+
You can [see the full set of changes introduced in Akka.NET v1.4.27 here](https://github.com/akkadotnet/akka.net/milestone/57?closed=1)
68+
69+
| COMMITS | LOC+ | LOC- | AUTHOR |
70+
| --- | --- | --- | --- |
71+
| 3 | 89 | 8 | Aaron Stannard |
72+
| 1 | 856 | 519 | Andreas Dirnberger |
73+
| 1 | 3 | 4 | Vadym Artemchuk |
74+
| 1 | 261 | 233 | Gregorius Soedharmo |
75+
| 1 | 1 | 1 | dependabot[bot] |
76+
177
#### 1.4.26 September 28 2021 ####
278
**Maintenance Release for Akka.NET 1.4**
379
Akka.NET v1.4.26 is a very small release that addresses one wire format regression introduced in Akka.NET v1.4.20.

docs/articles/actors/routers.md

+3-4
Original file line numberDiff line numberDiff line change
@@ -472,10 +472,9 @@ var router = system.ActorOf(Props.Empty.WithRouter(new ScatterGatherFirstComplet
472472

473473
The `SmallestMailboxPool` router will send the message to the routee with fewest messages in mailbox. The selection is done in this order:
474474

475-
1. Pick any idle routee (not processing message) with empty mailbox
476-
2. Pick any routee with empty mailbox
477-
3. Pick routee with fewest pending messages in mailbox
478-
4. Pick any remote routee, remote actors are consider lowest priority, since their mailbox size is unknown
475+
1. Pick any routee with empty mailbox
476+
2. Pick routee with fewest pending messages in mailbox
477+
3. Pick any remote routee, remote actors are consider lowest priority, since their mailbox size is unknown
479478

480479
![SmallestMailbox Router](/images/SmallestMailbox.png)
481480

src/common.props

+62-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<PropertyGroup>
33
<Copyright>Copyright © 2013-2021 Akka.NET Team</Copyright>
44
<Authors>Akka.NET Team</Authors>
5-
<VersionPrefix>1.4.23</VersionPrefix>
5+
<VersionPrefix>1.4.27</VersionPrefix>
66
<PackageIconUrl>https://getakka.net/images/akkalogo.png</PackageIconUrl>
77
<PackageProjectUrl>https://github.com/akkadotnet/akka.net</PackageProjectUrl>
88
<PackageLicenseUrl>https://github.com/akkadotnet/akka.net/blob/master/LICENSE</PackageLicenseUrl>
@@ -11,7 +11,7 @@
1111
<PropertyGroup>
1212
<XunitVersion>2.4.1</XunitVersion>
1313
<TestSdkVersion>16.11.0</TestSdkVersion>
14-
<HyperionVersion>0.11.1</HyperionVersion>
14+
<HyperionVersion>0.11.2</HyperionVersion>
1515
<NewtonsoftJsonVersion>[12.0.3,)</NewtonsoftJsonVersion>
1616
<NBenchVersion>2.0.1</NBenchVersion>
1717
<ProtobufVersion>3.17.3</ProtobufVersion>
@@ -30,7 +30,66 @@
3030
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
3131
</PropertyGroup>
3232
<PropertyGroup>
33-
<PackageReleaseNotes>Placeholder for nightlies**</PackageReleaseNotes>
33+
<PackageReleaseNotes>Maintenance Release for Akka.NET 1.4**
34+
Akka.NET v1.4.27 is a small release that contains some _major_ performance improvements for Akka.Remote.
35+
Performance Fixes**
36+
In [RemoteActorRefProvider address paring, caching and resolving improvements](https://github.com/akkadotnet/akka.net/pull/5273) Akka.NET contributor @Zetanova introduced some major changes that make the entire `ActorPath` class much more reusable and more parse-efficient.
37+
Our last major round of Akka.NET performance improvements in Akka.NET v1.4.25 produced the following:
38+
```
39+
OSVersion: Microsoft Windows NT 6.2.9200.0
40+
ProcessorCount: 16
41+
ClockSpeed: 0 MHZ
42+
Actor Count: 32
43+
Messages sent/received per client: 200000 (2e5)
44+
Is Server GC: True
45+
Thread count: 111
46+
Num clients, Total [msg], Msgs/sec, Total [ms]
47+
1, 200000, 130634, 1531.54
48+
5, 1000000, 246975, 4049.20
49+
10, 2000000, 244499, 8180.16
50+
15, 3000000, 244978, 12246.39
51+
20, 4000000, 245159, 16316.37
52+
25, 5000000, 243333, 20548.09
53+
30, 6000000, 241644, 24830.55
54+
```
55+
In Akka.NET v1.4.27 those numbers now look like:
56+
```
57+
OSVersion: Microsoft Windows NT 6.2.9200.
58+
ProcessorCount: 16
59+
ClockSpeed: 0 MHZ
60+
Actor Count: 32
61+
Messages sent/received per client: 200000 (2e5)
62+
Is Server GC: True
63+
Thread count: 111
64+
Num clients, Total [msg], Msgs/sec, Total [ms]
65+
1, 200000, 105043, 1904.29
66+
5, 1000000, 255494, 3914.73
67+
10, 2000000, 291843, 6853.30
68+
15, 3000000, 291291, 10299.75
69+
20, 4000000, 286513, 13961.68
70+
25, 5000000, 292569, 17090.64
71+
30, 6000000, 281492, 21315.35
72+
```
73+
To put these numbers in comparison, here's what Akka.NET's performance looked like as of v1.4.0:
74+
```
75+
Num clients (actors) Total [msg] Msgs/sec Total [ms]
76+
1 200000 69736 2868.60
77+
5 1000000 141243 7080.98
78+
10 2000000 136771 14623.27
79+
15 3000000 38190 78556.49
80+
20 4000000 32401 123454.60
81+
25 5000000 33341 149967.08
82+
30 6000000 126093 47584.92
83+
```
84+
We've made Akka.Remote consistently faster, more predictable, and reduced total memory consumption significantly in the process.
85+
You can [see the full set of changes introduced in Akka.NET v1.4.27 here](https://github.com/akkadotnet/akka.net/milestone/57?closed=1)
86+
| COMMITS | LOC+ | LOC- | AUTHOR |
87+
| --- | --- | --- | --- |
88+
| 3 | 89 | 8 | Aaron Stannard |
89+
| 1 | 856 | 519 | Andreas Dirnberger |
90+
| 1 | 3 | 4 | Vadym Artemchuk |
91+
| 1 | 261 | 233 | Gregorius Soedharmo |
92+
| 1 | 1 | 1 | dependabot[bot] |</PackageReleaseNotes>
3493
</PropertyGroup>
3594
<!-- SourceLink support for all Akka.NET projects -->
3695
<ItemGroup>

src/contrib/cluster/Akka.Cluster.Metrics/ClusterMetricsStrategy.cs

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using System;
99
using Akka.Actor;
1010
using Akka.Configuration;
11-
using Akka.Configuration;
1211

1312
namespace Akka.Cluster.Metrics
1413
{

src/core/Akka.API.Tests/CoreAPISpec.ApproveCore.approved.txt

+23-21
Original file line numberDiff line numberDiff line change
@@ -177,18 +177,21 @@ namespace Akka.Actor
177177
protected ActorPath(Akka.Actor.Address address, string name) { }
178178
protected ActorPath(Akka.Actor.ActorPath parentPath, string name, long uid) { }
179179
public Akka.Actor.Address Address { get; }
180-
public abstract System.Collections.Generic.IReadOnlyList<string> Elements { get; }
180+
public int Depth { get; }
181+
public System.Collections.Generic.IReadOnlyList<string> Elements { get; }
181182
public string Name { get; }
182-
public abstract Akka.Actor.ActorPath Parent { get; }
183-
public abstract Akka.Actor.ActorPath Root { get; }
183+
public Akka.Actor.ActorPath Parent { get; }
184+
[Newtonsoft.Json.JsonIgnoreAttribute()]
185+
public Akka.Actor.ActorPath Root { get; }
184186
public long Uid { get; }
185187
public Akka.Actor.ActorPath Child(string childName) { }
186-
public abstract int CompareTo(Akka.Actor.ActorPath other);
188+
public int CompareTo(Akka.Actor.ActorPath other) { }
187189
public bool Equals(Akka.Actor.ActorPath other) { }
188190
public override bool Equals(object obj) { }
189191
public static string FormatPathElements(System.Collections.Generic.IEnumerable<string> pathElements) { }
190192
public override int GetHashCode() { }
191193
public static bool IsValidPathElement(string s) { }
194+
public Akka.Actor.ActorPath ParentOf(int depth) { }
192195
public static Akka.Actor.ActorPath Parse(string path) { }
193196
public string ToSerializationFormat() { }
194197
public string ToSerializationFormatWithAddress(Akka.Actor.Address address) { }
@@ -199,13 +202,17 @@ namespace Akka.Actor
199202
public string ToStringWithoutAddress() { }
200203
public Akka.Util.ISurrogate ToSurrogate(Akka.Actor.ActorSystem system) { }
201204
public static bool TryParse(string path, out Akka.Actor.ActorPath actorPath) { }
205+
public static bool TryParse(Akka.Actor.ActorPath basePath, string absoluteUri, out Akka.Actor.ActorPath actorPath) { }
206+
public static bool TryParse(Akka.Actor.ActorPath basePath, System.ReadOnlySpan<char> absoluteUri, out Akka.Actor.ActorPath actorPath) { }
202207
public static bool TryParseAddress(string path, out Akka.Actor.Address address) { }
203-
public abstract Akka.Actor.ActorPath WithUid(long uid);
208+
public static bool TryParseAddress(string path, out Akka.Actor.Address address, out System.ReadOnlySpan<char> absoluteUri) { }
209+
public static bool TryParseParts(System.ReadOnlySpan<char> path, out System.ReadOnlySpan<char> address, out System.ReadOnlySpan<char> absoluteUri) { }
210+
public Akka.Actor.ActorPath WithUid(long uid) { }
204211
public static Akka.Actor.ActorPath /(Akka.Actor.ActorPath path, string name) { }
205212
public static Akka.Actor.ActorPath /(Akka.Actor.ActorPath path, System.Collections.Generic.IEnumerable<string> name) { }
206213
public static bool ==(Akka.Actor.ActorPath left, Akka.Actor.ActorPath right) { }
207214
public static bool !=(Akka.Actor.ActorPath left, Akka.Actor.ActorPath right) { }
208-
public class Surrogate : Akka.Util.ISurrogate, System.IEquatable<Akka.Actor.ActorPath.Surrogate>, System.IEquatable<Akka.Actor.ActorPath>
215+
public sealed class Surrogate : Akka.Util.ISurrogate, System.IEquatable<Akka.Actor.ActorPath.Surrogate>, System.IEquatable<Akka.Actor.ActorPath>
209216
{
210217
public Surrogate(string path) { }
211218
public string Path { get; }
@@ -408,13 +415,17 @@ namespace Akka.Actor
408415
public static Akka.Actor.Address Parse(string address) { }
409416
public override string ToString() { }
410417
public Akka.Util.ISurrogate ToSurrogate(Akka.Actor.ActorSystem system) { }
418+
public static bool TryParse(string path, out Akka.Actor.Address address) { }
419+
public static bool TryParse(string path, out Akka.Actor.Address address, out string absolutUri) { }
420+
public static bool TryParse(System.ReadOnlySpan<char> span, out Akka.Actor.Address address) { }
421+
public static bool TryParse(System.ReadOnlySpan<char> span, out Akka.Actor.Address address, out System.ReadOnlySpan<char> absolutUri) { }
411422
public Akka.Actor.Address WithHost(string host = null) { }
412423
public Akka.Actor.Address WithPort(System.Nullable<int> port = null) { }
413424
public Akka.Actor.Address WithProtocol(string protocol) { }
414425
public Akka.Actor.Address WithSystem(string system) { }
415426
public static bool ==(Akka.Actor.Address left, Akka.Actor.Address right) { }
416427
public static bool !=(Akka.Actor.Address left, Akka.Actor.Address right) { }
417-
public class AddressSurrogate : Akka.Util.ISurrogate
428+
public sealed class AddressSurrogate : Akka.Util.ISurrogate
418429
{
419430
public AddressSurrogate() { }
420431
public string Host { get; set; }
@@ -497,15 +508,9 @@ namespace Akka.Actor
497508
{
498509
public static void CancelIfNotNull(this Akka.Actor.ICancelable cancelable) { }
499510
}
500-
public class ChildActorPath : Akka.Actor.ActorPath
511+
public sealed class ChildActorPath : Akka.Actor.ActorPath
501512
{
502513
public ChildActorPath(Akka.Actor.ActorPath parentPath, string name, long uid) { }
503-
public override System.Collections.Generic.IReadOnlyList<string> Elements { get; }
504-
public override Akka.Actor.ActorPath Parent { get; }
505-
public override Akka.Actor.ActorPath Root { get; }
506-
public override int CompareTo(Akka.Actor.ActorPath other) { }
507-
public override int GetHashCode() { }
508-
public override Akka.Actor.ActorPath WithUid(long uid) { }
509514
}
510515
public sealed class CoordinatedShutdown : Akka.Actor.IExtension
511516
{
@@ -963,6 +968,8 @@ namespace Akka.Actor
963968
Akka.Actor.IInternalActorRef TempContainer { get; }
964969
System.Threading.Tasks.Task TerminationTask { get; }
965970
Akka.Actor.IInternalActorRef ActorOf(Akka.Actor.Internal.ActorSystemImpl system, Akka.Actor.Props props, Akka.Actor.IInternalActorRef supervisor, Akka.Actor.ActorPath path, bool systemService, Akka.Actor.Deploy deploy, bool lookupDeploy, bool async);
971+
[Akka.Annotations.InternalApiAttribute()]
972+
Akka.Actor.FutureActorRef<T> CreateFutureRef<T>(System.Threading.Tasks.TaskCompletionSource<T> tcs);
966973
Akka.Actor.Address GetExternalAddressFor(Akka.Actor.Address address);
967974
void Init(Akka.Actor.Internal.ActorSystemImpl system);
968975
void RegisterTempActor(Akka.Actor.IInternalActorRef actorRef, Akka.Actor.ActorPath path);
@@ -1274,6 +1281,7 @@ namespace Akka.Actor
12741281
public Akka.Actor.IInternalActorRef TempContainer { get; }
12751282
public System.Threading.Tasks.Task TerminationTask { get; }
12761283
public Akka.Actor.IInternalActorRef ActorOf(Akka.Actor.Internal.ActorSystemImpl system, Akka.Actor.Props props, Akka.Actor.IInternalActorRef supervisor, Akka.Actor.ActorPath path, bool systemService, Akka.Actor.Deploy deploy, bool lookupDeploy, bool async) { }
1284+
public Akka.Actor.FutureActorRef<T> CreateFutureRef<T>(System.Threading.Tasks.TaskCompletionSource<T> tcs) { }
12771285
public Akka.Actor.Address GetExternalAddressFor(Akka.Actor.Address address) { }
12781286
public void Init(Akka.Actor.Internal.ActorSystemImpl system) { }
12791287
public void RegisterExtraName(string name, Akka.Actor.IInternalActorRef actor) { }
@@ -1546,15 +1554,9 @@ namespace Akka.Actor
15461554
public void SwapUnderlying(Akka.Actor.ICell cell) { }
15471555
protected override void TellInternal(object message, Akka.Actor.IActorRef sender) { }
15481556
}
1549-
public class RootActorPath : Akka.Actor.ActorPath
1557+
public sealed class RootActorPath : Akka.Actor.ActorPath
15501558
{
15511559
public RootActorPath(Akka.Actor.Address address, string name = "") { }
1552-
public override System.Collections.Generic.IReadOnlyList<string> Elements { get; }
1553-
public override Akka.Actor.ActorPath Parent { get; }
1554-
[Newtonsoft.Json.JsonIgnoreAttribute()]
1555-
public override Akka.Actor.ActorPath Root { get; }
1556-
public override int CompareTo(Akka.Actor.ActorPath other) { }
1557-
public override Akka.Actor.ActorPath WithUid(long uid) { }
15581560
}
15591561
[Akka.Annotations.InternalApiAttribute()]
15601562
public class RootGuardianActorRef : Akka.Actor.LocalActorRef

src/core/Akka.API.Tests/CoreAPISpec.ApproveRemote.approved.txt

+1
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ namespace Akka.Remote
202202
public System.Threading.Tasks.Task TerminationTask { get; }
203203
public Akka.Remote.RemoteTransport Transport { get; }
204204
public Akka.Actor.IInternalActorRef ActorOf(Akka.Actor.Internal.ActorSystemImpl system, Akka.Actor.Props props, Akka.Actor.IInternalActorRef supervisor, Akka.Actor.ActorPath path, bool systemService, Akka.Actor.Deploy deploy, bool lookupDeploy, bool async) { }
205+
public Akka.Actor.FutureActorRef<T> CreateFutureRef<T>(System.Threading.Tasks.TaskCompletionSource<T> tcs) { }
205206
protected virtual Akka.Actor.IActorRef CreateRemoteDeploymentWatcher(Akka.Actor.Internal.ActorSystemImpl system) { }
206207
protected virtual Akka.Actor.IInternalActorRef CreateRemoteRef(Akka.Actor.ActorPath actorPath, Akka.Actor.Address localAddress) { }
207208
protected virtual Akka.Actor.IInternalActorRef CreateRemoteRef(Akka.Actor.Props props, Akka.Actor.IInternalActorRef supervisor, Akka.Actor.Address localAddress, Akka.Actor.ActorPath rpath, Akka.Actor.Deploy deployment) { }

src/core/Akka.Cluster/ClusterDaemon.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1561,8 +1561,9 @@ public void StopSeedNodeProcess()
15611561
/// Received `Join` message and replies with `Welcome` message, containing
15621562
/// current gossip state, including the new joining member.
15631563
/// </summary>
1564-
/// <param name="node">TBD</param>
1565-
/// <param name="roles">TBD</param>
1564+
/// <param name="node">The unique address of the joining node.</param>
1565+
/// <param name="roles">The roles, if any, of the joining node.</param>
1566+
/// <param name="appVersion">The software version of the joining node.</param>
15661567
public void Joining(UniqueAddress node, ImmutableHashSet<string> roles, AppVersion appVersion)
15671568
{
15681569
var selfStatus = LatestGossip.GetMember(SelfUniqueAddress).Status;

src/core/Akka.MultiNodeTestRunner.Shared.Tests/MultiNodeTestRunnerDiscovery/DiscoverySpec.cs

+12-5
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,22 @@ public void Only_MultiNodeConfig_role_count_used()
6464
private static Dictionary<string, List<NodeTest>> DiscoverSpecs()
6565
{
6666
Environment.SetEnvironmentVariable(MultiNodeFactAttribute.MultiNodeTestEnvironmentName, "1");
67-
using (var controller = new XunitFrontController(AppDomainSupport.IfAvailable, new System.Uri(typeof(DiscoveryCases).GetTypeInfo().Assembly.CodeBase).LocalPath))
67+
try
6868
{
69-
using (var discovery = new Discovery())
69+
using (var controller = new XunitFrontController(AppDomainSupport.IfAvailable, new System.Uri(typeof(DiscoveryCases).GetTypeInfo().Assembly.CodeBase).LocalPath))
7070
{
71-
controller.Find(false, discovery, TestFrameworkOptions.ForDiscovery());
72-
discovery.Finished.WaitOne();
73-
return discovery.Tests;
71+
using (var discovery = new Discovery())
72+
{
73+
controller.Find(false, discovery, TestFrameworkOptions.ForDiscovery());
74+
discovery.Finished.WaitOne();
75+
return discovery.Tests;
76+
}
7477
}
7578
}
79+
finally
80+
{
81+
Environment.SetEnvironmentVariable(MultiNodeFactAttribute.MultiNodeTestEnvironmentName, null);
82+
}
7683
}
7784

7885
private string KeyFromSpecName(string specName)

0 commit comments

Comments
 (0)