Diseño de modelo de alta concurrencia de una sola máquina
Cómo atender a 10.000 usuarios y 10.000 usuarios en una computadora física al mismo tiempo no es difícil para los programadores de Java. netty se puede utilizar para crear programas de servidor que admitan más de 10.000 concurrencias. Entonces, ¿cómo lo logra Netty? Primero, olvidemos a Netty y comencemos desde cero.
Una conexión por usuario significa dos cosas para el servidor.
Tomemos como ejemplo una conexión TCP común.
[Error en la carga de la imagen...(Picture-12267d-1657 446196326)]
Una imagen muy familiar. Este artículo se centra en el análisis del servidor, por lo que ignoraremos los detalles del cliente por ahora.
El servidor se prepara creando un socket, vinculando un puerto y escuchando. Finalmente establecer una conexión con el cliente mediante aceptar. Obtenga un connectFd, un socket de conexión (que es un descriptor de archivo en Linux) para identificar de forma única una conexión. En esto se basa la posterior transmisión de datos.
[Error en la carga de la imagen...(Image-c 9c 08 f-1657 446196326)]
Para transferir datos, el servidor abre un hilo para procesar los datos. El proceso específico es el siguiente:
Debido a que un hilo procesa los datos de una conexión, el modelo de hilo correspondiente es así.
[Error en la carga de la imagen...(Imagen-47A 077-1657 446196326)]
Porque una transmisión de conexión y un subproceso requieren demasiados subprocesos y ocupan más recursos. Al mismo tiempo, la conexión finaliza y el recurso se destruye. Tenemos que reconectarnos. Entonces una idea natural es reutilizar hilos. Es decir, varias conexiones utilizan el mismo hilo. Esto plantea una pregunta,
A la entrada de la transmisión de datos, se supone que el hilo está procesando los datos de una conexión, pero los datos no han sido buenos porque la selección está bloqueada, por lo que incluso si otros Las conexiones tienen datos para leer, pero tampoco puedo leerlos. Por lo tanto, no se puede bloquear; de lo contrario, varias conexiones no pueden usar un hilo. Por eso no debe bloquearse.
Después de cambiar a sin bloqueo, la aplicación necesita sondear continuamente el espacio del kernel para determinar si la conexión está lista.
El sondeo es ineficiente y consume mucha CPU, por lo que una práctica común es que la persona que llama envíe notificaciones de eventos para notificar a la persona que llama, en lugar de que la persona que llama sondee todo el tiempo. Esta es la multiplexación IO, que se refiere a enchufes de conexión y entrada estándar. Al registrar previamente un lote de sockets en un grupo, cuando hay eventos de IO en este grupo, se notifica al objeto de bloqueo que está listo.
La tecnología de reutilización de IO generalmente se implementa mediante selección y sondeo. No hay mucha diferencia entre seleccionar y sondear, principalmente porque la encuesta no tiene un límite máximo de descriptores de archivos.
Desde el sondeo hasta la notificación de eventos, después de utilizar la optimización de IO multiplexada, aunque la aplicación no tiene que sondear el espacio del kernel todo el tiempo. Sin embargo, después de recibir una notificación de evento desde el espacio del kernel, la aplicación no sabe qué evento de conexión correspondiente es y debe atravesarlo.
Se puede predecir que a medida que aumente el número de conexiones, el consumo de tiempo aumentará proporcionalmente. En comparación con poll, que devuelve el número de eventos, epoll devuelve una matriz connectFd con eventos, evitando así el sondeo de la aplicación.
Por supuesto, el alto rendimiento de epoll no es solo esto, sino también la activación de bordes, que no se describirá en este artículo.
El proceso de clasificación de IO+multiplexación sin bloqueo es el siguiente:
[Error en la carga de la imagen...(Imagen-b 5192 c-1657 446196326)]
Arriba, solucionamos principalmente problemas de lectura y selección local mediante IO multiplexada y sin bloqueo. Reorganicemos todo el proceso y veamos cómo se agrupa todo el proceso de procesamiento de datos. Esta etapa es manejada por un grupo de subprocesos diferente para mayor eficiencia.
En primer lugar, existen dos tipos de eventos.
El proceso de procesamiento de eventos de conexión es relativamente fijo, sin lógica adicional y sin necesidad de más divisiones.
Los eventos de transmisión leídos y enviados son relativamente fijos y la lógica de procesamiento de cada conexión es similar, por lo que se pueden procesar en un grupo de subprocesos. La decodificación lógica específica y la codificación lógica tienen una lógica de procesamiento de conexión diferente. El conjunto se puede procesar en un grupo de subprocesos.
El servidor está dividido en tres partes.
Debido a que 1 y 2 son más rápidos, se procesan en el grupo de subprocesos y la lógica empresarial se procesa en otro grupo de subprocesos.
Lo anterior es el famoso modelo de reactor de alta concurrencia.