2 --- notificación de información detallada diseño del sistema back-end


En una sección pequeña, hablamos de antes y después del final de la selección de comunicación, entonces esta sección introducimos la arquitectura de fondo la forma de diseñar?

El diseño general

Los usuarios pueden obtener una notificación de mensaje tiene dos modos

  • Después de entrar en la iniciativa en línea para obtener el sistema de
  • iniciativa en línea para impulsar el sistema un nuevo mensaje al destinatario

Bajo previsto, y los nuevos datos de recordatorio de notificación de mensajes de notificación de usuario se coloca en la base de datos, una base de datos de las operaciones de leer y escribir con frecuencia. Si el mensaje es grande, la presión DB, pueden producirse cuellos de botella de datos.

De acuerdo a un lado dos modos anterior, el diseño en dos niveles:

Después de entrar en la solicitud en línea para el sistema

Este sistema modelo es el destinatario de la solicitud, el sistema vuelve a la nueva modalidad de notificación de mensajes de un destinatario, el siguiente procedimiento:

  1. Receptor de petición al servidor de Netty
  2. Netty servicio de conexión WebSocket a conectarse a su propio conjunto de conexiones
  3. Netty acuerdo con la información del destinatario en el mensaje de consulta RabbitMQ
  4. Si hay un mensaje nuevo, se devuelve una notificación de mensaje nuevo
  5. conexión WebSocket utilizando el número, el destinatario devuelva un mensaje nuevo
    Aquí Insertar imagen Descripción

iniciativa en línea para impulsar el sistema para el destinatario

Este modo es el nuevo sistema de notificación de mensajes vuelve al modo del receptor, el proceso es el siguiente:

  1. RabbitMQ empujará datos a un nuevo mensaje de Netty
  2. Netty conexión WebSocket retira del receptor agrupación de conexiones
  3. Netty nuevo mensaje devuelto por el número de conexión del receptor WebSocket
    Aquí Insertar imagen Descripción

Programación IO

El mencionado Netty, antes de empezar a entender Netty, los primeros en implementar un programa para comunicarse con el servicio de cliente, utilizando la programación tradicional IO y programación utilizando el NIO ¿Cuál es la diferencia.

La programación tradicional IO

Después de cada sobre la conexión del cliente, el servidor va a iniciar un hilo para manejar la petición del cliente. modelo de comunicación bloqueo de E / S del diagrama es la siguiente:
Aquí Insertar imagen Descripción
C-Business: Cliente cada dos segundos para enviar la cadena al servidor, el servidor de impresión a la consola después de la recepción.

public class IOServer {
    public static void main(String[] args) throws Exception {
​
        ServerSocket serverSocket = new ServerSocket(8000);while (true) {
            // (1) 阻塞方法获取新的连接
            Socket socket = serverSocket.accept();new Thread() {
                @Override
                public void run() {
                    String name = Thread.currentThread().getName();try {
                        // (2) 每一个新的连接都创建一个线程,负责读取数据
                        byte[] data = new byte[1024];
                        InputStream inputStream = socket.getInputStream();
                        while (true) {
                            int len;
                            // (3) 按字节流方式读取数据
                            while ((len = inputStream.read(data)) != -1) {
                                System.out.println("线程" + name + ":" + new String(data, 0, len));
                            }
                        }
                    } catch (Exception e) {
                    }
                }
            }.start();
        }
    }
}

implementación del cliente:

public class MyClient {public static void main(String[] args) {
        //测试使用不同的线程数进行访问
        for (int i = 0; i < 5; i++) {
            new ClientDemo().start();
        }
    }static class ClientDemo extends Thread {
        @Override
        public void run() {
            try {
                Socket socket = new Socket("127.0.0.1", 8000);
                while (true) {
                    socket.getOutputStream().write(("测试数据").getBytes());
                    socket.getOutputStream().flush();
                    Thread.sleep(2000);
                }
            } catch (Exception e) {
            }
        }
    }
}

