Phoenix as a Meteor alternative

Totes! I hope they do steal a few things… Elixir has some awesome features. Well, functional programming languages in general have awesome features (e.g. pattern-matching, pipes, etc…)

I love JavaScript, but man, I miss Elixir when I work with it haha. It’s kinda nice to switch back and forth when I build with React and Phoenix.

This is an interesting benchmark, have you seen this? Phoenix Showdown Comparative Benchmarks @ Rackspace · GitHub

I was pretty surprised by the performance of Elixir. Because you can spin up millions of processes to do work all at the same time you can get stuff done very quickly. It’s actually kinda shocking… Super fast.

But, this says it all:

Spot on.

2 Likes

It’s better than BASIC. At least we have classes now. Still no strong typing though.

I have to admit I find this new dynamic of transpilers quite fascinating. I thought .net was nifty when you could do something similar with outputting a C# app from a VB app or vice-versa, but this is another level altogether.

The Erlang VM uses a separate heap per process. A process in Erlang takes just 309 words to spin up, including 233 words for the stack which auto-grows and shrinks. That means you can spin up millions of them at will.

It a fully preemptive scheduler. No stop the world GC pauses and no synch process killing the rest of the system. It values low latency over throughput. @SkinnyGeek1010 posted about this earlier with his own benchmarks. 14ms response times, and only 16ms under heavy load.

If you have knowledge of how computers actually work there is no way you are not amazed at Erlang. Node, or even GO/Scala just cannot compete.

Get back to us when meteor’s (O)n^2 feature says hello. Meteor is the only framework where you hope and pray your application doesn’t become too popular. And by popular, we’re talking a few hundred users.

1 Like

btw dont trust any benchmarks you see, try them out for yourself and modify them to reflect what you are trying to build.

Just some useless info: I have performed the same with latest everything and you can see my results below. This doesnt say much, my env can be different or something else can be wrong. Point is try it out yourself :smile:

Note that the phoenix they used was very old so I created it from scratch, there might have been some performance tweaks I missed. Both ran in prod env.

[2015/12/02, 2:30:46 PM] Riaan Jacobs: phoenix:
[2015/12/02, 2:30:48 PM] Riaan Jacobs: riaans-MacBook-Pro-3:wrk riaan$ ./wrk -t4 -c100 -d30S --timeout 2000 "http://127.0.0.1:4000/showdown"
Running 30s test @ http://127.0.0.1:4000/showdown
4 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 9.09ms 0.91ms 18.38ms 73.06%
Req/Sec 2.76k 102.10 3.01k 76.25%
329775 requests in 30.01s, 729.06MB read
Requests/sec: 10988.04
Transfer/sec: 24.29MB

[2015/12/02, 2:30:54 PM] Riaan Jacobs: and express cluster:
[2015/12/02, 2:31:03 PM] Riaan Jacobs: iaans-MacBook-Pro-3:wrk riaan$ ./wrk -t4 -c100 -d30S --timeout 2000 "http://127.0.0.1:3000/showdown"
Running 30s test @ http://127.0.0.1:3000/showdown
4 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 4.72ms 3.60ms 167.29ms 95.64%
Req/Sec 5.57k 559.22 8.04k 86.20%
666977 requests in 30.10s, 1.36GB read
Requests/sec: 22156.41
Transfer/sec: 46.34MB

btw I really like phoenix and node/meteor. I look at my projects requirements and then pick the correct tool for the job.

Haha, same here. After writing Elixir, I’ve been using de-structuring heavily in my JS now, as well as making modules with just functions (no classes!). Using underscore’s chain method to pipe data through functions

var res = _.chain('555 121-7878')
  .callFn(stripChars, '.')
  .callFn(stripChars, ' ')
  .callFn(stripChars, '-').value();

console.log(res);
// ->  "5551217878"

Yea this is important. However, if you’re already using React/Redux in Meteor then the jump is not as far because you’re still using the same frontend. Instead of Meteor.call you use AJAX, and instead of subscribe you use the JS channels API.

