• No results found

V. node-openflow: High-Performance OpenFlow Protocol Library

5.3 Runtime System: Node.js

The library is built on the Node.js runtime system. This system was chosen for its cross-platform design, relative high performance, and ease of use, all of which align well to the stated goals for this library. Node.js is a cross-platform runtime

system built on Google’s V8 engine and the libuv asynchronous I/O library. Node.js is implemented with a combination of C++ and JavaScript [51].

5.3.1 V8.

V8 is an engine to run JavaScript developed by Google primarily for use in the Chrome web browser. It features a Just-In-Time (JIT) compiler supporting speculative optimizations. While all JavaScript is JIT compiled into an intermediate bytecode and run by an interpreter, functions that are run frequently are selectively further compiled into optimized machine code to increase overall performance [52].

5.3.2 libuv.

libuv is a cross-platform fork of the Libev event library for Unix. The developers of Node.js created libuv in order to extend Node.js to support Microsoft Windows. Libev has since been removed from Node.js, and libuv is used in Node.js to handle event-driven I/O for Node.js while keeping the same API across all platforms. libuv is significant in that its event loop architecture is the basis for the design paradigm of Node.js [53].

The libuv architecture is shown in Figure 22. In this figure, the boxes drawn near the bottom of the figure represent lower-level, OS-interfacing components while components near the top represent APIs that interface with Node.js.

5.3.3 Cross-Platform Asynchronous Programming.

Each operating system supported by libuv provides its own asynchronous event notification mechanism, and these are shown as components in Figure 22. epoll, kqueue, event ports, and IOCP are the asynchronous event notification mechanisms of Linux, FreeBSD/macOS, Solaris, and Windows, respectively. While these features can

Figure 22. The libuv architecture [53]

be used to the same effect, each one varies both syntactically and semantically from the others. This illustrates the main feature of the libuv library, which is to abstract over these operating system details and present one unified, cross-platform API for asynchronous I/O.

However, these asynchronous event notification mechanisms only apply to certain system calls. Other system calls, such as those related to the file system and Domain Name System (DNS) lookups, are only provided as blocking calls. To handle these synchronous, blocking calls in an asynchronous manner, libuv maintains a thread pool. By default, this thread pool is made up of four threads. This is shown at the bottom right of Figure 22. Whenever such a call is made, it is assigned to a thread which can block while the rest of the program executes in the event loop.

5.3.4 Event-Based Programming.

Node.js is built on libuv, which handles asynchronous programming with an event loop, as shown in Figure 23.

Figure 23. The libuv event loop [53]

While traditional network servers (e.g., Apache) make heavy use of multithreaded programming to serve many requests concurrently, Node.js eschews this model for event- based, asynchronous programming. The motivation for this is a simpler programming model while maintaining a high degree of concurrency over I/O-bound workloads. In comparing the approaches, one author expands on the difficulties of the former:

Even though many developers have successfully used multithreading in production applications, most agree that multithreaded programming is anything but easy. It’s fraught with problems that can be difficult to isolate and correct, such as deadlock and failure to protect resources shared among threads. [54]

I/O tasks, by nature, run orders of magnitude slower than tasks involving pure computation. By implementing non-blocking calls for these tasks, the main loop of the program can continue to process other events while the I/O-related task continues in the background, on a separate thread. When a task completes, the main loop gives

cooperates with the operating system to manage background work through polling or threads, depending on the platform, in a way which keeps the platform-specific details transparent to the user of the library.

libuv implements a single-threaded event loop which continually checks for new events and handles callbacks associated with those events. libuv’s event-loop pattern (and therefore Node.js) can yield programs that are higher-performing, simpler, and less prone to error than traditional patterns. By abstracting away the details of handling multi-threaded logic, the library shields the user from having to use semaphores, mutexes, or other safety mechanisms for shared memory, which makes code both simpler and less prone to error. This method also avoids the memory overhead incurred in the traditional model by having a static number of threads or processes ready to handle the expected workload from connecting clients.

libuv embraces asynchronous, non-blocking calls for I/O-intensive tasks in order to keep from blocking the event loop and maintain good performance. I/O-intensive tasks typically include tasks such as reading or writing a file from a disk, sending or receiving data over the network, or printing data to the screen.

Related documents