[Switch] High-performance network server programming: Why is epoll the best under linux, and Netty is better than NIO.2?

High-performance network server programming: why epoll is the best under linux, and Netty is better than NIO.2?

  (2015-02-28 19:12:37)
Label: 

miscellaneous talk

 
 

  The basic IO programming process (including network IO and file IO) is to open the file descriptor (windows is handler, java is stream or channel), multiplex capture (Multiplexe, ie select and poll and epoll) IO can read and write the state , and then the readable and writable file descriptors are used for IO reading and writing. Since the speed of the IO device is slower than that of the CPU and memory, in order to make better use of the CPU and memory, multiple threads will be opened, and each thread will read and write a file descriptor.

  But the C10K problem made us realize that with a large number of network connections, machine equipment and network speed are no longer the bottleneck. The bottleneck lies in the way the operating system and IO applications communicate and cooperate .

  For example, when 10,000 sockets are connected, the traditional IO programming model needs to open 10,000 threads to deal with it. It should also be noted that sockets will be closed and opened, and 10,000 threads must be closed and rebuilt continuously, and resources are wasted here. Above, we calculate that creating a thread consumes 1M memory, and a 10,000-thread machine requires at least 10G memory, which is basically impossible under the IA-32 machine architecture (PAE is required), and now the x64 architecture can be more comfortable. , be aware that this is just a rough memory consumption. What about other resources?

  Therefore, high-performance network programming (ie IO programming), first, needs to loosen the corresponding relationship between IO connections and application threads, which is the origin of the requirements of non-blocking and asynchronous (constructing a thread pool, epoll monitors a number of fds, passes fds into the thread pool, and these worker threads read and write io). Second, a high-performance OS is required to notify the IO device that can read and write (data is coming): from level-triggered notification to edge-triggered notification, we will talk about this notification method later.

  It is necessary to pay attention to asynchrony, which is not equal to AIO (asynchronous IO). Both linux's AIO and java's AIO are a way to achieve asynchronous, and they are both slag, which we will talk about next.

  In response to the two points mentioned above, let's look at the problem of select and poll

  imageimage

 

  Both of these functions require us to pass the file descriptors that need to be monitored (to see if there is data) into the kernel through an array each time they are called. The kernel scans these file descriptors every time, understands them, and establishes An array corresponding to a file descriptor and IO (actual kernel work will have a better implementation, but it can be understood first), so that when IO comes, these file descriptors are notified, and then these selects, etc. waiting in the process are notified. poll. What about when there are 10,000 file descriptors to monitor (10,000 network connections)? This work efficiency is very low, but the resource requirements are very high.

  we watch epoll

  image

  image

  image

  epoll is very clever. It is divided into three functions. The first function creates something similar to a session. The second function tells the kernel to maintain the session and passes the fd belonging to the session to the kernel. The third function, epoll_wait, is the real monitoring. For multiple file descriptor functions, I only need to tell the kernel which session I am waiting for, and the fd in the session has been analyzed by the kernel for a long time, and it is no longer analyzed every time epoll is called, which saves most of the work of the kernel. . In this way, every time epoll is called, the kernel does not rescan the fd array, because we maintain the session.

  Speaking of this, there is only one word, open source, praise, everyone gathers firewood, and the flame is high, praise.

  The efficiency of epoll is not only reflected here, but also improved in the way of kernel notification. Let's first look at the notification method of select and poll, that is, level-triggered notification. After the kernel is interrupted by DMA and captures data from IO devices , originally only need to find which file descriptor this data belongs to, and then notify the waiting function in the thread, but select and poll require the kernel to continue to scan the one corresponding to the kernel fd and io just created during the notification phase. Array, because the application may not actually read those fds after the last notification that there is data, the application did not read the last time, the kernel has to continue to notify when the select and poll call this time, the communication method between the os and the application Efficiency is low. It's just convenient for programming (you don't need to read that network io, Founder will continue to notify next time).

  So epoll designed another notification method: edge-triggered notification. In this mode, when io devices receive data, only the fd corresponding to these io devices will be notified. The fd notified last time will not be notified, and the kernel will no longer scan. a lot of fd.

  Based on the above analysis, we can see that epoll is a design specially designed for the communication and cooperation between os and applications under the large network concurrent connection. When programming a network server under linux, this must be adopted. The domestic asynchronous frameworks of nginx and php are swool and varnish. , all use this.

  Note that the edge-triggered notification of epoll is also turned on. Both NIO and NIO.2 of java only use epoll and do not open edge-triggered notification, so they are not as good as Netty of JBoss.

  Next, let's talk about AIO. What AIO hopes is that you need to use a function to monitor a lot of fds in select, poll, and epoll. Then I don't need it in AIO. You tell the kernel about the fd, and your application does not need to wait. , the kernel will tell the application through soft interrupts such as signals that the data is coming, and you can read it directly. Therefore, select, poll, and epoll can be discarded with AIO.

  However, the implementation of Linux's AIO is that the kernel and the application share a memory area. The application tests this memory area (avoid calling nonblocking read and write functions to test whether data is coming, because even if nonblocking read and write are called, the process needs to switch users. state and kernel state, which is still inefficient) to know whether fd has data, but the detection of memory area is not real-time after all, you need to construct a loop to monitor memory in the thread, set sleep, the overall efficiency is not as good as real-time notification such as epoll . Therefore, AIO is slag, suitable for low-concurrency IO operations. Therefore, the AIO introduced by NIO.2 introduced by java7 is also slag for high-concurrency network IO design programs. Only Netty's epoll+edge-triggered notification is the best, which can make applications and OS communicate with the highest efficiency in linux.

 

Note: Blocking IO and asynchronous IO basically mean the same thing, but describe different aspects of the same thing.

http://en.wikipedia.org/wiki/Asynchronous_I/O

In computer science, asynchronous I/O, or non-blocking I/O is a form of input/output processing that permits other processing to continue before thetransmission has finished.

 

From: http://blog.sina.com.cn/s/blog_4c8c58ce0102vkbo.html

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326949072&siteId=291194637