This is the sixth day of my participation in the August More text Challenge. For details, see:August is more challenging

Why does Redis support high concurrency?

The underlying Redis uses the mechanism of NIO multiplexing I/O to realize I/O multiplexing for multiple different connections (TCP), which well supports high concurrency and can achieve thread safety.

Redis officially does not have a Windows version, only a Linux version.

NIO is implemented in different operating systems in different ways. In Windows operating system, SELECT is used to implement round training, and empty round training still exists, which is very inefficient. The time complexity is order n. Secondly, the data of the rotation is limited by default, so it is difficult to support tens of thousands of TCP connections. In Linux operating system, epoll is used to implement event-driven callback, so there is no empty wheel training, only active callback is implemented for active socket connection, so the performance is greatly improved, and the time complexity is O(1).

Epoll does not exist in Windows, but only in Linux.

This is why Nginx, Redis, and ultimately Epoll, the IO multiplexing mechanism in Linux, all support high concurrency very well.

Blocking and non-blocking

Blocking and non-blocking are commonly used to describe interactions between multiple threads. For example, if a thread occupies a critical section, all other threads that need the resource must wait in the critical section, and waiting causes the thread to hang. This is called blocking. At this point, if the occupying thread remains unwilling to release the resource, all other threads blocking on the critical section will not work. Non-blocking allows multiple threads to enter a critical section simultaneously.

A blocking call means that the current thread is suspended until the result of the call is returned. The calling thread returns only after it gets the result. A non-blocking call does not block the current thread until the result is not immediately available.

BIO NIO AIO concept

BIO (Blocking IO) : A traditional java. IO package, which is based on the stream model, is implemented in a synchronous, blocking manner. This means that when an input stream or output stream is read, the threads are blocked until the action is complete, and the calls between them are in a reliable linear order. The advantage is that the code is relatively simple and intuitive; The disadvantages are low IO efficiency and scalability, which can easily become the bottleneck of application performance. NIO (non-blocking IO) : The Java. Nio package, introduced in Java 1.4, provides new abstractions such as channels, selectors, buffers, etc., allowing you to build multiplexed, synchronous, non-blocking I/O programs, while providing a way to operate data more closely to the operating system’s underlying high performance. AIO (Asynchronous IO) : Asynchronous IO is an update of NIO introduced after Java 1.7. It provides an Asynchronous non-blocking IO operation, so people call it AIO (Asynchronous IO). Asynchronous IO is based on the event and callback mechanism, which means that the application operation returns directly after the application operation. When the background processing is complete, the operating system notifies the corresponding thread to proceed.

NIO interpretation

We know that BIO is blocking I/O, it’s stream oriented, it’s byte by byte, it’s inefficient; NIO is synchronous, non-blocking, buffer-oriented, and its highlight is IO multiplexing. We can think of IO multiplexing this way, multiplexing can mean multiple different TCP connections, multiplexing is a thread that maintains multiple different IO operations. So it has the advantage of being very small in CPU usage and thread-safe.

NIO core components

Channel: Data is transmitted through a channel. Channels are all registered with selectors. Selector: Also called a multiplexer. You can maintain multiple channels in a single-threaded situation, and you can maintain multiple connections.

BIO and NIO code demo

Traditional BIO-blocking Socket procedures:

Start a Socket server, at which point the console will output start waiting to receive data… And wait for the client to connect.

package com.nobody;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

/ * * *@author Mr.nobody
 * @Description
 * @date2020/7/4 * /
public class SocketTcpBioServer {

    private static byte[] bytes = new byte[1024];

    public static void main(String[] args) {

        try {
            / / create a ServerSocket
            final ServerSocket serverSocket = new ServerSocket();
            // Bind the listening port number
            serverSocket.bind(new InetSocketAddress(8080));

            while (true) {
                System.out.println("Start waiting for receiving data in...");
                Socket accept = serverSocket.accept();
                int read = 0;
                read = accept.getInputStream().read(bytes);
                String result = new String(bytes);
                System.out.println("Data received:"+ result); }}catch(IOException e) { e.printStackTrace(); }}}Copy the code

To start another Socket client, do not enter.

package com.nobody;

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

/ * * *@author Mr.nobody
 * @Description
 * @date2020/7/4 * /
public class ClientTcpSocket {

    public static void main(String[] args) {
        Socket socket = new Socket();
        try {
            // Establish a connection with the server
            SocketAddress socketAddress = new InetSocketAddress(InetAddress.getLocalHost(), 8080);
            socket.connect(socketAddress);
            while (true) {
                Scanner scanner = newScanner(System.in); socket.getOutputStream().write(scanner.next().getBytes()); }}catch (UnknownHostException e) {
            e.printStackTrace();
        } catch(IOException e) { e.printStackTrace(); }}}Copy the code

