BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News EventMachine: Fast and Scalable Event-Driven I/O Framework

EventMachine: Fast and Scalable Event-Driven I/O Framework

This item in japanese

EventMachine is a framework for network and concurrent programming, based on the Reactor design pattern. The Reactor pattern describes a service handler that receives events and dispatches them to registered event handlers. The benefits of the reactor pattern are a clear separation between the event dispatching and the application logic that handles the events, without complicating the code with multithreading.

EventMachine provides a high-level interface to network sockets and tries to hide the lower level operations. EventMachine's goals are:

  • Extremely high scalability, performance and stability for the most demanding production environments; and
  • An API that eliminates the complexities of high-performance threaded network programming, allowing engineers to concentrate on their application logic.

Let's take a look at a small example; a simple chat server:

 require 'eventmachine'

module Chat
 
# Called after the connection with a client has been established
  def post_init
# Add ourselves to the list of clients
  (@@connections ||= []) << self
send_data "Please enter your name: "
  end

  # Called on new incoming data from the client
  def receive_data data
  # The first message from the user is its name
  @name ||= data.strip
 
@@connections.each do |client|
  # Send the message from the client to all other clients
  client.send_data "#{@name} says: #{data}"
  end
  end
 end

# Start a server on localhost, using port 8081 and hosting our Chat application
EventMachine::run do
 EventMachine::start_server "localhost", 8081, Chat
end

We talked to Francis Cianfrocca, the main developer of EventMachine (EM). We asked him about his motivations to develop EventMachine:

I originally started the project because I wanted to write a high-performance message-oriented middleware that could be programmed easily in scripting languages, including Ruby. At this point, there have been a great many projects written in EM, but the middleware project still hasn't been done! I was looking for a way to create an access-policy enforcement solution that would be extremely scalable, for global enterprises. And I wanted a communications framework that would be extremely fast but also have proper security built into it.

EventMachine is used by Thin (A fast and very simple Ruby web server), Swiftiply (a clustering proxy server for web applications), Evented Mongrel (Mongrel that has its network traffic handled by EventMachine), Sparrow (lightweight queue [..] that speaks memcache) and Juggernaut (plugin for Ruby on Rails [that lets]  the server initiate a connection and push data to the client). Francis also wrote his own web framework:

Mine is called Unicycle, and it's intended for RESTful applications that must contact other applications in order to fulfill Web requests. That also is based on EM, using EM's built-in HTTP server.

Version 0.12 of EventMachine has recently been released:

There are some performance enhancements and minor features on 0.12, but the primary motivation was to release a binary gem for Windows that had all the features we've added since 0.8.

The core of the EventMachine, the Reactor, has originally been implemented in C++ and has bindings for other languages besides Ruby. There's also a pure Ruby implementation, and one of the next versions will see the release of a Java implementation to be used with JRuby:

The most important new feature to be released soon will be full support for JRuby. This required a complete re-implementation of the reactor core in Java, which actually went quite well. Charles Nutter and his team have done a tremendous job on JRuby, and I think it has a lot of potential. I'm also very intrigued by Rubinius. The interesting thing about Rubinius is its support for fibers, which enables a more natural programming style for EM. I've already experimented with it in Ruby 1.9, but I'm hesitant to fork the API until more people are using the newer platforms. One of the key design goals for EM always has been maximum compatibility.

We asked Francis to elaborate on the advantages of EventMachine:

The key technical reason to use EM is because it enables a programming model that avoids threads. Threaded programming is of course a very well-known model, especially for network servers, but it has some very deep problems. There is a relatively small class of problems which are a good match for the threaded model. Network servers happen to be one of them, because it's usually possible to construct a non-overlapping working set for each request. But of course it's very difficult to get a threaded program 100% correct if it has any shared state between threads, or if it relies on operations to be properly sequenced across threads. And in Ruby, there's the additional problem that threading is very expensive.

The other reason to use EM is that we support a wide range of network protocols out of the box. The goal is to provide programmers with a large set of mature, high-performance tools that are easy to drop into their applications. This is what makes EM different from the many projects that are simply trying to implement the reactor model.

We also spoke of event driven programming, and why it is easier to work with, compared to a threaded model:

A lot has been written about the fact that event-driven programs are not theoretically any faster than threaded ones, and that is true. But in practice, I think the event-driven model is easier to work with, if you want to get to extremely high scalability and performance while still ensuring maximum robustness. I write programs that have to run for months or years without crashing, leaking memory, or exhibiting any kind of lumpy performance, so in practice, event-driven programming works better. Now, here's the problem with event-driven programming: you have to write "backwards." A threaded model stores your program state (inefficiently) in local variables on a runtime stack. In EM you have to do that yourself, which is very unintuitive to programmers who are used to threads. This is why I'm interested in fibers, because it opens the possibility of writing what looks to the programmer like blocking I/O, but still is evented and uses no threads.

Let's take a closer look at this, using an HTTP server as an example:

Think of an HTTP server. With threads, you simply read the socket and block until all the data has been retrieved from the remote peer. With events, you get the data as soon as it appears, with no waiting and no scheduling overhead—But it may not be complete! Your program has to detect that it hasn't yet received enough data to interpret the request, and it needs to store the partial data. But the next event that your program handles will possibly contain data for a different connection, so you have to keep all of this straight. The threading abstraction is a very heavyweight way of keeping those working sets separate, so it makes the programming task arguably more intuitive. But the evented model is not really so hard to learn. Nevertheless, I think this is the biggest barrier to wider use of event-driven programming.

Luckily, this is where EventMachine comes into play:

Now one of the things that EM does is to wrap up the standard protocols so that all of this is largely hidden from the programmer. Unlike low-level libraries like libev, which provide only a reactor core, EM seeks to provide robust implementations for all the standard network protocols, for example, email. EM includes a well-written handler for both the client and server side of SMTP. So an EM programmer only has to write code to handle events associated with complete email messages. There's no need to touch the underlying protocol. But still you have all the other benefits of the evented model (high speed, high scalability).

You can find more about EventMachine on the official Rubyforge website and on rubyeventmachine.com:

We recently opened up the community site rubyeventmachine.com which is a Trac implementation done by Jason Roelofs. And there is also an EventMachine IRC channel. Plenty of people, including Kirk Haines, James Tucker (raggi) and Aman Gupta (tmm1) have contributed a lot to EM. Also the people who do thin, Marc-André Cournoyer, have contributed a lot of ideas.

 

Rate this Article

Adoption
Style

BT