Podemos ver en el código del lado del servidor, en el modelo tradicional IO, se requiere que cada conexión para crear un hilo para mantener tras el éxito de cada hilo contiene un bucle infinito tiempo.

Si se ejecuta en el caso de un pequeño número de usuarios no es ningún problema, pero por el número relativamente grande de usuarios de negocios, el servidor puede tener que soportar cientos de miles de conexiones, modelo IP puede no ser apropiado.
Si hay 10 000 10 000 conectada a la rosca correspondiente, a continuación, 10,000 mientras bucle, este modelo tiene los siguientes problemas:

  • Cuanto mayor sea el cliente, se creará más hilos de procesamiento. Un hilo es un sistema operativo recurso muy valioso, al mismo tiempo, un gran número de procesos en el estado bloqueado es muy grave desperdicio de recursos. Y si el servicio se encuentre en el flujo máximo impacto, como la doble once actividades, el grupo de subprocesos al instante que se haya agotado, lo que resulta en la parálisis del servidor.
  • Debido a que está bloqueando la comunicación, después de la explosión de los hilos del sistema operativo frecuentan conmutación hilo, una fuerte disminución de rendimiento de la aplicación.
  • los datos de programación IO se lee en unidades de un flujo de bytes, la eficiencia no es alta.

programación NIO

NIO, también llamada nueva-IO o de no bloqueo-IO, entiende que es no bloqueante IO. NIO modelo de programación, una conexión ya no es nuevo para crear un nuevo hilo, pero se puede poner la conexión directamente unido a un hilo fijo, y luego conectar todos este hilo para leer y escribir por el responsable, con una imagen de comparar IO y NIO:
Aquí Insertar imagen Descripción
como se muestra arriba, el modelo de IO, una conexión creará un hilo, que corresponde a un tiempo de bucle, el propósito de un bucle infinito es supervisar constantemente si los datos se puede leer en esta conexión. Pero en la mayoría de los casos, el 10000 está conectado dentro del mismo tiempo, sólo una pequeña cantidad de datos que leer está conectado, por lo tanto, mientras que un número de ciclo de la muerte se desperdician porque no hay datos.

En el modelo de NIO, puede poner tantos muertos bucle while se convierte en un bucle infinito, el control de bucle de un hilo. Este es el efecto después de que el modelo de selección NIO (Selector), y una conexión, y mientras no creamos un bucle infinito para vigilar si hay datos para leer, pero se conecten directamente a este registro a la barra de selección, mediante la verificación este selector, el monitor se puede conectar a los datos del lote legible, y luego leer los datos.

NIO de tres componentes básicos: un canal (Channel), un tampón (tampón), un selector (selector)

Channel (Canal)

IO es tradicional en la actualización corriente (corriente). Flujo es unidireccional, de lectura y escritura (InputStream y OutputStream), Canal es bidireccional independiente, la operación de lectura se puede realizar, pero también se puede escribir.

Buffer (Buffer)

Buffer puede ser entendido como un área de memoria, los datos pueden ser escritos y leídos después de ella.

Un selector (selector)

Un selector (selector) puede implementar un hilo separado para supervisar registro múltiple su canal superior (Channel), mediante la selección de un determinado mecanismo para lograr el efecto de multiplexación.

NIO IO ventajas relativas:

