32
Streaming in CAF Dominik Charousset October 2018 C++ User Group Hamburg

Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

  • Upload
    others

  • View
    5

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Streaming in CAF

Dominik Charousset

October 2018C++ User Group Hamburg

Page 2: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Why care about alternative programming

paradigms?

Page 3: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Multi-cores are Here to Stay• The number of CPU cores will only increase

• Concurrency cannot be an afterthought

• Software needs to adapt to available hardware

• Programming concurrent systems should be easy

• Low-level abstractions error-prone and slow

• Common idioms break in concurrent settings

Page 4: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Beyond Concurrency• Microservices challenge monolithic software design

• Modular and distributed by design

• Orchestration of loosely coupled services

• Cloud deployments demand flexibility

• Re-deployment and automated vertical scaling

• Partial failures of the system common

Page 5: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

What we Need• No race conditions by design (without locks!)

• Concurrency & distribution at high abstraction level

• Compose large systems from small components

• Scale without code changes from IoT up to HPC

Microcontrollers Servers Supercomputers

Why we need Actors

Page 6: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

What is the actor model?

Page 7: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Actor Model in a Nutshell

• Distributed by design, perfect fit for microservices

• Asynchronous message passing

• Shared nothing architecture

• Hierarchical error handling

• Divide & conquer work flows

actorA

actorB

actorC

FIFO mailbox

Page 8: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

The World is a Stage

• "Actor model" refers to a theater metaphor

• Each individual acts according to a script

• Actors are agents with intents and behaviors

• An application is a choreography of many

Page 9: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Programming Actors• Actors operate event-based (message → event)

• In response to messages, actors can:

• Send messages

• Spawn more actors

• Change their behavior (set of message handlers)

Page 10: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Anatomy of an ActorActor

Address to an actor(allows enqueueing of messages)

Actor

Address to an actor(allows enqueueing of messages)

Processing(Control Loop)

Dequeue Message

Invoke Behavior

done?

yes

no

Actor

Address to an actor(allows enqueueing of messages)

Processing(Control Loop)

Dequeue Message

Invoke Behavior

done?

yes

no

Storage (State)

int count;string foo;...

Internal Variables

[=](int x) { count += x;}...

Message Handlers (Behavior)

Actor

Address to an actor(allows enqueueing of messages)

Processing(Control Loop)

Dequeue Message

Invoke Behavior

done?

yes

no

Storage (State)

int count;string foo;...

Internal Variables

[=](int x) { count += x;}...

Message Handlers (Behavior)

Communications (via FIFO mailbox)

Page 11: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Control Flow of Actors

case 1

input: M pattern 1 matched M

case 2pattern 2 matched M

else

receive next

message

case Npattern N matched M

else

else

Page 12: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Error Handling

• Errors have no side effects between actors

• Explicit handling of remote errors via messages

• Monitoring: unidirectional observing of actors

• Linking: strong lifetime coupling of actors

Page 13: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Linking Actorsalice

exit message(non-normal exit reason)

link

bob

quit()

Page 14: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

How can I program with actors in C++?

Page 15: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

C++ Actor Framework• Lightweight & fast actor model implementation

• In active development since 2011

• Provides building blocks for infrastructure software

