1.select and Epoll Model differences
1.1. Overview of the network IO model
Generally speaking, network IO can be abstracted into the data exchange between the user state and the kernel state.
A network data read operation (read), can be split into two steps:
1) NIC driver waits for data ready (kernel state)
2) Copy the data from the kernel space to the process space (user state). Depending on how these two steps are handled differently, we typically divide the network IO into blocking IO and non-blocking IO.
• Block IO. When a user invokes a network IO-related system call (for example, read), the system call will block until the data sent by the peer system arrives until the network data has been read by the kernel network card at this time. If the peer has never sent the data, the call will never return.
· Non-blocking IO. When a user invokes a network IO-related system call (for example, read), if the kernel network has not received the network data at this time, then the system call will return immediately and return a eagain error code.
There is no good way to detect whether the network IO is readable or writable before the IO multiplexing technology is available. Therefore, in order to increase the concurrent connection of the system, it is generally to increase the number of concurrent connections of the system by means of multi-threaded or multi-process. However, the problem with this approach is that the number of concurrent connections to the system is limited by the maximum number of threads or processes in the operating system, and as the number of threads or processes in the operating system increases, there will be a lot of context switching, resulting in a sharp decrease in performance. To solve this problem, the operating system introduces IO multiplexing (IO multiplexing).
1.2. IO multi-channel transfer technology
Io multiplexing is essentially a mechanism for detecting IO events using system calls provided by operating systems such as SELECT, Epoll, and so on. Through the mechanisms of select, Epoll and so on, we can easily manage a large number of network IO connections at the same time, and gain access to the active state of the connection. When one or more of these network IO events occur, system calls such as SELECT, Epoll, and so on, return the corresponding connection, and we can read or write to the connection to complete the network data interaction.
1.3.select Working principle
Select function Prototypes:
int select (int Nfds, fd_setReadfds, Fd_setWritefds,fd_setExceptfds, struct timevalTimeout);
Select each parameter description:
· Nfds
The value of this parameter is generally set to the largest descriptor (FD) +1 in the Read collection (READFDS), the Write collection (Writefds), and the Exceptfds (Exception collection), and of course it can be set to fd_setsize. Fd_setsize is a macro defined by the operating system, typically 1024. That is, the maximum number of reads and writes and the size of the exception collection is 1024, so you can manage up to 1024 connections using SELECT. If it is greater than 1024 connections, select will produce an indeterminate behavior.
· Readfds
Pointers to the set of readable descriptors, if we care about the readable events of the connection, we need to set the connection descriptor to the Read collection.
Writefds
A pointer to a writable descriptor set that, if we care about a connected writable event, needs to set the connection descriptor to a writable collection.
· Exceptfds
A pointer to the exception descriptor set, which, if we care about an exception to the connection, sets the connection descriptor to the exception descriptor collection.
Timeout
Refers to the time a select is willing to wait.
struct Timeval {
Longtv_sec; Number of seconds
Longtv_usec; Number of microseconds
}
Generally speaking, there are three kinds of situations:
timeout is empty and select will wait forever. Returns until a connection is readable, writable, or interrupted by a signal.
timeout->tv_sec = 0 and timeout->tv_usec = 0, do not wait at all. Returns immediately after all specified descriptors have been detected. This is the polling method that gets the state of multiple descriptors without blocking the Select function.
timeout->tv_sec! = and Timeout->tv_usec! = 0, waiting for the specified number of seconds and microseconds. Returns immediately when one of the specified descriptors is ready or exceeds the specified time value. Returns 0 if the timeout has not yet been prepared for a descriptor.
Select works by polling to detect the state of the descriptor (FD) in each collection, and if the state of the descriptor changes, the corresponding tag bit is set in the collection, and if the state of the specified descriptor is not changed, the descriptor is removed from the corresponding collection. Therefore, the call complexity of select is linear, that is, O (n). For example, a babysitter takes care of a group of children, and if the child needs urine as a network IO event, the role of select is like the nanny asking every child: do you want to pee? If the child answers Yes, the babysitter will take the child out and put it in another place. When all the children have been asked, the babysitter leads the child to pee to go to the bathroom (handling network IO events).
The limit for select, mentioned earlier in the Fd_setsize macro, is defined by the operating system. Under Linux is usually 1024, which means that select can manage up to 1024 descriptors. If a description is greater than 1024, select will produce unpredictable behavior. How do I use Select to handle cases where the number of connections is greater than 1024 without poll or epoll? The answer is to use multithreading technology, where each thread uses a single select for detection. In this case, the number of concurrent connections your system can handle equals the number of threads1024. Early Apache was the technology to support massive connections.
1.4.epoll Working principle
Epoll function Prototypes:
int epoll_create (int size);
Intepoll_ctl (int epfd, int op, int fd, struct epoll_eventevent);
int epoll_wait (INTEPFD, struct epoll_event *events, intmaxevents, int timeout);
Epoll relies on the above three functions to accomplish thousands of concurrent connection management. Epoll use mode, 1) establish epoll handle through epoll_create. 2) Add the event of interest to the descriptor by Epoll_ctl to the Epoll handle. 3) Call epoll_wait to return all readable and writable descriptors.
Epoll is an improved epoll of the Linux kernel for processing large-volume file descriptors, an enhanced version of the multiplexed IO interface select/poll under Linux, which significantly increases the CPU utilization of the program in cases where there are only a few active instances of a large number of concurrent connections. Another reason is that when getting an event, it does not need to traverse the entire set of descriptors that are being listened to, as long as it traverses the set of descriptors that are joined to the ready queue by a kernel IO event that wakes up asynchronously. Epoll provides edge triggering (edge triggered) in addition to the level triggered of Select/poll IO events, which makes it possible for user space programs to cache IO states and reduce epoll_wait/ Epoll_pwait calls to improve application efficiency.
Or take care of a group of children as an example, under the Epoll mechanism, nannies no longer need to ask each child whether or not to pee. Instead, each child will take the initiative to step up to a predetermined place if he or she needs to pee, and the nanny's job is to see if there are any children in a predetermined place. If there is a child, lead the child to the toilet (Network event processing). Therefore, this mechanism of epoll can efficiently handle thousands of concurrent connections, and performance will not decrease as the number of connections increases.
The difference between Apache Select and Nginx epoll model