Enviado por admin el
OpenSIPS 4.0 no es solo una versión con nuevas funcionalidades, sino también una oportunidad para repensar partes del motor que llevan mucho tiempo sin cambios. Uno de los ejemplos más importantes es la capa TCP/TLS, que en su forma anterior se mantuvo prácticamente igual desde su introducción hace más de veinte años. Fue construida en torno a las realidades arquitectónicas de esa época y cumplió bien su función, pero con el tiempo sus limitaciones se fueron haciendo cada vez más evidentes. OpenSIPS 4.0 es la oportunidad para rediseñar esta área por completo: abandonar el viejo modelo TCP multiproceso y adoptar un nuevo enfoque de proceso único con múltiples threads.
Modelo anterior
El framework TCP tradicional se basaba en un proceso TCP Main que distribuía conexiones entre un conjunto de workers TCP. Dado que OpenSIPS fue diseñado en torno a un modelo multiproceso, la capa TCP debía soportar el compartir conexiones e incluso la "migración" de conexiones entre procesos. Ese enfoque tenía un coste. Primero, complicaba innecesariamente todo el path de I/O: las conexiones debían pasarse entre el proceso TCP Main y los workers, añadiendo overhead adicional y haciendo el flujo más difícil de mantener. Segundo, el balanceo de carga era limitado, ya que distribuir el trabajo eficientemente entre workers nunca fue tan flexible como se hubiera deseado al estar el ownership de conexiones e I/O atado al modelo basado en procesos. Finalmente, este diseño se convirtió en una carga importante para TLS. Desde el primer día, el soporte TLS en OpenSIPS fue difícil precisamente por esta arquitectura SIP multiproceso: requería manejo especial de memoria compartida y locks explícitos alrededor de las estructuras de OpenSSL. Con el tiempo, OpenSSL se fue alejando cada vez más de soportar este tipo de uso, obligando a acumular parches solo para mantener las cosas funcionando. Esos parches no solo afectaban a la capa de transporte TLS, sino que tenían efectos secundarios negativos en otros módulos que usan OpenSSL en escenarios más simples y de proceso único, como db_mysql, db_postgres, stir_shaken y otros. Además, el modelo antiguo abría la puerta al tipo de bugs que nadie quiere depurar: memoria colgante, dobles liberaciones, memory leaks y crashes difíciles de explicar. El rediseño fue impulsado por algo más que el deseo de modernizar el código: también se buscaba simplificar el modelo de I/O y eliminar un punto de dolor arquitectónico de larga data.
Nuevo modelo
En lugar de distribuir el ownership TCP entre múltiples procesos, todo el trabajo TCP/TLS se gestiona ahora dentro de un único proceso dedicado. Ese proceso utiliza un número configurable de threads para realizar la lectura y escritura en las conexiones TCP. Las conexiones ya no se pasan entre procesos: son propiedad de un único lugar y se gestionan desde allí. Esto hace que la capa TCP sea más ligera, más limpia y mejor alineada con los sistemas modernos, donde un diseño multithreaded es mucho más práctico que hace veinte años.
Lectura
En el lado de la lectura, el proceso TCP main realiza el I/O real a través de sus threads dedicados. Una vez recibidos los datos, se ejecuta un paso de parsing ligero, solo para determinar los límites del mensaje y calcular la longitud completa. Cuando hay un mensaje SIP completo disponible, se despacha a uno de los procesos worker de OpenSIPS, que continúa con el manejo a nivel SIP. El I/O de transporte permanece centralizado, mientras que la lógica SIP sigue siendo procesada por los workers.
Escritura y conexión
El path de escritura sigue la misma filosofía. Cuando un worker necesita enviar datos, ya no escribe directamente al socket. En su lugar, construye un chunk asíncrono y envía un job de escritura al proceso TCP, cuyos threads de I/O realizan el envío real. El establecimiento de conexiones también se gestiona allí, lo que significa que tanto la escritura como la conexión son ahora propiedad plena del proceso TCP y sus threads. Esto elimina por completo el paso de conexiones entre procesos y otorga al framework un modelo de ownership mucho más limpio. Para TLS/OpenSSL, los beneficios son aún más importantes: el contexto SSL puede ahora permanecer local al proceso TCP, sin necesidad de compartirse entre múltiples procesos. Esto elimina una de las mayores restricciones del diseño anterior y permite deshacerse de muchos de los parches y compromisos que antes eran necesarios.
Rendimiento
En términos de rendimiento, la ganancia principal está en la latencia, especialmente en el establecimiento de conexiones. En pruebas sintéticas de extremo a extremo sobre TLS con 30.000 intercambios SIP a 500 peticiones por segundo, la arquitectura rediseñada mantuvo un throughput similar mientras entregaba consistentemente menor latencia que el modelo anterior, con la mejora más clara visible durante el establecimiento de conexiones. Son pruebas sintéticas —el tráfico SIP real es mucho más difícil de replicar con precisión en un entorno controlado—, pero los resultados indican que centralizar el I/O de sockets dentro de un proceso TCP dedicado con su propio pool de threads reduce el overhead de coordinación y proporciona un path de ejecución más limpio y predecible bajo carga.
Trabajo futuro
Quedan pasos obvios para este nuevo framework: implementar la notificación del resultado de escritura, para que el lado SIP pueda ser informado si un envío asíncrono tuvo éxito o falló; y continuar simplificando el modelo de procesamiento eliminando el modo de workers dedicados para avanzar hacia un pool unificado. Este rediseño de TCP/TLS no es solo una limpieza del stack actual, sino un paso hacia cambios internos más amplios previstos para OpenSIPS 4.0 y versiones posteriores.
Conclusión
Este rediseño de TCP/TLS es un cambio interno significativo en OpenSIPS 4.0. Simplifica la capa de transporte, elimina algunas de las limitaciones del diseño TLS anterior y proporciona una base mejor para los cambios futuros en el core de OpenSIPS.
Comentarios recientes