Start another Socket client02 and enter client02.

package com.nobody;

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

/ * * *@author Mr.nobody
 * @Description
 * @date2020/7/4 * /
public class ClientTcpSocket02 {

    public static void main(String[] args) {
        Socket socket = new Socket();
        try {
            // Establish a connection with the server
            SocketAddress socketAddress = new InetSocketAddress(InetAddress.getLocalHost(), 8080);
            socket.connect(socketAddress);
            while (true) {
                Scanner scanner = newScanner(System.in); socket.getOutputStream().write(scanner.next().getBytes()); }}catch (UnknownHostException e) {
            e.printStackTrace();
        } catch(IOException e) { e.printStackTrace(); }}}Copy the code

In this case, you can see that the server does not receive data. The Socket client 01 connects first, but does not enter data. Therefore, the server is waiting for the input of client 01, which causes the blocking of client 02.

If we enter client01 on client01 at this time, the server console displays the following: first output the data of client01, and then output the data of client 02.Of course, if you do not want the connected client not to block, you can use multithreading to implement pseudo asynchronous IO, simply change the server code to:

public static void main(String[] args) {

    try {
        / / create a ServerSocket
        final ServerSocket serverSocket = new ServerSocket();
        // Bind the listening port number
        serverSocket.bind(new InetSocketAddress(8080));

        while (true) {
            System.out.println("Start waiting for receiving data in...");
            Socket accept = serverSocket.accept();
            new Thread(new Runnable() {
                @Override
                public void run(a) {
                    int read = 0;
                    try {
                        read = accept.getInputStream().read(bytes);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    String result = new String(bytes);
                    System.out.println("Data received:"+ result); } }).start(); }}catch(IOException e) { e.printStackTrace(); }}Copy the code

The downside of the above code, of course, is that the created threads are frequently created and destroyed, frequently CPU scheduled, and also consume memory resources, which can be optimized using the thread pool mechanism.

NIO non-blocking Socket procedure: The first two client code is unchanged, and the server code is as follows:

package com.nobody.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;

/ * * *@author Mr.nobody
 * @Description
 * @date2020/7/4 * /
public class NioServer {

    private Selector selector;

    public void iniServer(a) {
        try {
            // Create a pipe
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            // Set the pipe to non-blocking
            serverSocketChannel.configureBlocking(false);
            // Bind the pipe to port 8080
            serverSocketChannel.bind(new InetSocketAddress(8080));
            // Create a selector
            this.selector = Selector.open();
            // Register the pipe with the selectionKey.op_accept event,
            // Selector. Select () will return when the event arrives, otherwise the method will block.
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch(IOException e) { e.printStackTrace(); }}public void listen(a) throws IOException {
        System.out.println("Server started successfully...");
        // Polling access Selector
        while (true) {
            // Selector. Select () will return when the event arrives, otherwise the method will block.
            int select = selector.select(10);
            // No message sent, skip
            if (0 == select) {
                continue;
            }

            // Register the event selected by selector
            Iterator<SelectionKey> iterator = this.selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                // Delete the selected key to avoid repeated processing
                iterator.remove();
                if (key.isAcceptable()) { // Client connection event
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    // Get the pipe to the client
                    SocketChannel socketChannel = server.accept();
                    // Set the pipe to non-blocking
                    socketChannel.configureBlocking(false);
                    // After connecting to the client, set the pipeline to be read in order to receive messages from the client
                    socketChannel.register(this.selector, SelectionKey.OP_READ);
                } else if (key.isReadable()) { // Readable events
                    // Create a buffer to read data
                    ByteBuffer byteBuffer = ByteBuffer.allocate(512);
                    SocketChannel channel = (SocketChannel) key.channel();
                    channel.read(byteBuffer);
                    byte[] bytes = byteBuffer.array();
                    String msg = new String(bytes).trim();
                    System.out.println("Server receives message:" + msg);
                    ByteBuffer outByteBuffer = ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8));
                    // Reply the message to the clientchannel.write(outByteBuffer); }}}}public static void main(String[] args) throws IOException {
        NioServer nioServer = newNioServer(); nioServer.iniServer(); nioServer.listen(); }}Copy the code

Start the server, then start the two clients, neither of which blocks.


I am Chen PI, a Coding ITer in the Internet, wechat search “Chen PI JavaLib” first time to read the latest article oh!

The end of this sharing ~~

If you think the article is helpful to you, like, collect, follow, comment on your