The language can be learned in an intense weekend if you have Dave’s book and the learning elixir website. Phoenix is another day or two to make something to the point that it ‘clicks’.

That’s my experience and it was my first functional language (I find Elixir to pragmatic compared to Haskell/Listp/etc…)

It really depends on what you’re benchmarking… if it’s just a json api then you’re right, prob. not much of a difference comparing a node cluster to an Erlang machine. However… once you start benchmarking long lived stateful apps (websockets), Erlang/Elixir will rule the roost… mostly because the language itself was designed just to do this (telephone conversations are long lived connections).

2 Likes

@jacobin Perhaps I wasn’t clear. I wasn’t asking why it might be a better framework, but what makes it an ‘alternative’ in any real sense. I’d see something like sails.js as an alternative to meteor, for example. Phoenix is something different entirely.

i.e. If you had a trained team of javascript developers, you couldn’t easily migrate your meteor app to phoenix. It’s not something to consider unless you’re (likely) a sole developer and (likely) wanting to learn something new and quite different.

I guess this is pertinent. If ‘all’ your framework is doing is serving an API I guess the jump is a lot smaller.

Also if you’re the kind of developer that can pick up new languages easily it’s likely less of a big deal. I’m not a dedicated developer (although things seem to be shifting that way) and I still struggle with async coming from a PHP background, looking at Elixir code gives me the shivers!

Edit: tldr; Even if I went back to the day I discovered Meteor, I couldn’t imagine myself weighing up Phoenix vs Meteor - I think the target audiences are likely quite different.

(I’m sure it’s all awesome though, I really couldn’t say otherwise!)

1 Like

Purely out of interest, what kinds of jobs would you assign to each? (and when you say node/meteor, do you also mean you might use Phoenix over, say, Express for certain areas but not others?)

I think that’s true for certain benchmarks. In addition, I’m not to the level at which I’d feel confident conducting a benchmark as I’m neither a devops person nor a master of the intricate details of each framework. There are just too many nitty-gritty optimizations that I haven’t yet learned.

Did you just run the benchmark on your local machine?

I would imagine most Elixir code would be close to PHP and it’s sync by default :smiley: The Elixir docs do not really do it justice as a first glance (I passed it by the first time because of this)

Pattern matching can be confusing and this is a simple example. The first func in the module that matches will run (instead of an if/else in one function). Notice all of them have the same function name.

defmodule Greeter do
  # pattern matching determines what function runs, if the shape matches than it will run instead
  def say_hi([name]) do
    IO.puts "Hello, #{name} !"
  end

  def say_hi([name1, name2]) do
    IO.puts "Hello, #{name1} and #{name2} !"
  end

  def say_hi(_anythingelse) do
    IO.puts "Uh, oh you need to pass one or two names in an array"
  end
end

Greeter.say_hi(["Adam"])

Elixir makes you think of data transformation like Unix pipes sending input from one program to the next. The weird |> operator just means to send the output into the input of the next function. This allows you to compose a function from smaller functions like this:

defmodule NumberUtils do
  def normalize(number) do
    number
    |> strip_char '.'
    |> strip_char ~r/^+1/
    |> strip_char ' '
    |> strip_char '_'
  end

  # returns last line
  pdef strip_char(str, char) do
    String.replace(str, char)
  end
end

NumberUtils.normalize('+1 555 333-8888')


edited forgot to add number to pipeline

3 Likes

I know that https://dockyard.com/ did just that recently. I was actually very surprised at how quickly I was able to pick up Elixir/Phoenix. Now, by no means am I anywhere near expert level, but I certainly can get things done! That said, you definitely need to put in some time to learn everything and not everybody has a bunch of free time. This is especially true if you are swamped with work and have to pay the bills!! :grimacing:

1 Like

True that. Add my age to the equation and things start to become clear why learning basically anything is a ball ache! :smiley:

