Preguntas frecuentes de la entrevista de Netty

Visión de conjunto:

  • ¿Qué es Netty?
  • ¿Por qué usar Netty?
  • ¿Entiende los escenarios de aplicación de Netty?
  • ¿Cuáles son los componentes centrales de Netty? ¿Cuál es el papel de cada uno?
  • EventloopGroup entiende ¿Cuál es la relación con EventLoop?
  • ¿Conoce Bootstrap y ServerBootstrap?
  • ¿Cuántos subprocesos iniciará el constructor predeterminado de NioEventLoopGroup?
  • ¿Entiendes el modelo de subprocesamiento de Netty?
  • ¿Entiende el proceso de inicio del servidor y el cliente de Netty?
  • ¿Entiendes la conexión prolongada y el mecanismo de los latidos del corazón de Netty?
  • ¿Entiendes la copia cero de Netty?

¿Qué es Netty?

  1. Netty es un marco cliente-servidor basado en NIO, que se puede utilizar para desarrollar aplicaciones de red de forma rápida y sencilla.
  2. Simplifica y optimiza enormemente la programación de redes, como los servidores de socket TCP y UDP, y el rendimiento y la seguridad son incluso mejores en muchos aspectos.
  3. Admite múltiples protocolos como FTP, SMTP, HTTP y varios protocolos tradicionales binarios y basados ​​en texto.

El resumen oficial es: Netty ha encontrado con éxito una manera de lograr facilidad de desarrollo, rendimiento, estabilidad y flexibilidad sin comprometer la capacidad de mantenimiento y el rendimiento.
Además de lo anterior, muchos proyectos de código abierto, como Dubbo, RocketMQ, Elasticsearch, gRPC, etc., de uso común, usan Netty.

¿Por qué usar Netty?

Porque Netty tiene las siguientes ventajas y es más fácil de usar que usar directamente la API relacionada con NIO que viene con el JDK.

  • La API unificada admite múltiples tipos de transmisión, con bloqueo y sin bloqueo.
  • Modelo de subprocesamiento simple y potente.
  • El códec incorporado resuelve el problema de pegado / desempaquetado de TCP.
  • Viene con varias pilas de protocolos.
  • Verdadero soporte de socket de paquetes sin conexión.
  • En comparación con el uso directo de la API central de Java, tiene un mayor rendimiento, menor latencia, menor consumo de recursos y menos copia de memoria.
  • La seguridad es buena, con compatibilidad completa con SSL / TLS y StartTLS.
  • Comunidad activa
  • Es maduro y estable, y ha sido utilizado y probado por proyectos a gran escala, y muchos proyectos de código abierto han utilizado Netty, como Dubbo, RocketMQ, etc., con los que contactamos a menudo.

¿Entiende los escenarios de aplicación de Netty?

En teoría, lo que NIO puede hacer se puede hacer con Netty y mejor. Netty se utiliza principalmente para la comunicación en red:

  1. Como herramienta de comunicación de red del marco RPC: en un sistema distribuido, los diferentes nodos de servicio a menudo necesitan llamarse entre sí. En este momento, se necesita el marco RPC. ¿Cómo se realiza la comunicación entre los diferentes nodos de servicio? Puedes usar Netty para hacerlo. Por ejemplo, si llamo a un método de otro nodo, al menos debo informar a la otra parte qué método en qué clase estoy llamando y los parámetros relacionados.
  2. Implementar un servidor HTTP propio: Podemos implementar un servidor HTTP simple por nosotros mismos a través de Netty, que debería ser familiar para todos. Hablando de servidor HTTP, como desarrollo de back-end de Java, generalmente usamos más Tomcat. Un servidor HTTP básico puede manejar solicitudes de métodos HTTP comunes, como solicitudes POST, solicitudes GET, etc.
  3. Implementar un sistema de mensajería instantánea: Usando Netty, podemos implementar un sistema de mensajería instantánea que puede chatear similar a WeChat. Hay muchos proyectos de código abierto en esta área. Puedes ir a Github para encontrarlo tú mismo.
  4. Realice el sistema de envío de mensajes: hay muchos sistemas de envío de mensajes en el mercado que se basan en Netty.

