Red de conocimiento informático - Aprendizaje de programación - ¿Existe un límite en la cantidad de descriptores en los archivos de monitoreo de libevent?

¿Existe un límite en la cantidad de descriptores en los archivos de monitoreo de libevent?

1. El problema del C10K

El problema del C10K se planteó en los años 1990. Cuando el número de usuarios supera los 10.000, el rendimiento de muchos programas de servicios de red mal diseñados disminuirá drásticamente o incluso se paralizará. Además, este problema no se puede solucionar actualizando el equipo de hardware. Es un problema inherente al sistema operativo. En otras palabras, si su servidor puede admitir hasta 1000 concurrencias, incluso si actualiza la CPU al doble de potencia informática, el doble de memoria y el doble de velocidad del disco duro, no podrá admitir 2000 concurrencias.

Existen cuatro modelos clásicos de programación de redes:

1. Cada hilo/proceso sirve a un cliente y utiliza E/S de bloqueo. Es decir, cada cliente es atendido por diferentes hilos o. procesos y utilizar bloqueo de E/S en cada hilo o proceso. Esta es una estrategia común para programas pequeños y Java, y también es una opción común para aplicaciones interactivas. Esta estrategia es difícil de satisfacer las necesidades de programas de alto rendimiento. Su ventaja es que es extremadamente simple de implementar y puede implementar fácilmente una lógica de interacción compleja. Apache, ftpd, etc. , comúnmente usamos este tipo de trabajo.

2. Utilice un único hilo para atender a varios clientes, utilizando E/S sin bloqueo y notificaciones listas. Es decir, todos los clientes son atendidos por un hilo o proceso, utilizando una estrategia de IO asíncrona. Este es un modelo clásico con una implementación simple, un trasplante conveniente y un rendimiento suficiente. La desventaja es que no puede utilizar completamente los recursos de varias CPU.

3. Cada subproceso atiende a múltiples clientes. El uso de E/S desbloqueadas y notificaciones de lectura es una mejora simple con respecto al modelo clásico 2. El modelo clásico 2 todavía usa la estrategia de E/S asíncrona, pero utiliza múltiples subprocesos o procesos para servir. todos los clientes. La desventaja es que es fácil tener errores en la concurrencia de subprocesos múltiples y algunos sistemas operativos ni siquiera admiten la notificación de preparación de subprocesos múltiples.

4. Cada subproceso sirve a muchos clientes y el uso de E/S asincrónicas puede proporcionar un rendimiento bastante alto en sistemas operativos que admiten AI/O. Sin embargo, el modelo de programación AI/O es muy diferente del modelo clásico, por lo que es básicamente difícil escribir un marco que admita tanto AI/O como el modelo clásico. Este modelo se utiliza principalmente en plataformas de ventanas.

Para desarrollar aplicaciones de red de alto rendimiento en Linux, sólo puedes elegir el segundo y tercer método. Teniendo en cuenta la complejidad, tendemos a utilizar sólo la segunda opción. Analicemos el segundo modo.

Sabemos que la IO asincrónica generalmente se implementa mediante selección o encuesta. La definición de selección es la siguiente:

int select(int n, fd_set *rd_fds, fd_set *wr_fds, fd_set *ex_fds, struct time val * time out);

La votación La interfaz es la siguiente:

int poll(struct pollfd *ufds, unsigned int nfds, int time out);

Sin embargo, cuando aumenta el número de conexiones, el rendimiento de selección y las encuestas disminuirán drásticamente. Hay dos razones: primero, el sistema operativo necesita restablecer una lista de eventos de interés para el subproceso actual para cada operación de selección/sondeo y colgar el subproceso en esta compleja cola de espera, lo cual requiere bastante tiempo. En segundo lugar, después de que regresa la selección/encuesta, el software de la aplicación también necesita escanear la lista de identificadores entrantes para determinar qué identificadores están disponibles, lo que también requiere mucho tiempo. Estas dos cosas están relacionadas con la cantidad de concurrencia, y la densidad de eventos de E/S también está relacionada con la cantidad de concurrencia. Esto da como resultado que la relación aproximada entre el uso de la CPU y la cantidad de concurrencia sea O (n2).

