Monthly Archives: March 2017

Proto.Actor Remoting

I’m now going to take a look at what’s required to implement a remote Proto.Actor and a “client” to interact with it. I’m going to stick to the standard Greet class, as shown in my previous post, but we’re going to generate the Greet class from a .proto (protocol buffers) definition file.

So before we get into the client/server code, let’s create the Greet.proto file, here’s it is

syntax = "proto3";

package messages;
option csharp_namespace = "Messages";

message Greet {
   string Who = 1;
}

The Greet message will generate a Greet type with a property name Who. So once you’ve created this file, you’ll need to use protoc.exe with the following command line

protoc.exe –csharp_out=. Greet.proto

This will generate the Greet.cs file, which I will not bother to show here.

Next up, we’ll reuse our GreetActor class from the previous post, recreated below

public class GreetingActor : IActor
{
   public Task ReceiveAsync(IContext context)
   {
      var greet = context.Message as Greet;
      if (greet != null)
      {
         Console.WriteLine("[Thread {0}] Greeting {1}",
            Thread.CurrentThread.ManagedThreadId,
            greet.Who);
      }
      return Actor.Done;
   }
}

As we know, strictly speaking Akka.net and also Proto.Actor do not adhere to a client/server architecture but remote objects are created in a peer to peer architecture. For the sake of this post we will create two separate projects, one named Server the other Client, just for simplicity.

Creating our server

  • Create a Console application, named something like ProtoActorServer
  • Using Nuget add the Proto.Actor and Proto.Remote packages
  • Add or link to the Greet.cs file generated by protoc
  • Add or link to the GreetActor.cs file from above
  • In Program.cs add the following using clauses
    using Messages;
    using Proto;
    using Proto.Remote;
    
  • In the Main method add the following code
    Serialization.RegisterFileDescriptor(GreetReflection.Descriptor);
    RemotingSystem.Start("127.0.0.1", 12000);
    
    var props = Actor.FromProducer(() => new GreetingActor());
    Actor.SpawnNamed(props, "remote");
    
    // just to keep the app. open
    Console.ReadLine();
    

Creating our client

As we know, this is going to basically be very similar to the server is set-up, but there are differences in the code, but I’ll still list all the steps for completeness

  • Create a Console application, named something like ProtoActorClient
  • Using Nuget add the Proto.Actor and Proto.Remote packages
  • Add or link to the Greet.cs file generated by protoc
  • Add or link to the GreetActor.cs file from above
  • In Program.cs add the following using clauses
    using Messages;
    using Proto;
    using Proto.Remote;
    
  • In the Main method add the following code
    Serialization.RegisterFileDescriptor(GreetReflection.Descriptor);
    RemotingSystem.Start("127.0.0.1", 12001);
    
    var remote = new PID("127.0.0.1:12000", "remote");
    remote.Tell(new Greet { Who = "Hello World" });;
    
    // just to keep the app. open
    Console.ReadLine();
    

If you now run the ProtoActorServer and then the ProtoActorClient you should see the Greeting Hello World message displayed on the server console via it’s GreetingActor.

Disclaimer

At the time of writing this I’ve not yet seen documentation to suggest I’m doing everything 100% by the Proto.Actor book, so to speak, I’ve based this code on previous use of protobuf and Akka.net as well as a couple of examples from the Proto.Actor git repos. If I find I’m doing anything incorrectly, I will update this page.

Proto.Actor first look

No sooner had I started looking to use Akka.net, than I find out about Proto.Actor (via .NET Rocks). From my understanding this comes from some of the same guys involved in Akka.net and currently supports .NET and the language Go.