• ~80,000 lines of code (https://www.openhub.net/p/actor-framework)

• International users from MMO gaming to finance

Page 16: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Architecture

ActorMessageActor

NodeNodeProcess

MessageActor

NodeNodeProcess

GPU

GPGPUMessageActor

NodeNodeProcess

GPU

GPGPU

Actor SystemActor System

Distribution Layer

MessageActor

NodeNodeProcess

GPU

GPGPU

Actor SystemActor System

Distribution Layer Socket API Thread API

Network Middleman

Cooperative Scheduler

OpenCL

GPGPU Wrapper

NetworkCPU

MessageActor

Page 17: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

void caf_main(actor_system& system) { // create a 'mirror' auto mirror_actor = system.spawn(mirror); // create a 'hello_world' actor system.spawn(hello_world, mirror_actor); // system will wait until both actors are destroyed }

CAF_MAIN()

Starts a new actor

Our First ExampleReplaces the

traditional main()Hosts all of our actors

Page 18: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Mirror, mirror, on the Wallbehavior mirror(event_based_actor* self) { // return the (initial) actor behavior return { // a handler for messages containing a single string // that replies with a string [=](const string& what) -> string { // prints "Hello World!" via aout aout(self) << what << endl; // reply "!dlroW olleH" return string(what.rbegin(), what.rend()); } }; }

Page 19: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Hello World!void hello_world(event_based_actor* self, actor buddy) { // send "Hello World!" to our buddy ... self->request(buddy, std::chrono::seconds(10), "Hello World!") .then( // ... wait up to 10s for a response ... [=](const string& what) { // ... and print it aout(self) << what << endl; } ); }

Page 20: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Ok, but what about streams?

Page 21: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Streams

• Conceptually: potentially infinite lists

• Usually never fully present in memory at any time

• Allow chunked processing of huge data volumes

• Enable realtime event handling (e.g. Twitter feeds)

Page 22: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Just Send Messages!?• Actors have unbounded mailboxes

• No feedback to sender regarding mailbox load

• Fast senders eventually overwhelm receivers

• Overhead per message too high for little data

• Wrapping each item of a stream wastes memory

• Batch processing much faster than one-by-one

Page 23: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Streams in CAF

• Stream topologies can span any number of actors

• Demand signaling slows down senders if needed

• Load-balancing and broadcasting* via stages

• Stream priorities* allow fine-grained flow control

* only partially implemented as of CAF 0.16

Page 24: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Streaming Concept

source stage sink

data flows downstream

demand flows upstream

errors are propagated both ways

Page 25: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Per-Stream State

output buffer

input buffer

driver downstream manager

error handler

not in sinksnot in sources

user-provided

Page 26: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Implementing a Sourcebehavior int_source(event_based_actor* self) { // Makes ints [0, n) return { [=](open_atom, int n) { return self->make_source( [](int& x) { // Initializer x = 0; }, [n](int& x, downstream<int>& out, size_t hint) { // Generator auto max_x = std::min(x + static_cast<int>(hint), n); for (; x < max_x; ++x) out.push(x); }, [n](const int& x) { // End predicate return x == n; }); } }; }

{Drive

r im

plem

enta

tion

Page 27: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Implementing a Stagebehavior int_selector(event_based_actor* self) { // Drops odd numbers return { [=](stream<int> in) { return self->make_stage( in, // Our input source [](unit_t&) { // Initializer (uses unit_t for "no state") // nop }, [](unit_t&, downstream<int>& out, int val) { // Processor if (val % 2 == 0) out.push(val); }, [=](unit_t&, const error& err) { // Finalizer // Check for error ... }); } }; }

Page 28: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Implementing a Sinkbehavior int_sink(event_based_actor* self) { return { [=](stream<int> in) { return self->make_sink( in, // Our input source [](std::vector<int>&) { // Initializer // nop }, [](std::vector<int>& xs, int val) { // Consumer xs.emplace_back(val); }, [=](std::vector<int>& xs, const error& err) { // Finalizer // Check for error, do something with xs ... }); } }; }

Page 29: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Putting it Together

void caf_main(actor_system& sys, const config& cfg) { auto src = sys.spawn(int_source); auto stg = sys.spawn(int_selector); auto snk = sys.spawn(int_sink); auto pipeline = snk * stg * src; anon_send(pipeline, open_atom::value, cfg.n); }

Page 30: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

How fast is it, tho?

Page 31: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Demo Time

Page 32: Streaming in CAF - Dominik Charoussetdominik.charousset.de/2018-10 User Group Hamburg.pdfBeyond Concurrency • Microservices challenge monolithic software design • Modular and distributed

Thanks for Listening!

actor-framework actor_framework