• Follow us

Action Cable vs AnyCable: fight!

Maurizio de santis

Maurizio De Santis

on 27 Feb 2019 in #Code

5 minutes Read
Action Cable vs AnyCable: fight!

Introduction

I’m a long time Ruby on Rails developer. When Action Cable was released, the first thing that came to mind was: “will it perf?”, given that Ruby has never been recognized for its ability with concurrency management, nor Rails for its lightness.

Browsing around, I stumbled upon AnyCable, an alternative to Action Cable created for some reason. What if that reason is performance? Let’s find out!

How Action Cable works

Action Cable runs in an application server instance separate from the one that handles the standard HTTP requests. It uses the hijack API, a Rack API added specifically for sessions requiring evented IO, like Server-Sent Events and WebSockets, giving to the application the whole control of the socket. Within Action Cable, the WebSocket management is fully implemented in Ruby.

How AnyCable works

Like for Action Cable, AnyCable receives and sends messages using Ruby, but the socket management is forwarded via gRPC to a server compatible with AnyCable specifications, which can be written in any language. Currently, the official implementations are AnyCable-Go, written in Go, and ErlyCable, written in Erlang. For details about AnyCable architecture, I recommend reading the related posts listed in the AnyCable README.

Setup

If you’re trying to run the test by yourself you should read the Caveats section first

We are going to load test Action Cable and AnyCable with Tsung (credits to this excellent post which showed me the right way). Below the testing environment details:

  • CPU: Intel i7-2600K

  • OS: Ubuntu 18.04.1

  • Ruby: 2.5.3

  • Rails (along with Action Cable): 5.2.2

  • AnyCable: 0.6.0

  • AnyCable-Go: 0.6.0

  • Load testing: Tsung 1.7.0

I wrote two Procfile configurations respectively for Action Cable and AnyCable in order to run them using Foreman:

# Action Cable
foreman start -e .env.production,.env.actioncable -f Procfile.actioncable
# AnyCable
foreman start -e .env.production,.env.anycable -f Procfile.anycable

Once the server is up and running, we can start Tsung:

tsung -f tsung.xml -k start

Tsung is configured to open 500 WebSocket connections per second (and keep them open) until it gets 60000 connections. 60000 is around the limit that can be reached on a single machine since each connection needs a port to go through. Tsung writes its results in the ~/.tsung directory and serves them live at http://localhost:8091.

Caveats

Performing the test is a bit tricky; there are some workarounds and tweaks we have to take:

tsung_stats.pl not found error

Tsung runs correctly, but it fails to generate the report showing an error like the following:

Fail to generated reports: tsung_stats.pl was not found in the $PATH

It happens because Tsung can’t find its binaries. Add them to $PATH:

export PATH=/usr/lib/x86_64-linux-gnu/tsung/bin:$PATH

Overcome OS caps

As suggested here, we need to increase OS limits related to open files and port ranges. Add the following to /etc/sysctl.conf:

net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 1024 65000
fs.file-max = 2097152

And add the following to /etc/security/limits.conf:

*    soft nofile 1048576
*    hard nofile 1048576

Reboot or reload the configuration and everything should be fine.

Image paths are broken

Visiting http://localhost:8091/es/ts_web:graph we can’t see any report image, basically because image paths are broken. Run the following code in your browser console:

const prependSlash = (_i, attr) => (attr.charAt(0) !== '/') ? `/${attr}` : undefined
$('.graph').attr('src', prependSlash).closest('a').attr('href', prependSlash)

Benchmarks

Enough talking! Let’s look at the results:

Action Cable

Action Cable maximum simultaneous users

Action Cable performs fairly well for the first 20000 users, then it starts suffering and honorably tries to overtake this limit. Not without issues, as we can see from the errors rate report:

Action Cable errors rate

AnyCable

AnyCable maximum simultaneous users

AnyCable doesn’t miss a beat, facing up to all the 60000 connections we throw at it. Moreover, the errors rate is… inexistent! Tsung refused to generate it.

Conclusion

Action Cable is rather capped regarding the connections amount that it can handle, though it can be enough for use cases with a restricted amount of users. If instead your application has stronger requirements, AnyCable is a perfectly viable option.

Still not sure which solution suits your needs best?

Let's talk
Related posts
#Code | 2 Apr 2017

AB(C) testing with Ruby on Rails

I’d have never expected A/B testing would be so easy with Ruby on Rails. At the very beginning I didn’t even have an idea on what A/B tests...

Join the Conversation