One of my previous posts covered Getting started with Akka.net. Let’s take that post and rewrite the code using the Proto.Actor library, just to see what the differences are.

  • Create a Console application
  • Using Nuget, add the Proto.Actor package
  • Create a class named Greet, this will be used as the payload for wrapping our data that we shall pass to our Actor object. Here’s the code
    public class Greet
    {
       public Greet(string who)
       {
          Who = who;
       }
     
       public string Who { get; private set; }
    }
    
  • Create a new class named GreetingActor. This is our Actor object that does something and will accept objects of type Greet, the code should look like this
    public class GreetingActor : IActor
    {
       public Task ReceiveAsync(IContext context)
       {
          var greet = context.Message as Greet;
          if (greet != null)
          {
             Console.WriteLine("[Thread {0}] Greeting {1}",
                    Thread.CurrentThread.ManagedThreadId,
                    greet.Who);
          }
          return Actor.Done;
       }
    }
    

    So here’s the first difference, code-wise. We are implementing the IActor interface and our code goes in the ReceiveAsync method as opposed the Akka.net code which went in the constructor. Also we have to check the type in the context Message as opposed to using the Akka.net Receive<> generic to differentiate our types. Obviously with the latest C# 7 features we can use type matching, but I’m running this on C# 6 so the standard as operator is used.

  • Finally we want to create an instance of an actor and send a message to it via the Tell method, so our Main method should look like this
    var props = Actor.FromProducer(() => new GreetingActor());
    var greeter = Actor.Spawn(props);
    greeter.Tell(new Greet("Hello World"));
    
    // to stop the console closing 
    // before the message is received
    Console.ReadLine();
    

    This differs from Akka.net in the way we create the greeter but it’s the same number of lines of code and equally simple.

So in the code above we create the Greet class for our message type (in essence) and obviously the GreetingActor listens for Greet messages. In the Main method we create a Props instance from the Actor system using FromProducer (which acts as a factory type pattern) then using the Actor.Spawn we actually create an instance of each actor we want in our system.

The Tell line in the Main method is the same as Akka.net, in that we send a message to the greeter Actor via the Tell method and at some point the GreatingActor will receive this message and write it’s text to the Console and that’s it.

Using NBench for performance testing

Introduction

NBench is a performance testing framework which we can run from our unit tests to profile method performance and (hopefully) ensure any refactoring or other changes will highlight possible performance issues instantly (well at least when the unit tests are run which after all should be on every check-in).

So what we want to do is write some performance based unit test around a method, possibly the method is currently slow and we want to refactor it or it’s a critical point where performance must exceed a certain level, i.e. the method call must complete in less than n ms.

Note: Libraries such as NUnit already have a capability for profiling the amount of time the test takes to complete, but NBench offers this and a lot more besides.

We can write a performance test around our code which will fail if the method takes longer than expected to complete.

NBench is much more than just a stopwatch/timer though. We can benchmark memory usage, GC’s and counters.

Getting Started

My current priority is classic performance testing, i.e. how fast is this method. So let’s start by writing some code and some tests using NBench for this and see how things fit together.

  • Create a Class Library project
  • Add the Nuget package – i.e. Install-Package NBench
  • From the Package Manager Console, also run Install-Package NBench.Runner

Note: NBench.Runner is a simple command line runner, which we’ll use initially to test our code.

Let’s create a “Simple” Cache class to run our tests on.

public class SimpleCache<T>
{
   private readonly List<T> cache = new List<T>();

   public void Add(T item)
   {
      if(!Contains(item))
         cache.Add(item);
   }

   public bool Contains(T item)
   {
      return cache.Contains(item);
   }
}

Next, let’s write our first NBench performance test, here’s the code we’ll test, which is not an optimal solution to the requirements of writing a cache.

public class CacheTest
{
    private SimpleCache<string> cache = new SimpleCache<string>();

    [PerfBenchmark(NumberOfIterations = 1, 
       RunMode = RunMode.Throughput, 
       TestMode = TestMode.Test, 
       SkipWarmups = true)]
    [ElapsedTimeAssertion(MaxTimeMilliseconds = 2000)]
    public void Add_Benchmark_Performance()
    {
       for (var i = 0; i < 100000; i++)
       {
          cache.Add(i.ToString());
       }
    }
}

We need to mark our test with the PerfBenchmark attribute. This in itself doesn’t measure anything, it’s more about telling the runner what to do with the method it’s annotating. So we need to declare some measurements. We’re only currently interested in the elapsed time of the method under test, so we’re using the ElapsedTimeAssertionAttribute and stating that our method should take no longer than 2000 ms to complete.

We can run multiple iterations of the method and the result is the average of the runs. This is especially useful if we’re trying to look at GC’s etc. but for this example we’re just going to run the test once.

The use of TestMode.Test will work like a unit tests, i.e. PASS/FAIL, for information on the other attribute properties, see the NBench github page.

Upon running this code using the NBench.Runner.exe, I get a FAIL (as I expected) this method is a lot slower than I expect it to be with this number of items being added.

