&

@holsee

Elixir - what makes it different

  • Erlang VM
  • Symbolic Code as Data
  • Processes
  • Applications
  • Distribution
  • Resiliency
  • What this enables?
  • What this disables?

Elixir + Rust = ♡

  • What makes Rust different?
  • What is a NIF
  • Why Rust is well suited
  • Writing NIFs in Rust.

Elixir

what makes it different?

The Erlang VM

  • An extremely powerful platform


  • Designed for Salability, Distribution and Resiliency


  • ~21 years Open Source 🤘


  • Soft Real-time Scheduling

Symbolic Code as Data

  • Code is structure into Modules and Functions which are looked up dynamically at Runtime.

 

  • The Code is Functional & Dynamic and is treated as Data by the VM

 

  • When you run your application, you are literally loading your code into the Erlang VM. i.e. the Greeter Module will be available within the VM to be called.

 

  • Data is Immutable
defmodule Greeter do
  @moduledoc """
  Module with some timeless greetings!
  """

  @typedoc "A name to greet"
  @type name :: String.t()
  
  @typedoc "A greeting to a `name`"
  @type greeting :: String.t()

  @doc """
  Good old "Hiya!"

  ## Examples

      iex> Greeter.hiya("holsee")
      "Hiya holsee!"

  """
  @spec hiya(name) :: greeting
  def hiya(name) do
    "Hiya #{name}!"
  end
end

# Minimalist version of the above:
defmodule Greeter, do:
  def hiya(name), do: "Hiya #{name}!"

Processes

  • Not OS Processes

 

  • No Shared Memory between Processes

 

  • Per Process Garbage Collection

 

  • Process execution Concurrency which scales with the Hardware

Process

Process

Process

Erlang VM Schedulers

CPU Cores

Instrumentation: Schedulers View

# Concurrently compute sqrt or range 1 to 1 million (max concurrency = number of CPU Cores)
import Task
start(fn -> 1..1_000_000 |> async_stream(fn n -> :math.sqrt(n) end) |> Stream.run() end)

Message Passing

https://github.com/koudelka/visualixir

Applications

  • Wraps up your Modules ready to be loaded into the VM (known as a "Release") which can include Patches.

 

  • Applications are structured as a Tree, with Supervisors and Workers.
     
  • Many Applications can run on the same VM ~ it is not uncommon that a dependency for your app is an "Application".

App
(Sales)

Sup
(Users)

Sup
(Carts)

Worker

Worker

Worker

App
(Warehouse)

Worker

Sup
(Stock)

What this enables?

Distribution

(application scalibility)

Distribution

Erlang VM is designed for distribution.  Processes by their nature encourage this kind of thinking.

Many Erlang VMs can be registered into a cluster.  Code can be sent and loaded between nodes in the cluster.

 

Processes communicate via message passing, allowing for cross-node communication with no code change!

Erlang PL MongooseIM
Cluster View
https://youtu.be/BIbLOVNKZYw

DEMO!

  1. Start 2 Erlang VMs
  2. Connect Nodes
  3.  Spawn a Process on Remote Node
  4. Send a Message to it
  5. Receive Response

 

$ iex --sname foo --cookie m0nst3r

Node.connect(:"bar@your-machine")

Node.list()

ping_pid = Node.spawn(:bar@your-machine, fn -> 
                    receive do 
                      {:ping, from} -> 
                        IO.puts("Ping received by: #{inspect(self())}")
                        send(from, :pong)
                     end 
                    end)

send(ping_pid, {:ping, self()})

flush()
$ iex --sname bar --cookie m0nst3r

Some Interesting Projects to get Started with using
Distributed Elixir in Production:


https://github.com/bitwalker/libcluster
Automatic cluster formation/healing for Elixir applications
via:

  • Standard Erlang Distribution (EPMD)
  • Kubernetes
  • Multicast UDP gossip
  • Rancher metadata

 

https://github.com/bitwalker/swarm
Clustering, registration, and distribution of worker processes for Erlang/Elixir

Resiliency

(fault-tolerance)

Reliability & Maintainability

    The AXD301 has achieved a NINE nines reliability (yes, you read that right, 99.9999999%).

 

