ndc london 2014: thinking like an erlanger

67
Thinking Like An Erlanger Torben Hoffmann CTO @ Erlang Solutions [email protected] @LeHoff

Upload: torben-hoffmann

Post on 09-Jul-2015

1.126 views

Category:

Software


7 download

DESCRIPTION

How to design solutions in Erlang using lots of processes and dealing with errors. Use a monitoring process in addition to a standard supervisor to get a system back into a good state. Examples used: Conway's Game of Life and a stock exchange.

TRANSCRIPT

Page 1: NDC London 2014: Thinking Like an Erlanger

Thinking Like An Erlanger

Torben HoffmannCTO @ Erlang Solutions

[email protected]@LeHoff

Page 2: NDC London 2014: Thinking Like an Erlanger

Do You Want To See The Erlang Code?

Page 3: NDC London 2014: Thinking Like an Erlanger

You Can’t Handle The Erlang Code!!

Source: http://static7.businessinsider.com/image/4d9d0c7bcadcbbaf20120000/jack-a-few-good-men.jpg

Page 4: NDC London 2014: Thinking Like an Erlanger

Syntax Is Irrelevant

Page 5: NDC London 2014: Thinking Like an Erlanger

Thinking Is Everything

Page 6: NDC London 2014: Thinking Like an Erlanger

General vs Domain Specific

Telecom

Erlang

C++/Java

Smaller gap =

money!

Page 7: NDC London 2014: Thinking Like an Erlanger

Protocols

Page 8: NDC London 2014: Thinking Like an Erlanger

Paxos

{ Acceptors }Proposer Main Aux Learner| | | | | | -- Phase 2 --X----------->|->|->| | | Accept!(N,I,V)| | | ! | | --- FAIL! ---|<-----------X--X--------------->| Accepted(N,I,V)| | | | | -- Failure detected (only 2 accepted) --X----------->|->|------->| | Accept!(N,I,V) (re-transmit, include Aux)|<-----------X--X--------X------>| Accepted(N,I,V)| | | | | -- Reconfigure : Quorum = 2 --X----------->|->| | | Accept!(N,I+1,W) (Aux not participating)|<-----------X--X--------------->| Accepted(N,I+1,W)| | | | |

Source: https://en.wikipedia.org/wiki/Paxos_(computer_science)#Byzantine_Paxos

Page 9: NDC London 2014: Thinking Like an Erlanger

The Golden Trinity Of Erlang

Page 10: NDC London 2014: Thinking Like an Erlanger

Processes

They are dirt cheap!

Use lots of them! Lots!

Focus on their interactions

Page 11: NDC London 2014: Thinking Like an Erlanger

Game of Life

Simple cellular automaton

Evolution of cells

Discrete time

Page 12: NDC London 2014: Thinking Like an Erlanger

2,3 neighbours: survive

empty, 3 neighbours: new cell

all others: empty

Page 13: NDC London 2014: Thinking Like an Erlanger
Page 14: NDC London 2014: Thinking Like an Erlanger
Page 15: NDC London 2014: Thinking Like an Erlanger
Page 16: NDC London 2014: Thinking Like an Erlanger
Page 17: NDC London 2014: Thinking Like an Erlanger
Page 18: NDC London 2014: Thinking Like an Erlanger
Page 19: NDC London 2014: Thinking Like an Erlanger

Traditional Approach 2-d array - one per time step

Page 20: NDC London 2014: Thinking Like an Erlanger

Issues with Traditional Approach

Does not scale well

Imperative data structures are ugly in Erlang

Page 21: NDC London 2014: Thinking Like an Erlanger

Basic Erlang Idea

One process per cell

Talk to neighbour cells

Page 22: NDC London 2014: Thinking Like an Erlanger

Collect from all neighbours

Update own content and go to T+1

Page 23: NDC London 2014: Thinking Like an Erlanger

Is this Erlangy enough?

Page 24: NDC London 2014: Thinking Like an Erlanger

Spawn a process to collect from all neighbours

Page 25: NDC London 2014: Thinking Like an Erlanger

