Building Highly Scalable Distributed Applications with Actor Model

Gökhan GÖKALP

29.06.2018

Devnot Yazılımcı Buluşmaları

Who am I?

Gökhan GÖKALP
Software Architect

http://www.gokhan-gokalp.com

E-mail: gok.gokalp@yahoo.com
LinkedIn: in/gokgokalp

Twitter: @gokgokalp

Agenda

  • History
  • Actor Model
  • Project Orleans
  • Development with Project Orleans
  • Approximate Performance Expectations
  • References
  • Contacts

History

  • Performance issues.
  • In today, we still have performance issues.
  • Carl Hewitt & Alan Kay faced same issues in 1970s.
  • Message passing systems invented.
  • Carl Hewitt created Actor Model.
  • Erlang
  • Akka for JVM
  • Akka.NET
  • Microsoft Orleans

"Message passing" the key point

Concurrent & Parallel

Concurrent

  • Simultaneously, not parallel. (context switch)
  • A logical distinction.
  • Can be worked with single core.

Parallel

  • Processor's power physically.
  • Multi-core.

Concurrent & Parallel

  • We are losing benefits of OOP. (encapsulating states etc.)
  • Concurrency issues. (deadlocks, race-conditions)
  • Sharing mutable state :(

Actor Model

  • Actor model paradigm where smallest of work is being done by an actor.
  • Its state and behaviour encapsulated inside it.
  • Without locking issues.
  • Highly performance & fault-tolerance.

Concurrent & parallel, huh?

Actor Model

  • Message passing and async communication.
  • Actors in a system can work multiple at the same time.
  • An actor processes messages sequentially.
  • Divide and conquer approach.

Actors have mailboxes

Actor Model

  • Message oriented, mailboxes, talks with immutable messages.
  • An actor can create more actors. (like ants, divides)
  • Self-healing. (fault-tolerance, different action)
  • Each actor is completely independent of the other. (no memory sharing)
  • Async. (no order guarantee)
  • Unique address and location transparency. (across machines, cores)

What do they do?

Debugging, tracing, testing could be hard.

Actor Model

An example

We can think actors as a group of people. Everyone has some functionality and independent of each other. They are communicating with each other via emails.

What do they do?

Actor Model

An example

Student sends an email to the teacher of him and email is immutable. (non-blocking operation) The teacher checks her mailbox at any time.

What do they do?

Actor Model

When?

  • Especially when high throughput is important.
  • Dynamically scaling. (e.g. we can create more actors against high loads)

Published 1970s

Erlang 1980s (fault-tolerant)

Project Orleans

Orleans is a framework that provides a straightforward approach to building distributed "cloud-based" high scale computing applications without thinking "concurrency" issues.

Virtual Actor Model Abstraction (concurrency & high scalability)

  • Distributed cloud computing is a hard problem. (failures, need a good design)
  • Distributed resource management.
  • No single points of failure.
  • Less code. (time efficiency)

No need to learn:

  • Complex concurrency patterns. (single-threaded execution context)
  • Scaling patterns.

Microsoft research

Project Orleans

Open-sourced, January 2015

Microsoft research

Project Orleans

In OOP, we encapsulating states of objects. Also, it's easy to be able to do stateful operations. (shared memory)

but, in distributed stateless world :(

shared memory, encapsulating? :(

Project Orleans

but, in orleans project;

It's possible to build a distributed environment that behaves like single shared memory, encapsulates states and can scale with "low latency".

I love in memory...

Project Orleans

Orleans Concepts

Orleans works in silos in each machine. In silos, grains are activated.

  • Silo: deployment host for Grains.
    • One or more Silos per node.
  • Grain: an actor is called Grain in Orleans.

If silo failure, its grains are reactivated at other silos.

Project Orleans

Orleans Concepts

  • Silo is also responsible for deactivating grains which completed their job. (optimization)
  • It's also possible to add new nodes in Orleans cluster dynamically.

real-time things during high loads, huh?

Project Orleans

Orleans Concepts - Grains

  • Each grain have a unique identifier.
  • Grains can have a persistent state into in-memory or a store.
  • Grains not have a shared state. (concurrency)
  • Grains can call each other.
  • Grains have a message queue.

Grain lifecycle management runs at runtime transparently.

Project Orleans

Orleans Concepts - Silo

  • Deployment host for Grains.
  • Manages lifecycles of Grains.
  • It's a console application.
  • Clustered.
    • Requires persistent storage for reliable cluster membership. (up or down)
      • Azure Table Storage
      • SQL Server
      • Zookeeper
      • MySQL
      • PostgreSQL
      • Consul
      • DynamoDB

Project Orleans

Core Features

  • Grain Persistance. (auto)
    • E.g: Azure Table Storage, SQL Server.
    • Self-healing.
  • Timers.
  • Dependency Injection.
  • Observers. (for asynchronous)
  • Stateless Worker Grain. (scale-out, core count of a node.)

Project Orleans

Core Features - Streams

  • Streaming extensions. (some abstractions & APIs)
  • Reactive applications can be developed.
  • No need to write extra codes for work with queues. With Extensibility model of Orleans:
    • Azure Event Hubs
    • Azure ServiceBus
    • Azure Queues
    • Apache Kafka
  • Lightweight and dynamic stream.
  • Designed to handle a large number of streams.

Project Orleans

Scenarios​

  • IoT (telemetry data)
  • Real-time server backend. (Like Halo)
  • Real-time analytics. (stream, e.g fraud) detection)
  • Cache
  • etc...

Project Orleans

Deployment​

  • Local development.
    • UseLocalhostClustering() in SiloHostBuilder
  • Cluster of nodes. (or single node for development & testing)
    • For reliable management of cluster membership:
      • Azure Table Storage
      • SQL Server
      • Zookeeper
      • MySQL
      • PostgreSQL
      • Consul
      • DynamoDB
  • Azure, AWS, GCP
  • Docker
    • .NET Core
    • Kubernetes, Docker Swarm

Project Orleans

Monitoring

  • Microsoft.Orleans.OrleansTelemetryConsumers.AI (Application Insights)
  • Microsoft.Orleans.OrleansTelemetryConsumers.NewRelic (NewRelic)

Orleans output its runtime statistics and metrics through the ITelemetryConsumer interface.

Project Orleans

Design Grain Interface

Development with

Grains interact with each other by invoking methods declared as part of the respective grain interfaces.

  • Grain interface should implement IGrain interface.
  • All methods of a grain interface must return a Task.
  • Clients and Grains communicate with each other via RPC.
public interface IMyGrain : IGrainWithIntegerKey
{
    Task<string> SayHello(string name);
}

Project Orleans

Implement Grain Interface

Development with

  • Grain derived from base Grain class and implement interface.
public class MyGrain : Grain, IMyGrain
{
    public Task<string> SayHello(string name)
    {
        return Task.FromResult($"Hello {name}");
    }
}

Accessing a Grain

var helloGrain = client.GetGrain<IMyGrain>(1); //Called grain activation
await helloGrain.SayHello("Gökhan");
  • We can access a grain easily with its identity key.

Project Orleans

Grain Persistance

Development with

  • Grain classes that inherit from Grain<T> will have their state loaded automatically from a specified storage.
  • Allow different grain types to use different types of storage providers.
[StorageProvider(ProviderName="store1")]
public class MyGrain : Grain<MyGrainState>, IMyGrain
{
    public Task<string> SayHello(string name)
    {
        return Task.FromResult($"Hello {name}");
    }
}
<StorageProviders>
    <Provider Type="Orleans.Storage.MemoryStorage" Name="devStore" />
    <Provider Type="Orleans.Storage.AzureTableStorage" Name="store1"
        DataConnectionString="..." />
    <Provider Type="Orleans.Storage.AzureBlobStorage" Name="store2"
        DataConnectionString="..."  />
</StorageProviders>

Project Orleans

Dependency Injection

Development with

  • Orleans uses the DI abstraction created for ASP.NET Core.
var siloBuilder = new SiloHostBuilder(); //new ClientBuilder();

siloBuilder.ConfigureServices(svc=>
                 svc.AddSingleton<IInjectedService,InjectedService>());
public class MyGrain : Grain, IMyGrain
{
    private readonly IInjectedService _injectedService;

    public MyGrain(IInjectedService injectedService)
    {
        _injectedService = injectedService;
    }

    public Task<string> SayHello(string name)
    {
        return Task.FromResult($"Hello {name}");
    }
}

Project Orleans

Stateless Worker Grain (performans)

Development with

  • Especially for functional stateless operations. (e.g compressed or encrypted values)
  • Easily scale out. (core count of a node.)
[StatelessWorker]
public class MyStatelessWorkerGrain : Grain, IMyStatelessWorkerGrain
{
 ...
}
  • Making a call to a Stateless Worker grain is the same as to any other grain.
var worker = GrainFactory
                .GetGrain<IMyStatelessWorkerGrain>(0); //or Guid.Empty
await worker.Process(args);

Project Orleans

Development with

Appromixmate Performance Expectations

Using X-Large VMs (8 CPU Cores / 14 GB RAM) on Microsoft Azure, with one silo per VM:

  • A grain will handle a maximum of 1,000 requests per second.
  • A silo will handle a maximum of 10,000 requests per second.
  • A silo will hold 100,000 active grains.

NOTE: Old results - https://github.com/OrleansContrib/DesignPatterns

Project Orleans

Demo

Development with

References

  • https://dotnet.github.io/orleans/Documentation/Introduction.html
  • https://github.com/dotnet/orleans
  • https://gitter.im/dotnet/orleans
  • http://www.gokhan-gokalp.com/en/orleans-ile-loosely-coupled-ve-scalable-restful-service-olusturma/
  • https://github.com/GokGokalp/orleans-product-api-sample

Contacts

Made with Slides.com