Every HTTP request is a process from request to response, so the HTTP server does not need to maintain any state,
While websocket requires the server to maintain all connection states, ruby is not very good at dealing with concurrency. Actioncable uses many interesting technologies for performance and ease of use.
For example, message’s Pub / sub uses redis’s Pub / sub (there are other adapters).
In the concurrent processing, the ThreadPoolExecutor of current ruby is used, while the connection of websocket is processed by nio4r and websocket driver.
The following mainly introduces these two technologies and I / O model.
Websocket driver mainly deals with websocket protocol and I / O layer. That is to say, I / O events can be handled in different ways. At the same time, a series of events, such as: open,: message,: close, are provided for easy use.
The server side socket using websocket driver needs to implement two methods, URL and
URL is the URL that users use to connect to websocket.
write(string)Method is used to write data into the stream.
After that, when I / O monitors and hears the data, call
WebSocket::Driver#parseMethod to analyze the data.
After parsing, websocket will return the parsed data through the: message event.
The example given by websocket driver readme uses eventmachine to handle I / O operations, while actioncable uses nio4r directly.
I / O operation is to copy data between main memory and peripheral devices.
Peripherals are generally much slower than main memory. In order to deal with speed mismatch, different methods can be used to operate I / O, I / O model.
Synchronous blocking I / O is the traditional I / O model.
In short, when I / O is performed, the thread is suspended until I / O is completed, and then the operation after the program is executed. That is to say, during IO operation, the thread is always waiting, so it is called blocking io. Ruby provides io.read method.
Synchronous non blocking IO
During IO operation, whether the system is ready for data or not, it will return directly. If it is not ready, an error is returned. When the user receives the error, he can try the IO operation again. Ruby provides the io.read’nonblock method.
selectLet kernal suspend the current thread and give control to the application when one or more I / O events occur.
IO multiplexing is suitable for scenarios where multiple IO objects need to be monitored at the same time.
The time complexity of select is O (n), and Linux provides a more efficient version
epoll, epoll time complexity is O (log n)). Thin provides the option to use epoll or not. Ruby provides the IO. Select method.
Nio4r is a ruby implementation of Java. NiO, but it provides a simpler interface.
Nio4r has two main parts:
Selectors: used to monitor multiple I / O objects at the same time
Monitors: used to track I / O events of concern, such as reads.
require "nio" server = TCPServer.new("127.0.0.1", 12345) selector = NIO::Selector.new 3.times do client = server.accept _monitor = selector.register(client, :r) end ready = selector.select
First, create a NiO:: selector object, and then register the concerned I / O events to the selector object through NiO:: selector ා register.
Finally, in a loop, call the NiO:: selector ා select method to select the ready event.
The class handling I / O in actioncable is connection:: streameventloop, initializing selector in
@nio ||= NIO::Selector.new, and then the streameventloop ා attach method registers the I / O event on the NiO selector.
Finally, the run method is used to process the event listening run, using the
IO.read_nonblockRead the stream.
- The underlying library supporting actioncable
- Java NiO (3): IO model
- Analysis of Java NiO
- A gentle introduction to nio4r: low-level portable asynchronous I/O for Ruby
- Computer Systems: A Programmer’s Perspective
- Programming Erlang : Software for a Concurrent World