Edit: Although I have no excuse, there are older, busier people than me that are always learning, I probably just like things to come easy. Did you just call me lazy!?

Yip ran them on localhost just as the original one. But dont read to much into it please. Was just trying to illustrate a point :smile:

1 Like

Yea I really don’t pay too much attention to benchmarks. They’re usually ballpark best case. I stress tested my own Phoenix API and got around 800-1000 requests per second on a small digital ocean box. I wasn’t able to benchmark the websockets because of cost but we’ll see in time. At any rate it’s good enough :smile:

The best I could squeeze out of my Meteor app on modulus was ~300 concurrent users before becoming too slow (because of websockets… not comparing to above stats).

As an Elixir noob, can you explain the difference in piping? In node, Streams can be piped really easily (and just about everything critical is a stream). Are you just talking about the easier piping syntax or is there something under the hood that I’m missing?

Yup, I consider that benchmark to be worthless when you look at what it actually does (and how outdated node & phoenix are). I think the webdev community needs a universally accepted benchmark or 2 for websockets, just like we have for browsers. Something like:

  • add a user every second (round robin, 4 CPUs)
  • Randomly assign the user to 1 of 4 channels
  • disconnect a user every 3 seconds
  • pingpong every 20 seconds
  • Publish a 200B message every 2 seconds to all subscribers in the channel
  • repeat until the server dies, last server living wins!

If someone has some spare time, comparing socket cluster http://socketcluster.io/ to phoenix would be a really worthwhile endeavor for a weekend project, I’d star the hell out of that github project :wink:

I’ve got some reading to do on Erlang it looks like, that’s really interesting stuff. Regarding GC, if you are having stop the world GC then you’re doing something really wrong (huge object, maintaing a global reference, letting objects grow too old, etc). Thankfully V8 profiling is pretty amazing at catching stuff like this, although mucking around in assembly isn’t as enjoyable as it sounds. :confounded:.

Writing an Elixir app is not imperative at all. It’s a series of data transformations, identical to how you do things in csh with pipes. Something like…

ps -aux | grep “foo” | awk '{if($6 > 90)print $0} > perfout.txt

V8’s garbage collection is a stop the world gc. However the biggest problem with V8 is that it’s garbage collector is impossible to tune so high frequencies of short lived object will kill you. In other VM’s like Java, tuning the GC is a black art.

The only answer is to pool everything and bypass the GC. That eats ram.

Noop. haha. Figured I’d respond just in case I was wrong in assuming you were joking.

1 Like

Typescript to the rescue !
Dynamic when you want it, strongly typed when you want it, and even everything in between !

Piping in Elixir is different than Node piping. It’s the equivalent to underscore chaining. Like in my example above the |> means to pipe it into the next function: number |> strip_char( '.') just like a unix pipe.

This means that this terse code (in JS or Elixir):

strip_char(strip_char(strip_char(strip_char(number, '.'), /^+1/), ' '), '_')

is the same as:

    number
    |> strip_char '.'
    |> strip_char ~r/^+1/
    |> strip_char ' '
    |> strip_char '_'

The first param is always the thing getting piped (number in this case). See a few post above for how this works in a module.

I was just doing my crazy old guy routine :laughing:

@SkinnyGeek1010 I’m currently halfway through the online intro to Elixir, it’s actually a lot more familiar than I’d realised, I don’t use coffeescript or ruby so the lack of parenthesis threw me off a bit!

4 Likes

Also for people just getting started or who are curious, this set of videos for $8 is really really easy to follow.
https://www.learnelixir.tv

5 Likes

Since this thread has long since since ceased to be a Phoenix / Meteor comparison (the “what Meteor can learn from Phoenix” discussion was particularly constructive), and is now primarily just Phoenix / Elixir chat - would it be unreasonable to suggest that those interested in continuing the discussion congregate in their respective forums?

https://groups.google.com/forum/#!forum/phoenix-talk
https://elixir-lang.slack.com/