collector_loop([], NeighbourCount, Cell, Content) ->

Cell ! {self(), {next_content, next_content(Content, NeighbourCount)}};

collector_loop(WaitingOn, NeighbourCount, Cell, Content) ->

receive

{cell_content, {{{_,_},_}=XYatT, NeighbourContent}} ->

case lists:member(XYatT, WaitingOn) of

true ->

collector_loop(lists:delete(XYatT, WaitingOn),

NeighbourCount + NeighbourContent,

Cell, Content);

false -> %% ignore messages we are not waiting for

collector_loop(WaitingOn, NeighbourCount, Cell, Content)

end

end.

Page 26: NDC London 2014: Thinking Like an Erlanger

Will this work?

Page 27: NDC London 2014: Thinking Like an Erlanger

It works if…

you only take one step at a time

let the cells run freely…

cells get out of sync

requests for old time

requests for future time

Page 28: NDC London 2014: Thinking Like an Erlanger

Fixes

Old time requests:

keep history

Future time requests:

queue the response

Page 29: NDC London 2014: Thinking Like an Erlanger

What About Failures?

Page 30: NDC London 2014: Thinking Like an Erlanger

Supervising Cells

The Erlang supervisor will restart with the original args…

all state and history is lost

Fix:

monitor all cells

step them forward to current time

Page 31: NDC London 2014: Thinking Like an Erlanger
Page 32: NDC London 2014: Thinking Like an Erlanger
Page 33: NDC London 2014: Thinking Like an Erlanger

Cell Mgr Codeloop(#state{cells=Cells}=State) ->

receive

{'DOWN', Ref, process, _Pid, _Info} ->

{value, {_,_, XY}, Rest} = lists:keytake(Ref, 2, Cells),

NewPid = await_restart(XY),

NewRef = erlang:monitor(process, NewPid),

NextState = State#state{

cells=[{NewPid, NewRef, XY}|Rest]},

spawn ( fun () -> pacer(NewPid) end ),

loop(NextState)

end.

Process down

Page 34: NDC London 2014: Thinking Like an Erlanger

Cell Mgr Codeloop(#state{cells=Cells}=State) ->

receive

{'DOWN', Ref, process, _Pid, _Info} ->

{value, {_,_, XY}, Rest} = lists:keytake(Ref, 2, Cells),

NewPid = await_restart(XY),

NewRef = erlang:monitor(process, NewPid),

NextState = State#state{

cells=[{NewPid, NewRef, XY}|Rest]},

spawn ( fun () -> pacer(NewPid) end ),

loop(NextState)

end.

Wait for supervisorto restart it

Page 35: NDC London 2014: Thinking Like an Erlanger

Cell Mgr Codeloop(#state{cells=Cells}=State) ->

receive

{'DOWN', Ref, process, _Pid, _Info} ->

{value, {_,_, XY}, Rest} = lists:keytake(Ref, 2, Cells),

NewPid = await_restart(XY),

NewRef = erlang:monitor(process, NewPid),

NextState = State#state{

cells=[{NewPid, NewRef, XY}|Rest]},

spawn ( fun () -> pacer(NewPid) end ),

loop(NextState)

end.

Get the new processup-to-date

Page 36: NDC London 2014: Thinking Like an Erlanger

Deadlock Remaining…

N1 dies with Cell(i,j) queued

Page 37: NDC London 2014: Thinking Like an Erlanger

Re-cap

A process per cell

Short-lived processes for small tasks

Focus on the protocols between processes

Supervisor to restart

Monitoring manager process to get restarted cells up-to-speed

Page 38: NDC London 2014: Thinking Like an Erlanger

Stock Exchange

Page 39: NDC London 2014: Thinking Like an Erlanger

The Trigger…

Erlang-Questions on using ETS for sell and buy orders:

http://erlang.org/pipermail/erlang-questions/2014-February/077969.html

Painful…

Page 40: NDC London 2014: Thinking Like an Erlanger

An Exchange

Connects buyers and sellers

Buyers post buy intentions

Sellers post sell intentions

Page 41: NDC London 2014: Thinking Like an Erlanger