¿Cuáles son los componentes centrales de Netty? ¿Cuál es el papel de cada uno?

1. La
interfaz Channel Channel es una clase abstracta de Netty para operaciones de red. Incluye operaciones de E / S básicas como bind (), connect (), read (), write (), etc.

Las clases de implementación de interfaz de canal más comúnmente utilizadas son NioServerSocketChannel (servidor) y NioSocketChannel (cliente) Estos dos canales pueden corresponder a los dos conceptos de ServerSocket y Socket en el modelo de programación BIO. La API proporcionada por la interfaz del canal de Netty reduce en gran medida la complejidad de usar directamente la clase Socket.

2. EventLoop
¡Se puede decir que la interfaz EventLoop (bucle de eventos) es el concepto más básico de Netty! "EventLoop define la abstracción central de Netty, que se utiliza para procesar eventos que ocurren en el ciclo de vida de la conexión. Para decirlo sin rodeos, la función principal de EventLoop es en realidad monitorear eventos de red y llamar a los controladores de eventos para procesar I / O operaciones.

¿Cuál es la conexión directa entre Channel y EventLoop?
El canal es una clase abstracta de operaciones de red de Netty (operaciones de lectura y escritura). EventLoop es responsable de procesar el canal registrado en él para procesar las operaciones de E / S, y los dos cooperan para participar en las operaciones de E / S.

3. ChannelFuture
Netty es asíncrono y sin bloqueo, y todas las operaciones de E / S son asíncronas.

Por lo tanto, no podemos obtener el éxito de la operación de inmediato, pero puede registrar un ChannelFutureListener a través del método addListener () de la interfaz ChannelFuture. Cuando la operación tiene éxito o falla, el oyente activará automáticamente el resultado devuelto. Además, puede obtener el canal asociado a través del método channel () de ChannelFuture. Además, también podemos hacer que las operaciones asincrónicas sean síncronas a través del método sync () de la interfaz ChannelFuture.

4. ChannelHandler y ChannelPipeline
El siguiente código no debería ser desconocido para aquellos que han usado Netty Hemos especificado un códec de serialización y un ChannelHandler personalizado para procesar mensajes.

b.group(eventLoopGroup) .handler(new ChannelInitializer<SocketChannel>() {
    
     
@Override protected void initChannel(SocketChannel ch) {
    
     
	ch.pipeline().addLast(new NettyKryoDecoder(kryoSerializer, RpcResponse.class)); 
	ch.pipeline().addLast(new NettyKryoEncoder(kryoSerializer, RpcRequest.class)); 
	ch.pipeline().addLast(new KryoClientHandler()); 
	} 
});

ChannelHandler es el procesador concreto del mensaje. Es responsable de manejar operaciones de lectura y escritura, conexiones de clientes y otras cosas. ChannelPipeline es una cadena de ChannelHandlers que proporciona un contenedor y define API para propagar flujos de eventos entrantes y salientes a lo largo de la cadena. Cuando se crea un canal, se asignará automáticamente a su canal de canal dedicado. Podemos agregar uno o más ChannelHandlers en ChannelPipeline a través del método addLast (), porque varios Handlers pueden procesar un dato o un evento. Cuando se procesa un ChannelHandler, los datos se entregan al siguiente ChannelHandler.

EventloopGroup entiende ¿Cuál es la relación con EventLoop?

Inserte la descripción de la imagen aquí

EventLoopGroup contiene múltiples EventLoops (cada EventLoop generalmente contiene un hilo en su interior). Como dijimos anteriormente, la función principal de EventLoop es realmente responsable de monitorear los eventos de red y llamar a los controladores de eventos para procesar las operaciones de E / S relacionadas.

Y los eventos de E / S manejados por EventLoop se procesarán en su Thread dedicado, es decir, Thread y EventLoop pertenecen a una relación 1: 1, lo que garantiza la seguridad de los subprocesos.

La figura anterior es un diagrama de bloques general del EventLoopGroup usado por el servidor, en el que Boss EventloopGroup se usa para recibir conexiones, y Worker EventloopGroup se usa para procesamiento específico (leer y escribir mensajes y otro procesamiento lógico).