Con base en las razones anteriores, se desarrollaron en Unix tres interfaces de programa de mayor rendimiento, epoll, kqueue y /dev/poll, para resolver los problemas anteriores. Entre ellos, epoll es la solución para Linux, kqueue es la solución para freebsd y /dev/poll es la solución más antigua para Solaris, que se está volviendo cada vez más difícil de usar.

En pocas palabras, estas API hacen dos cosas:

1. Evita la sobrecarga de configurar la estructura de espera de eventos a través de los parámetros de análisis del kernel cada vez que se llama a select/poll. El kernel mantiene una lista de vigilancia de eventos a largo plazo y las aplicaciones modifican esta lista para capturar eventos de E/S a través de identificadores.

2. Evita la sobrecarga de la aplicación al escanear toda la tabla de identificadores después de que regresa la selección/encuesta, y el kernel devuelve directamente la lista de eventos específicos a la aplicación.

Dos. biblioteca libevent

Debido a que epoll, kqueue y /dev/poll tienen sus propias características, es muy difícil trasplantar programas. Por lo tanto, estas interfaces deben encapsularse para que sean fáciles de usar y trasplantar. La biblioteca libevent es una de ellas.

Según el sitio web oficial de libevent, la biblioteca libevent proporciona las siguientes funciones: cuando ocurre un evento específico de un descriptor de archivo (como legible, escribible o de error), o cuando ocurre un evento programado, libevent ejecutará automáticamente la función Especificar la devolución de llamada del usuario para manejar el evento. Actualmente, libevent admite las siguientes interfaces /dev/poll, kqueue (2), eventports, select (2), poll (2), epoll (4). El mecanismo de eventos interno de Libevent se basa completamente en la interfaz utilizada. Por lo tanto, libevent es muy fácil de portar y ampliar. Actualmente, libevent ha sido compilado en los siguientes sistemas operativos: Linux, BSD, Mac OS X, Solaris y Windows.

Es muy sencillo de desarrollar utilizando la biblioteca libevent y también es fácil de trasplantar en varias plataformas Unix. El siguiente es un programa sencillo que utiliza la biblioteca libevent:

3. solicitud. biblioteca libevent

El proxy Go2 es una aplicación proxy de alto tráfico, con un tráfico mensual de casi TB. Entre ellos, las imágenes, los archivos flash y zip representan la gran mayoría del tráfico total. Para reducir los costes del tráfico, es necesario desviar parte del tráfico. Al principio, se utilizó un proxy PHP tradicional para desviar el tráfico, pero el acceso simultáneo de Go2 era demasiado grande y PHP con una arquitectura multiproceso no pudo soportarlo. Se bloqueó inmediatamente después de iniciarse en el VPS del host virtual en unos pocos. artículos de segunda clase. Más tarde, cambié a la arquitectura de red retorcida de Python y adopté la función de comunicación TCP asíncrona de Twisted. Después de ejecutarlo durante un período de tiempo, descubrí que la estabilidad del DNS asíncrono retorcido no era muy buena y que a menudo se producían fallas a nivel del sistema. Finalmente, después del análisis y la comparación, decidimos utilizar la biblioteca libevent como aplicación de proxy de desvío de Go2.

La biblioteca Libevent admite sockets asíncronos y dns asíncronos, y también tiene un servidor http simple. La aplicación de agente distribuido de Go2 utiliza las tres funciones anteriores de la biblioteca libevent.

1. Servidor http simple: realiza la gestión de entrada y salida de agentes jerárquicos.

2. Sockets asíncronos para lograr un alto acceso simultáneo de usuarios y un alto acceso simultáneo al servidor de destino.

3. El DNS asincrónico resuelve la concurrencia y eficiencia de las consultas de DNS.