Let’s put this in context: 5 nines is reckoned to be good (5.2 minutes of downtime/year). 7 nines almost unachievable ... but we did 9.


    Why is this? No shared state, plus a sophisticated error recovery model.

source: Joe Armstrong @ Programming Erlang (progprog 2013)

Bonus: https://youtu.be/rQIE22e0cW8
Joe Armstrong - K things I know about building Resilient Reactive Systems @ React Conf run by Instil 2014

App
(Sales)

Sup
(Users)

Sup
(Carts)

Worker

Worker

Worker

App
(Warehouse)

Worker

Sup
(Stock)

Error Recovery

If any of the Workers crash

~ the Supervisor can restart them in the last know good state.

 

If the Supervisor Crashes

~ They can also be restarted including any children

 

If the Node Crashes

~ The app can  fail-over between Nodes in
the Cluster

Aggressively Code on the Happy Path.

 

 

Design your Processes into Fault-Tolerant Tree Structures whereby related Entities will Crash Together, but come back up in a good state to continue Processing!

 

This kind of "let it crash" based approach works, because Elixir / Erlang VM is designed to handle it and recover.

 

It highlights failure cases without taking your application down and allows for patching to handle new conditions without taking the application offline!

Orchestration

(Distribution + Supervision)

Interop with External Applications

  • Leverage the Distribution functionality of the Platform
  • Spawn & Monitor external applications
  • Failure Detection to Restart through Supervision

Test Scenario Client
web socket connections speaking
chrome remote debug protocol

node1@.

nodeN@.


ws:// client

|

|
|
Proxy built on :gen_tcp

|

|

Chrome's ws:// RDP Server

ChromeServer
Supervisor

ChromeServer

P
O
R
T

💥

💥

💥

What are the Trade-offs?

No Mutable Memory Access &
Sub-optimal Math

Slow @ Math? Not Really...

"When we say Elixir may not be suited to do number crunching, we are usually thinking a bit beyond analytics, averages, medians, etc.

 

Because it is not necessarily the mathematical processing that hurts but rather the lack of support for large mutable data structures that would allow us to do implement things like image processing or support vector machines efficiently."

 

Mutable Memory Access?

 There exist constructs within Elixir which allow for Shared Data Access, Atomic Operations and Similar Style of Data Structures as would be possible in other languages, but this is achieved through using ETS, a built in No-SQL K/V Store written in C.
 

Example ~ Erlang Patterns of Concurrency (epocxy)
See: https://github.com/duomark/epocxy

So you can build a Ring Buffer, but you can't build a disruptor!
See: https://lmax-exchange.github.io/disruptor/

Memory Layout / CPU Caching

1. Lack of real ARRAYS

2. The inability to control (or assume) Memory Layout

3. Process & Scheduler Design

For me, these are all major factors which impact the potential throughput of any data structure & algorithm pairing on the Erlang VM compared to traditional languages.

Memory Layout / CPU Caching

To learn more about writing "Mechanically Sympathetic" Code

FWIW This course is where I learned all this stuff...

Rust

what makes it different?

Blazingly Fast

"C++ FITE ME!"

🌝
💪💪            

<- @sigma

Memory Safety!

All that talk of Resiliency Guarantees of the Erlang VM...

Once you load and execute Natively Implement Functions (NIFs)

ALL BETS ARE OFF!
 

What is a NIF?

"A NIF is a function that is implemented in C instead of Erlang. NIFs appear as any other functions to the callers."

 

http://erlang.org/doc/tutorial/nif.html

Therefore...
Can we write Native Functions in Rust
 

and use them from Elixir

Taking           to the

"Rustler is a library for writing Erlang NIFs in safe Rust code. That means there should be no ways to crash the BEAM (Erlang VM). The library provides facilities for generating the boilerplate for interacting with the BEAM, handles encoding and decoding of Erlang terms, and catches rust panics before they unwind into C."

https://github.com/hansihe/rustler

Elixir + Rust

I used Rust for Computing and comparing SimHashes with the underlying computation delegated to RUST

&

Thanks for listening!

 

@holsee

Elixir + Rust <3

By Steven Holdsworth

Elixir + Rust <3

What makes Elixir different? & Why Rust is complimentary!

  • 354