Como se puede ver en la figura anterior: cuando el cliente se conecta al servidor a través del método de conexión, bossGroup procesa la solicitud de conexión del cliente. Cuando se completa el procesamiento del cliente, la conexión se enviará al grupo de trabajadores para su procesamiento, y luego el grupo de trabajadores es responsable de procesar sus operaciones relacionadas con IO.

¿Conoce Bootstrap y ServerBootstrap?

Bootstrap es la clase de arranque de inicio / clase auxiliar del cliente. Los métodos de uso específicos son los siguientes:

EventLoopGroup group = new NioEventLoopGroup (); try {// Cree una clase auxiliar / de arranque de cliente: Bootstrap Bootstrap b = new Bootstrap (); // Especifique el modelo de hilo b.group (grupo).… // Intente establecer una conexión ChannelFuture f = b.connect (host, port) .sync (); f.channel (). CloseFuture (). Sync ();} finalmente {// Cierre con gracia los recursos del grupo de subprocesos relacionados group.shutdownGracefully ();}

La clase de arranque / clase auxiliar del cliente ServerBootstrap, el método de uso específico es el siguiente:

// 1.bossGroup se usa para recibir conexiones, workerGroup se usa para procesamiento específico EventLoopGroup bossGroup = new NioEventLoopGroup (1); EventLoopGroup workerGroup = new NioEventLoopGroup (); try {// 2. Crear servidor de arranque / clase auxiliar: ServerBootstrap ServerBootstrap b = new ServerBootstrap (); // 3. Configure dos grupos de subprocesos para la clase de arranque y determine el modelo de subproceso b.group (bossGroup, workerGroup).… // 6. Vincular el puerto ChannelFuture f = b.bind (puerto). sync (); // Espera a que se cierre la conexión f.channel (). closeFuture (). sync ();} finalmente {// 7. Cierra con gracia los recursos del grupo de subprocesos relacionados bossGroup.shutdownGracefully (); workerGroup.shutdownGracefully ( );}}

En el ejemplo anterior, podemos ver:

  1. Bootstrap generalmente usa el método connet () para conectarse a un host y puerto remotos como cliente en la comunicación del protocolo TCP de Netty. Además, Bootstrap también puede vincular un puerto local a través del método bind () como un extremo de la comunicación del protocolo UDP.
  2. ServerBootstrap generalmente usa el método bind () para vincularse al puerto local y luego espera a que el cliente se conecte.
  3. Bootstrap solo necesita configurar un grupo de subprocesos, EventLoopGroup, mientras que ServerBootstrap necesita configurar dos grupos de subprocesos, EventLoopGroup, uno para recibir conexiones y otro para procesamiento específico.

¿Cuántos subprocesos iniciará el constructor predeterminado de NioEventLoopGroup?

// 1.bossGroup se usa para recibir conexiones, workerGroup se usa para procesamiento específico EventLoopGroup bossGroup = new NioEventLoopGroup (1); EventLoopGroup workerGroup = new NioEventLoopGroup ();

Para saber cuántos subprocesos crea el constructor predeterminado de NioEventLoopGroup, echemos un vistazo a su código fuente.

/ ** * Constructor sin argumentos. * nThreads: 0 / public NioEventLoopGroup () {// Llame al siguiente método de construcción this (0);} / * * Ejecutor: null / public NioEventLoopGroup (int nThreads) {// Continúe llamando al siguiente método de construcción this (nThreads, (Executor) null);} // Parte del constructor se omite en el medio / * * RejectedExecutionHandler (): RejectedExecutionHandlers.reject () * / public NioEventLoopGroup (int nThreads, Executor ejecutor, final SelectorProvider selectorProvider, final SelectStrategyFactory selectStrategy // Comienza a llamar al padre El constructor de la clase super (nThreads, ejecutor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject ());}

Si recorre todo el camino hacia abajo, encontrará el código relevante para especificar el número de subprocesos en la clase MultithreadEventLoopGroup, de la siguiente manera:

// De 1, las propiedades del sistema, el número de núcleos de CPU , tome el mayor de los tres valores // Puede obtener el valor de DEFAULT_EVENT_LOOP_THREADS como el número de núcleos de CPU 2 privado estático final int DEFAULT_EVENT_LOOP_THREADS = Math. max (1, SystemPropertyUtil.getInt ("Io.netty.eventLoopThreads", NettyRuntime.availableProcessors () * 2)); // El constructor de la clase padre que se llama, el constructor predeterminado de NioEventLoopGroup tendrá el secreto de cuántos hilos / / Cuando el número especificado de subprocesos nThreads es 0 Cuando se utiliza el número predeterminado de subprocesos DEFAULT_EVENT_LOOP_THREADS protected MultithreadEventLoopGroup (int nThreads, ThreadFactory threadFactory, Object ... args) {super (nThreads == 0? DEFAULT_EVENT_LOOP_THREADS, thread); }

En resumen, encontramos que el número de subprocesos realmente iniciados por el constructor predeterminado de NioEventLoopGroup es el número de núcleos de CPU * 2.

Además, si continúa profundizando y observa el constructor, encontrará que cada objeto NioEventLoopGroup asignará un grupo de NioEventLoops, cuyo tamaño es nThreads, que constituye un grupo de subprocesos, y un NIOEventLoop corresponde a un subproceso, que nos corresponde La relación entre EventloopGroup y EventLoop mencionada anteriormente corresponde a esta parte.

¿Entiendes el modelo de subprocesamiento de Netty?

La mayoría de los marcos de red se diseñan y desarrollan basándose en el patrón Reactor.

"El modo Reactor se basa en eventos controlados y utiliza multiplexación para distribuir eventos al Handler correspondiente para su procesamiento, que es muy adecuado para manejar escenarios de E / S masivos.

Netty se basa principalmente en el grupo de subprocesos NioEventLoopGroup para implementar el modelo de subprocesamiento específico.
Cuando implementamos el servidor, generalmente inicializamos dos grupos de subprocesos:

  1. bossGroup: Recibir conexión.
  2. workerGroup: Responsable del procesamiento específico, que es manejado por el Handler correspondiente.

1. Modelo de un solo subproceso:
un subproceso debe ejecutar y procesar todos los eventos de aceptación, lectura, decodificación, proceso, codificación y envío. No es aplicable a escenarios con alta carga, alta simultaneidad y requisitos de alto rendimiento.

El código Netty correspondiente es el siguiente

"Utilice el constructor sin parámetros de la clase NioEventLoopGroup para establecer el valor predeterminado del número de subprocesos como el número de núcleos de CPU * 2.

//1.eventGroup no solo se usa para manejar conexiones de clientes, sino que también es responsable de un procesamiento específico. EventLoopGroup eventGroup = new NioEventLoopGroup (1); // 2. Cree una clase auxiliar / de arranque del servidor: ServerBootstrap ServerBootstrap b = new ServerBootstrap (); boobtstrap.group (eventGroup, eventGroup) // ...

2. Modelo de subprocesos múltiples
Un subproceso Acceptor solo es responsable de monitorear las conexiones del cliente, y un grupo de subprocesos NIO es responsable del procesamiento específico: aceptar, leer, decodificar, procesar, codificar y enviar eventos. Cumple con la mayoría de los escenarios de aplicación.Cuando el número de conexiones simultáneas es pequeño, no hay problema, pero cuando el número de conexiones simultáneas es grande, pueden surgir problemas y convertirse en un cuello de botella en el rendimiento.

El código Netty correspondiente es el siguiente:

// 1.bossGroup se usa para recibir conexiones, workerGroup se usa para procesamiento específico EventLoopGroup bossGroup = new NioEventLoopGroup (1); EventLoopGroup workerGroup = new NioEventLoopGroup (); try {// 2. Crear servidor de arranque / clase auxiliar: ServerBootstrap ServerBootstrap b = new ServerBootstrap (); // 3. Configure dos grupos de subprocesos para la clase de arranque y determine el modelo de subproceso b.group (bossGroup, workerGroup) // ...
Inserte la descripción de la imagen aquí

3. Modelo de múltiples subprocesos maestro-esclavo
Seleccione un subproceso de un grupo de subprocesos NIO del subproceso principal como subproceso aceptor, enlace el puerto de escucha, reciba conexiones de cliente y otros subprocesos son responsables de la autenticación de acceso posterior y otras tareas. Una vez establecida la conexión, el grupo de subprocesos NIO es responsable del procesamiento específico de lectura y escritura de E / S. Si el modelo de subprocesos múltiples no puede satisfacer sus necesidades, puede considerar utilizar el modelo de subprocesos múltiples maestro-esclavo.

// 1.bossGroup se usa para recibir conexiones, workerGroup se usa para procesamiento específico EventLoopGroup bossGroup = new NioEventLoopGroup (); EventLoopGroup workerGroup = new NioEventLoopGroup (); try {// 2. Crear servidor de arranque / clase auxiliar: ServerBootstrap ServerBootstrap b = new ServerBootstrap (); // 3. Configure dos grupos de subprocesos para la clase de arranque y determine el modelo de subproceso b.group (bossGroup, workerGroup) // ...
Inserte la descripción de la imagen aquí

¿Entiende el proceso de inicio del servidor y el cliente de Netty?

Servidor

shutdownGracefully (); }

Analice brevemente cómo es el proceso de creación del servidor:
1. Primero, crea dos instancias de objeto NioEventLoopGroup: bossGroup y workerGroup.

  • bossGroup: se utiliza para procesar la solicitud de conexión TCP del cliente.
  • workerGroup: Responsable de la lógica de procesamiento de datos de lectura y escritura específicos para cada conexión, y es realmente responsable de las operaciones de lectura y escritura de E / S, que son manejadas por el Handler correspondiente.

Por ejemplo: tratamos al jefe de la empresa como el grupo de jefes y a los empleados como el grupo de trabajadores. Una vez que el grupo de jefes recoge el trabajo en el exterior, se envía al grupo de trabajadores para su procesamiento. En circunstancias normales, especificaremos el número de subprocesos del bossGroup como 1 (cuando el número de conexiones simultáneas no es grande), y el número de subprocesos del workGroup es el número de núcleos de CPU * 2. Además, de acuerdo con el código fuente, usando el constructor sin parámetros de la clase NioEventLoopGroup para establecer el valor predeterminado del número de subprocesos es el número de núcleos de CPU * 2.

2. A continuación, creamos una clase auxiliar / de arranque del servidor: ServerBootstrap, esta clase nos guiará para iniciar el servidor.

3. Configure dos grupos de subprocesos para la clase de arranque ServerBootstrap a través del método .group () para determinar el modelo de subproceso.
A través del siguiente código, realmente configuramos el modelo multiproceso, que se mencionó anteriormente.

EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup();

4. El modelo IO de la clase de arranque ServerBootstrap se especifica como NIO a través del método channel ()

  • NioServerSocketChannel: especifique el modelo IO del servidor como NIO, que corresponde al ServerSocket en el modelo de programación BIO
  • NioSocketChannel: especifique el modelo IO del cliente como NIO, que corresponde al Socket en el modelo de programación BIO. 5. Cree un ChannelInitializer para la clase de arranque a través de .childHandler (), y luego formule la lógica de procesamiento del servicio del objeto HelloServerHandler del mensaje del servidor 6 . Llame al método bind () de la clase ServerBootstrap para vincular el puerto

Cliente

// 1. Cree una instancia de objeto NioEventLoopGroup EventLoopGroup group = new NioEventLoopGroup (); try {// 2. Cree una clase auxiliar / de arranque de cliente: Bootstrap Bootstrap b = new Bootstrap (); // 3. Especifique el grupo de subprocesos b. Group (grupo) // 4. Especifique el modelo de E / S. channel (NioSocketChannel.class) .handler (new ChannelInitializer () {@Override public void initChannel (SocketChannel ch) throws Exception {ChannelPipeline p = ch.pipeline (); // 5 . Aquí puede personalizar la lógica de procesamiento comercial del mensaje p.addLast (new HelloClientHandler (mensaje));}}); // 6. Intente establecer una conexión ChannelFuture f = b.connect (host, port) .sync ( ); // 7. Esperar a que se cierre la conexión (bloquear hasta que el Canal se cierre) f.channel (). CloseFuture (). Sync ();} finalmente {group.shutdownGracefully ();}

Continuar analizando el proceso de creación del cliente

  1. Cree una instancia de objeto NioEventLoopGroup
  2. La clase de arranque para crear el inicio del cliente es Bootstrap
  3. Configure un grupo de subprocesos para la clase de arranque Bootstrap a través del método .group ()
  4. El modelo IO de Bootstrap se especifica como NIO a través del método channel ()
  5. Cree un ChannelInitializer para la clase de arranque a través de .childHandler () y luego formule la lógica de procesamiento empresarial del objeto HelloClientHandler del mensaje del cliente.
  6. Llame al método connect () de la clase Bootstrap para conectarse. Este método necesita especificar dos parámetros:
    • inetHost: dirección IP
    • inetPort: número de puerto
    • public ChannelFuture connect (String inetHost, int inetPort) {devolver this.connect (InetSocketAddress.createUnresolved (inetHost, inetPort)); } public ChannelFuture connect (SocketAddress remoteAddress) {ObjectUtil.checkNotNull (remoteAddress, “remoteAddress”); this.validate (); return this.doResolveAndConnect (remoteAddress, this.config.localAddress ()); }

El método de conexión devuelve una interfaz pública de objeto de tipo Future ChannelFuture extiende Future {…} es decir, esta parte es asíncrona, podemos monitorear si la conexión es exitosa a través del método addListener y luego imprimir la información de conexión. El método específico es muy simple, solo necesita hacer los siguientes cambios en el código: ChannelFuture f = b.connect (host, port) .addListener (future -> {if (future.isSuccess ()) {System.out.println ("¡Conectado correctamente!");} Else {System.err.println ("¡Conexión fallida!");}}). Sync (); ¿Qué es TCP pegado / desempaquetado? ¿Hay alguna solución?

¿Qué es TCP pegado / desempaquetado?

El pegado / desempaquetado de TCP es cuando envía datos basados ​​en TCP, varias cadenas se "pegan" juntas o una cadena se "desensambla". Por ejemplo, envía repetidamente: "¡Hola, eres tan guapo! ¡Hermano!", Pero el cliente puede recibir algo como lo siguiente
Inserte la descripción de la imagen aquí

1. Utilice el decodificador integrado de Netty

  • LineBasedFrameDecoder: cuando el remitente envía paquetes de datos, cada paquete de datos está separado por un carácter de nueva línea. El principio de funcionamiento de LineBasedFrameDecoder es que atraviesa los bytes legibles en ByteBuf a su vez, determina si hay un carácter de nueva línea y luego realiza la intercepción correspondiente.
  • DelimiterBasedFrameDecoder: El decodificador DelimiterBasedFrameDecoder se puede personalizar. LineBasedFrameDecoder es en realidad un decodificador especial DelimiterBasedFrameDecoder.
  • FixedLengthFrameDecoder: decodificador de longitud fija, que puede descomprimir el mensaje de acuerdo con la longitud especificada.
  • LengthFieldBasedFrameDecoder

2. Códec de serialización personalizado
En Java viene con la implementación de la interfaz Serializable para lograr la serialización, pero debido a su rendimiento, seguridad y otras razones, no se utilizará en circunstancias normales. En circunstancias normales, utilizamos más métodos de secuencia Protostuff, Hessian2, json, y hay algunos métodos de serialización con muy buen rendimiento de serialización que también son buenas opciones:

  • Específicamente para el lenguaje Java: Kryo, FST, etc.
  • Lenguaje cruzado: Protostuff (desarrollado en base a protobuf), ProtoBuf, Thrift, Avro, MsgPack, etc.

¿Entiendes la conexión prolongada y el mecanismo de los latidos del corazón de Netty?

¿Entiende las conexiones TCP largas y cortas?
Sabemos que antes de que TCP lea y escriba, se debe establecer una conexión de antemano entre el servidor y el cliente. El proceso de establecer una conexión requiere el apretón de manos de tres vías que solemos decir, y se requieren cuatro movimientos de manos para liberar / cerrar la conexión. Este proceso consume recursos de la red y tiene un retraso de tiempo.

La llamada conexión corta significa que después de que el lado del servidor establece una conexión con el lado del cliente, la conexión se cierra después de que se completan la lectura y la escritura. Si el mensaje se va a enviar entre sí la próxima vez, se requiere la conexión. La conexión corta es un poco obvia, es decir, la administración y la implementación son relativamente simples, y las deficiencias también son obvias. El establecimiento de una conexión para cada lectura y escritura conducirá inevitablemente al consumo de una gran cantidad de recursos de red. y el establecimiento de la conexión también lleva tiempo.

Conexión larga significa que después de que el cliente establece una conexión con el servidor, incluso si el cliente y el servidor completan una lectura y escritura, la conexión entre ellos no se cerrará activamente y las operaciones de lectura y escritura posteriores continuarán usando esta conexión. Las conexiones largas pueden ahorrar más operaciones de establecimiento y cierre de TCP, reducir la dependencia de los recursos de la red y ahorrar tiempo. Para los clientes que solicitan recursos con frecuencia, las conexiones largas son muy adecuadas.

¿Por qué necesitamos un mecanismo de latido del corazón? ¿Entiendes el mecanismo de salto central de Netty?

En el proceso de que TCP mantiene una conexión larga, pueden ocurrir anomalías en la red, como la desconexión de la red. Cuando ocurre la anomalía, si no hay interacción entre el cliente y el servidor, no podrán encontrar que la otra parte se ha desconectado . Para resolver este problema, necesitamos introducir un mecanismo de latido. El principio de funcionamiento del mecanismo de latido es: cuando no hay interacción de datos entre el cliente y el servidor durante un cierto período de tiempo, es decir, cuando está en estado inactivo, el cliente o servidor enviará un paquete de datos especial al otro parte, y cuando el receptor recibe estos datos Después de que se envía el mensaje, también se envía inmediatamente un mensaje de datos especiales para responder al remitente, que es una interacción PING-PONG. Por lo tanto, cuando un extremo recibe el mensaje de latido, sabe que la otra parte todavía está en línea, lo que garantiza la validez de la conexión TCP. De hecho, TCP tiene su propia opción de conexión larga y también tiene un mecanismo de paquete de latido, que es decir, Opciones de TCP: SO_KEEPALIVE. Sin embargo, la larga flexibilidad de conexión a nivel de protocolo TCP no es suficiente. Por lo tanto, en general, implementamos un mecanismo de latido personalizado en el protocolo de la capa de aplicación, es decir, mediante la codificación en el nivel de Netty. Si el mecanismo de latido se implementa a través de Netty, la clase principal es IdleStateHandler.

¿Entiendes la copia cero de Netty?

"La tecnología de copia cero (en inglés: copia cero; también traducida como copia cero) significa que cuando una computadora realiza una operación, la CPU no necesita copiar primero los datos de una determinada memoria a otra área específica. Esta tecnología se usa generalmente para transferir archivos a través de una red Ahorro de tiempo en ciclos de CPU y ancho de banda de memoria.

La copia cero en el nivel del sistema operativo generalmente se refiere a evitar copiar datos entre el espacio de usuario y el espacio del kernel. A nivel de Netty, la copia cero se refleja principalmente en la optimización de las operaciones de datos.

La copia cero en Netty se refleja en los siguientes aspectos:

  1. Usando la clase CompositeByteBuf proporcionada por Netty, se pueden fusionar múltiples ByteBufs en un ByteBuf lógico, evitando la copia entre cada ByteBuf.
  2. ByteBuf admite la operación de corte, por lo que ByteBuf se puede descomponer en varios ByteBuf que comparten la misma área de almacenamiento, evitando la copia de memoria.
  3. La transferencia de archivos se realiza a través de FileChannel.tranferTo envuelto por FileRegion, que puede enviar directamente los datos en el búfer de archivos al canal de destino, evitando el problema de copia de memoria causado por el método tradicional de escritura circular.

Supongo que te gusta

Origin blog.csdn.net/CSDN877425287/article/details/114505079
Recomendado
Clasificación