So let’s leave the test as it is an see if we can refactor the code. Here’s a quick an dirty version of the cache using a Dictionary

public class SimpleCache<T>
{
   private readonly Dictionary<T, T> cache = new Dictionary<T, T>();

   public void Add(T item)
   {
      if (!Contains(item))
         cache.Add(item, item);
   }

   public bool Contains(T item)
   {
      return cache.ContainsKey(item);
    }
}

Now when I run the test with the TestRunner, I get a PASS (well we would expect this implementation to be massively faster that the linear search list version!).

Integration with our build server

Obviously we run a build/continuous integration server, so we want to integrate these tests into our builds. Now it may be that you can use the NBench runner within your build, but (as mentioned in a previous post) there’s already a way to achieve this integration with the likes on NUnit (see NBench Performance Testing – NUnit and ReSharper Integration).

I’ve recreated the code show in the aforementioned blog post here, for completeness

public abstract class PerformanceTestSuite<T>
{
   [TestCaseSource(nameof(Benchmarks))]
   public void PerformanceTests(Benchmark benchmark)
   {
      Benchmark.PrepareForRun();
      benchmark.Run();
      benchmark.Finish();
    }

    public static IEnumerable Benchmarks()
    {
      var discovery = new ReflectionDiscovery(
         new ActionBenchmarkOutput(report => { }, results =>
         {
            foreach (var assertion in results.AssertionResults)
            {
                Assert.True(assertion.Passed, 
                    results.BenchmarkName + " " + assertion.Message);
                Console.WriteLine(assertion.Message);
            }
      }));

      var benchmarks = discovery.FindBenchmarks(typeof(T)).ToList();

      foreach (var benchmark in benchmarks)
      {
         var name = benchmark.BenchmarkName.Split('+')[1];
         yield return new TestCaseData(benchmark).SetName(name);
      }
   }
}

Now simple derive out test from PerformanceTestSuite, like this

public class CacheTest : PerformanceTestSuite<CacheTest>
{
   // our code
}

Benchmarking GC collections

What if we want to look at measuring the method in terms of garbage collection and it’s possible affect on your code’s performance. NBench inclues the GCTotalAssertAttribute. Just add the following to the previous method

[GcTotalAssertion(GcMetric.TotalCollections, 
   GcGeneration.Gen0, MustBe.ExactlyEqualTo, 0.0d)]
public void Add_Benchmark_Performance()
{
    // our code
}

This, as one might expect, causes a failure on my test as it’s expecting ZERO Gen 0 collections. With this FAIL information we can now update our test to something more realistic or look at whether we can alter our code to pass the test (obviously this is less likely for a caching class).

Pre and Post benchmarking code

We have the equivalent of a setup/teardown attributes. A PerfSetupAttribute marked method is run before the benchmarking tests, this is useful for setting up the counters or the likes used within the tests and a PerCleanupAttribute is used on a method to clean up any code, post test.

Available Assertions

In the current release of NBench we have the following assertions

  • MemoryAssertionAttribute – asserts based upon the memory allocated
  • GcTotalAssertionAttribute – asserts based upon total GC’s
  • ElapsedTimeAssertionAttribute – asserts based upon the amount of time a method takes
  • CounterTotalAssertionAttribute – asserts based upon counter collection
  • GcThroughputAssertionAttribute – asserts based upon GC throughput (i.e. average time)
  • CounterThroughputAssertionAttribute – asserts based upon counter throughput (i.e. average time)
  • PerformanceCounterTotalAssertionAttribute – asserts based upon total average performance counter values
  • PerformanceCounterTotalAssertionAttribute – asserts based upon throughput of performance counters

Akka Remoting

In this post I’ll be covering pretty much the same as the Akka.net Remoting page. So I would definitely suggest you read that instead or in conjunction with this post.

As Akka.net has been designed for distributed systems and because (as you’ll have seen from my previous post on Akka.net) you interact with Actor objects via messages. Distributing your Actors should be pretty simple and painless. Let’s see if that holds true.

Initially we’re going to simply create two console applications. Let’s start off by thinking of one as the AkkaServer and the other the AkkaClient (although conceptually, in many ways, the idea of a server and client are meaningless in such an application as they’re really just “peers”).