IO flujo orientado, cada vez que un byte es un byte leído partir de los datos subyacentes del sistema operativo y los datos sólo se puede leer desde el extremo al otro, no se puede mover hacia atrás y adelante en el flujo de datos. NIO se enfrenta a la memoria intermedia, los datos se leen desde un buffer dentro de este, y se pueden mover hacia atrás y adelante en el búfer cuando se requiera.
IO se bloquea, lo que significa que, cuando un hilo para leer datos o escribir datos, el hilo se bloquea hasta que hay algunos datos que deben leerse, o los datos están completamente escrito, en el que el hilo no se puede hacer nada más. El NIO es no bloqueante, no siempre tiene que esperar a que se complete la operación antes de hacer otras cosas, pero se puede hacer otra cosa mientras se espera para el proceso, somos capaces de maximizar el uso de recursos del servidor.
NIO introdujo selector de multiplexor IO. proporcionar un selector de canales es hilos de servicio registrados, múltiples canales puede atracar en el mismo tiempo, y en el grupo de subprocesos para el adaptador de canal, seleccione el hilo apropiado canal de mango. Dado que el modelo NIO reduce en gran medida el número de hilos, la eficiencia de conmutación hilo es, por tanto, muy mejorado.
Y en frente de la misma escena, utilizando la cuenta de NIO (código de copia demuestra los efectos):

public class NIOServer {
    public static void main(String[] args) throws IOException {
        // 负责轮询是否有新的连接
        Selector serverSelector = Selector.open();
        // 负责轮询处理连接中的数据
        Selector clientSelector = Selector.open();new Thread() {
            @Override
            public void run() {
                try {
                    // 对应IO编程中服务端启动
                    ServerSocketChannel listenerChannel = ServerSocketChannel.open();
                    listenerChannel.socket().bind(new InetSocketAddress(8000));
                    listenerChannel.configureBlocking(false);
                    // OP_ACCEPT表示服务器监听到了客户连接,服务器可以接收这个连接了
                    listenerChannel.register(serverSelector, SelectionKey.OP_ACCEPT);while (true) {
                        // 监测是否有新的连接,这里的1指的是阻塞的时间为1ms
                        if (serverSelector.select(1) > 0) {
                            Set<SelectionKey> set = serverSelector.selectedKeys();
                            Iterator<SelectionKey> keyIterator = set.iterator();while (keyIterator.hasNext()) {
                                SelectionKey key = keyIterator.next();if (key.isAcceptable()) {
                                    try {
                                        // (1) 每来一个新连接,不需要创建一个线程,而是直接注册到clientSelector
                                        SocketChannel clientChannel = ((ServerSocketChannel) key.channel()).accept();
                                        clientChannel.configureBlocking(false);
                                        // OP_READ表示通道中已经有了可读的数据,可以执行读操作了(通道目前有数据,可以进行读操作了)
                                        clientChannel.register(clientSelector, SelectionKey.OP_READ);
                                    } finally {
                                        keyIterator.remove();
                                    }
                                }
                            }
                        }
                    }
                } catch (IOException ignored) {
                }
            }
        }.start();
​
​
        new Thread() {
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                try {
                    while (true) {
                        // (2) 批量轮询是否有哪些连接有数据可读,这里的1指的是阻塞的时间为1ms
                        if (clientSelector.select(1) > 0) {
                            Set<SelectionKey> set = clientSelector.selectedKeys();
                            Iterator<SelectionKey> keyIterator = set.iterator();while (keyIterator.hasNext()) {
                                SelectionKey key = keyIterator.next();if (key.isReadable()) {
                                    try {
                                        SocketChannel clientChannel = (SocketChannel) key.channel();
                                        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                                        // (3) 读取数据以块为单位批量读取
                                        clientChannel.read(byteBuffer);
                                        byteBuffer.flip();
                                        System.out.println("线程" + name + ":" + Charset.defaultCharset().newDecoder().decode(byteBuffer)
                                                .toString());
                                    } finally {
                                        keyIterator.remove();
                                        key.interestOps(SelectionKey.OP_READ);
                                    }
                                }
                            }
                        }
                    }
                } catch (IOException ignored) {
                }
            }
        }.start();
    }
}
Publicado 41 artículos originales · ganado elogios 47 · Vistas a 30000 +

Supongo que te gusta

Origin blog.csdn.net/u014526891/article/details/105388898
Recomendado
Clasificación