_______. _______.___ ___ .______ ____ ____ _______ .______
/ | / | / / | _ / / | ____|| _
| (----` | (----` V / | |_) | / / | |__ | |_) |
> < | / / | __| | /
.----) | .----) | / . | | ----. / | |____ | | ----.
|_______/ |_______/ /__/ __ | _| `._____| __/ |_______|| _| `._____|
SSXRVER es una biblioteca de red de alto rendimiento y de alto rendimiento que se ejecuta en la plataforma Linux. Está escrito en C ++ 17 y admite protocolos TCP y UDP.
Intente hacer coincidir el mismo entorno de desarrollo que yo. Si no necesita un módulo de base de datos, modifique cmakelists.txt en consecuencia.
Instalación de CMake
# debian/ubuntu
sudo apt-get install cmakeInstalación de la biblioteca Boost
wget http://sourceforge.net/projects/boost/files/boost/1.72.0/boost_1_72_0.tar.bz2
tar -xvf boost_1_72_0.tar.bz2
cd ./boost_1_72_0
./bootstrap.sh --prefix=/usr/local
sudo ./b2 install --with=allEjecutar ./build.sh En el directorio SSXRVER, puede modificar build.sh para elegir generar la versión de depuración o la versión de versión (la versión de versión predeterminada)
./build.shEl compilado compilará correctamente la compilación/ directorio, y el archivo ejecutable se encuentra en el directorio de versiones correspondiente. Por ejemplo, cuando selecciona la versión de versión, el archivo ejecutable está en/compilación/versión/ssxrver.
Imite el formato de conf/ssxrver.json.example para crear su archivo de configuración (tenga en cuenta que el archivo de configuración no se puede comentar, no comentarse, no comentarse). Explicaré las opciones de cada archivo de configuración a continuación. De hecho, establecí los valores predeterminados para muchos parámetros. Si no está configurado, no lo afectará.
{
" port " : 4507, # 端口号,不填的话默认4507
" address " : " 127.0.0.1 " , # 绑定的地址
" worker_processes " : 4, # IO 线程数量,不填默认为 4 个
" worker_connections " : -1, # 一个 IO 线程最多支持多少连接, -1 表示最多能创建多少就创建多少,不做限制
" task_processes " : 0, # 任务线程,不填的话默认为 0
" cpu_affinity " : " off " , # cpu 亲和度 ,默认关闭
" http " : { # http 模块
" max_body_size " : 67108864, # 单个 http 包最大支持大小
" root_path " : " /home/randylambert/sunshouxun/ssxrver/html/ " # 文件访问根路径
},
" log " : { # log 模块
" level " : " INFO " , # 输出等级,可填三种等级, DEBUG,INFO,WARN 不填默认为 INFO 等级
" ansync_started " : " off " , # 是否打开异步日志线程,不填默认关闭
" flush_second " : 3, # 异步线程每隔多久持久化一次
" roll_size " : 67108864, # 日志文件滚动大小
" path " : " /home/randylambert/sunshouxun/ssxrver/logs/ " , # 日志文件存放路径
" base_name " : " ssxrver " # 日志文件基础名
},
" mysql " : { # 数据库模块
" mysql_started " : " off " , # 是否打开数据库模块,默认关闭
" address " : " 127.0.0.1 " , # 以下是对应数据库连接信息
" user " : " root " ,
" password " : " 123456 " ,
" database_name " : " ttms " ,
" port " : 0,
" unix_socket " : null,
" client_flag " : 0
},
" blocks_ip " : [ " 122.0.0.2 " , " 198.1.2.33 " ] # 可屏蔽部分恶意 IP
}Ejecute el archivo ejecutable.
./ssxrver -f /配置文件的路径
# 例如
./build/Release/ssxrver -f ./conf/ssxrver.json| Entorno de prueba | Valor |
|---|---|
| Versión de peinado del sistema operativo | Deepin V20.1 Community Edition (1030) |
| Versión de kernel | 5.4.70-amd64-desktop (64 bits) |
| Versión compiladora | GCC 8.3 |
| Versión de Boost Library | 1.72 |
| procesador | Intel (R) Core (TM) i7-8750H CPU @2.20GHz |
| Tamaño de caché L1 | 32k |
| Tamaño de caché L2 | 256k |
| Tamaño de caché l3 | 9216K |
| Velocidad del disco duro | 1.8 TIB Mechanical Drip Drug 5400 RPM |
| Velocidad de lectura y escritura del disco duro | 370 MB en 3.03 segundos = 122.27 MB/seg |
| Memoria | 7.6 GB |
| Partición de intercambio | 4.7GB |
| Recuento de núcleo lógico | 12 núcleos |
Para controlar las variables, reinicie la computadora antes de probar para asegurarse de que el entorno de prueba no tenga otras aplicaciones con alta carga de CPU y alta carga IO.
La herramienta de prueba es WebBench1.5. Elimine los primeros datos de calentamiento. El comando de prueba es el siguiente (se ha accedido continuamente a 100 clientes durante 15 segundos).
./webbench -c 100 -t 15 http://127.0.0.1:8081/Los objetos de prueba son Apache/2.4.38, Nginx/1.14.2, SSXRVER.
Nota: Si usa Webbench o AB, los datos medidos por esta herramienta de medición de presión solo pueden usarse como una referencia simple. La medición de la presión es una prueba que requiere un ángulo completo y de ángulo múltiple, en lugar de simplemente ejecutar un comando. Incluso durante la medición de la presión, los datos no se transmiten a través de la red, sino que simplemente giran alrededor del núcleo.
| Biblioteca de red | Velocidad (páginas/min) | Solicitud de tasa de éxito |
|---|---|---|
| ssxrver Devuelve la respuesta generada en la memoria | 7107414 | 100% |
| ssxrver devuelve archivos estáticos | 5114376 | 100% |
| Apache/2.4.28 | 2884072 | 100% |
| nginx/1.14.2 | 4728748 | 100% |
Los resultados de las pruebas de SSXRVER son bastante buenos, pero extrañamente, pensé que los datos serían más altos, porque cuando me estaba desarrollando en los primeros días, no hice muchas optimizaciones en ese momento. Cuando devolví la respuesta generada directamente en la memoria, se midió como máximo cerca de 8000000 páginas/min (los resultados de la prueba de 8000000 páginas/min no se tomaron en capturas de pantalla, dejando un 7550778). En ese momento, Nginx/1.14.2 tenía un máximo de 5000000 páginas/min. Sin embargo, no importa si fue SSXRVER o NGINX/1.14.2, no pude encontrar un valor tan alto. No sé cuál fue la razón, lo que condujo a una brecha tan grande en el resultado final (¿es porque mi computadora está envejeciendo?  ̄ □  ̄||)
En la actualidad, personalmente modificaré el módulo de búfer y el módulo de registro de SSXRVER si tengo tiempo.
En primer lugar, la forma más fácil de modificar el módulo de búfer es cambiarlo a un búfer cíclico, reduciendo así efectivamente el número de veces que el búfer avanza los datos, o abandonando directamente esta implementación del búfer y reimplementando un búfer de alto rendimiento.
En segundo lugar, el módulo de registro actual está escrito en forma de flujo de C ++. Aunque definitivamente es más alto en el rendimiento que el uso de C ++ directamente con IOSTREAM, la sobrecarga del registro en la forma simbólica << seguirá causando problemas de rendimiento y control de formato causados por las cadenas de llamadas de funciones. Ambos problemas se pueden resolver implementando el registro en forma de printf.
Debido a las razones de tiempo, SSXRVER no implementa el módulo de administración de memoria, por lo que es casi imposible escribir un módulo de gestión de memoria de alto rendimiento general (es mejor ir directamente a Jemalloc o TCMALLOC). Sin embargo, al analizar el escenario de la biblioteca de red, todavía es una pequeña oportunidad de escribir un módulo de gestión de memoria con un mayor rendimiento en este escenario. Si tengo tiempo, echaré un vistazo a la implementación en Nginx y lo aprenderé.
Cuando estaba consultando la información, llegué a una conclusión de que en C ++ 17, puede usar STD :: String_View para reemplazar const String &, lo que mejorará cierta eficiencia. Por lo tanto, intenté reemplazar todos los lugares donde const String y en mi proyecto con std :: string_view. Sin embargo, cuando finalmente usé perf -top para ver la carga cambiada, descubrí inesperadamente que algunas funciones realmente aumentaron después de usar std :: string_view para reemplazarla. Estaba muy perplejo por qué ocurrió esta situación. Debido a las razones de tiempo, no investigaré la causa específica de este problema por el momento. Tengo la oportunidad de verificar la implementación subyacente para verificar la razón específica.
Al implementar el módulo de análisis HTTP, utilicé una máquina de estado escrita a mano que coincida directamente con cadenas en la primera versión. Luego lo reemplacé con la máquina de estado implementada por Ragel. Sin embargo, durante las pruebas recientes, descubrí que la carga de la función de análisis HTTP es muy exagerada, alcanzando el 10%. ¿Podría ser que usar Ragel ha causado la degradación del rendimiento? (Si analizar el encabezado causará una carga de sistema tan alta, entonces parece que HTTP/2.0 aún mejorará significativamente el rendimiento) Desafortunadamente, cuando escribí a mano la máquina de estado antes, no probé la carga de la función de análisis correspondiente. Ahora no puedo obtener la comparación de datos entre los dos a la vez, y tengo la oportunidad de escribir una prueba de referencia.
SSXRVER admite una transmisión UDP simple, pero personalmente creo que un marco UDP sin control de congestión, control de tráfico y funciones de retransmisión de pérdidas de paquetes básicamente se puede decir que no se puede usar normalmente. En el futuro, tengo tiempo para aprender protocolos de Quic y KCP. Complementaré el conocimiento relacionado con UDP. ¡Creo que el protocolo UDP más eficiente y flexible se utilizará cada vez más en el futuro!
De hecho, en realidad creo que el mejor marco de red en la actualidad debería ser que la multiplexación de la dirección de multiplexión de puertos más hilos múltiples (procesos múltiples) une la misma dirección y puerto, y el kernel realiza automáticamente el equilibrio de carga de aceptación. Al mismo tiempo, el sistema bloquea las llamadas a través de Coroutine Framework + Hook. Después de usar este marco, puede garantizar un alto rendimiento sin usar el hilo principal para distribuir conexiones, y no hay necesidad de caer en el infierno de devolución de llamada asíncrona.
Además, si puede usar el mecanismo IO asíncrono IO_uring agregado después de Linux Kernel 5.1, creo que el rendimiento del servidor será mayor. Sin embargo, no sé mucho sobre Io_uring en la actualidad, y no tengo la capacidad de diseñar una biblioteca de red IO asíncrona basada en IO_uring.