Let’s write some code

  • Both projects are going to be compiled in .NET 4.6, so go ahead a create two console applications, name the first AkkaServer and the second AkkaClient.
  • Next up, add the Nuget Packages for Akka and Akka.Remote to both projects.
  • We could now create a third solution for our shared types, but let’s just add a new project to the AkkaServer, mine’s named Shared, you’ll need to add the Akka Nuget package to this project also.
  • In the Shared project, add the GreetingActor (as outlined previously and in the Akka.net documentation, here it is for completeness
    public class Greet
    {
       public Greet(string who)
       {
          Who = who;
       }
    
       public string Who { get; private set; }
    }
    
    public class GreetingActor : ReceiveActor
    {
       public GreetingActor()
       {
          Receive<Greet>(greet =>
             Console.WriteLine("{0} Greeting {1}",
             Thread.CurrentThread.ManagedThreadId, 
             greet.Who));
       }
    }
    
  • Once built, add the Shared.dll as a reference to your AkkaClient, so you’ve got access to the same type of GreetingActor etc.
  • In the AkkaServer Main method simply place the following
    var config = ConfigurationFactory.ParseString(@"
    akka {
        actor {
            provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
        }
    
        remote {
            helios.tcp {
                port = 8080
                hostname = localhost
            }
        }
    }");
    
    using (var system = ActorSystem.Create("MyServer", config))
    {
       system.ActorOf<GreetingActor>("greeter");
       Console.ReadKey();
    }
    

    This code is taken from Remoting as is the next piece of code for the client

  • Now in the AkkaClient Main method place the following
    var config = ConfigurationFactory.ParseString(@"
    akka {
        actor {
            provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
        }
        remote {
            helios.tcp {
                port = 8090
                hostname = localhost
            }
        }
    }");
    
    using (var system = ActorSystem.Create("MyClient", config))
    {
       var greeter = system.ActorSelection(
          "akka.tcp://MyServer@localhost:8080/user/greeter");
    
       greeter.Tell(new Greet("Roger"));
    
       Console.ReadLine();
    }
    

Run the server and then the client and you should see (in the server console window) the Greeting Roger text.

What have we just done?

So as you can see, we’re using the ConfigurationFactory.ParseString to simply create our remoting configuration in both the client and server. For this example, both applications are expected to be available on the localhost and therefore require different ports to communicate through.

We then create our ActorSystem in each application, for the sake of this example, one is perceived as the server and one as the client, but the beauty of Akka.net is they can be deployed in a peer-to-peer manner (which we’ll look at also).

Our AkkaServer creates an instance of the GreetingActor and then waits for messages. The AkkaClient uses the ActorSelection method to locate the server Actor (or a known name greeter. Although ofcourse we could just find all Actors if we wished) and then via the Tell method sends a messages to the Actor running on the server.

Let’s move towards a Peer-to-Peer design

Time to create the classic peer-to-peer chat application. This is going to be very basic and built using the previous code. The only changes to the two solutions are in the Main methods. Keep the config code the same as it was, but in the server replace the existing code with

using (var system = ActorSystem.Create("MyServer", config))
{
   system.ActorOf<GreetingActor>("greeter");

   string msg;
   while (!String.IsNullOrEmpty(msg = Console.ReadLine()))
   {
      var greeter = system.ActorSelection(
          "akka.tcp://MyClient@localhost:8090/user/greeter");

      greeter.Tell(new Greet(msg));
   }
}

and in the client, the code is exactly the same except MyServer becomes MyClient and the akka.tcp line changes to akka.tcp://MyServer@localhost:8080/user/greeter. For completeness here’s the code in full anyway

using (var system = ActorSystem.Create("MyClient", config))
{
   system.ActorOf<GreetingActor>("greeter");

   string msg;
   while (!String.IsNullOrEmpty(msg = Console.ReadLine()))
   {
      var greeter = system.ActorSelection(
         "akka.tcp://MyServer@localhost:8080/user/greeter");

      greeter.Tell(new Greet(msg));
   }
}

If you run up both solutions, both will create their own greeter Actor and only upon receiving some input via Console.ReadLine, will try to connect to all greeter Actors on to other’s ActorSystem (i.e. server will try to send to client and vice versa).

All this is happening via TCP and hence we could just as easily move one of the applications onto another machine – as long as both are accessible to one another, they should seamlessly work.

So there you have it, a very basic introduction to peer to peer Akka.net objects.