Basic Erlang Idea

One process per buy/sell intention

Processes to negotiate deals by exchanging messages

Page 42: NDC London 2014: Thinking Like an Erlanger

Communication

Use gproc as pub-sub mechanism to announce buy and sell intentions

All buyers listen to sell intention

All sellers listen to buy intentions

Page 43: NDC London 2014: Thinking Like an Erlanger

Can happen when

Negotiation by 3-way handshake

Deals

priceseller pricebuyer

Page 44: NDC London 2014: Thinking Like an Erlanger

Buyer Arrives

Page 45: NDC London 2014: Thinking Like an Erlanger
Page 46: NDC London 2014: Thinking Like an Erlanger

Unique reference to identify the sell offerSeller’s Pid

Page 47: NDC London 2014: Thinking Like an Erlanger
Page 48: NDC London 2014: Thinking Like an Erlanger
Page 49: NDC London 2014: Thinking Like an Erlanger

5 pt

Page 50: NDC London 2014: Thinking Like an Erlanger

Seller Arrives

Page 51: NDC London 2014: Thinking Like an Erlanger
Page 52: NDC London 2014: Thinking Like an Erlanger

What About Failures?

Page 53: NDC London 2014: Thinking Like an Erlanger

What Can Go Wrong?

1. Buyer dies

3. Buyer dies

2. Seller dies

1 & 2 can be fixed by timing out

Danger!! Seller has closed the deal on his side

Simple re-start leaves the buyer at 3@5

Page 54: NDC London 2014: Thinking Like an Erlanger

Monitor each other

Removes the need for timeouts

Still not sure how far the other side got

Page 55: NDC London 2014: Thinking Like an Erlanger

Transaction Log Per Process

Just replay back to the last state

Issues:

Messages cannot be replayed

Must ask partner about their view on the status of the deal

Page 56: NDC London 2014: Thinking Like an Erlanger

Ledger

Create Ledger process that tracks all completed deals

Each buyer and seller get a unique OfferID when started

Page 57: NDC London 2014: Thinking Like an Erlanger
Page 58: NDC London 2014: Thinking Like an Erlanger

Thinking in Erlang

Focus on protocols (MSCs)

Ask “What could go wrong here?”

Page 59: NDC London 2014: Thinking Like an Erlanger

Tools Lots of processes!!

Spawn short-lived processes for small things

Supervisors

Link and monitor

gproc for registering and pub/sub

Timeouts

Transaction logs (ledgers)

Page 60: NDC London 2014: Thinking Like an Erlanger

Food for Thought

What can I only do in Erlang?

http://erlang.org/pipermail/erlang-questions/2014-November/081570.html

You can avoid writing your own service framework.

Craig Everett

Page 61: NDC London 2014: Thinking Like an Erlanger

Testing

Async protocols are nasty

Use EQC - Property Based Testing

Focus on one process

Mock the calls to others

WIP in repo!

Page 62: NDC London 2014: Thinking Like an Erlanger

Code

Game of life

https://github.com/lehoff/egol

Erlang Exchange

https://github.com/lehoff/erlang_exchange

Deadlock left to fix

Testing incomplete

No ledger

Page 63: NDC London 2014: Thinking Like an Erlanger

Learning Erlang

Page 64: NDC London 2014: Thinking Like an Erlanger

Source: http://www.despair.com/mistakes.html

Page 65: NDC London 2014: Thinking Like an Erlanger

Learning Erlang

ESL training courses

Learn You Some Erlang

http://learnyousomeerlang.com/

Use the erlang-questions mailing list

Do it hands-on

Give it time to sink in!!!

Page 66: NDC London 2014: Thinking Like an Erlanger

Elixir

Built on top of the Erlang VM

More Ruby-like syntax

Hygienic macros - easy to do DSLs

Better support for data handling

But… you still have to learn the Erlang programming model

Page 67: NDC London 2014: Thinking Like an Erlanger

Key building blocks

Share nothing processes

Message passing

Fail fast approach

Link/monitor concept

You can deal with failures in a sensible manner because you have a language for them.