Tengo 6 contenedores juntos ejecutándose en docker swarm. Kafka+Zookeeper, MongoDB, A, B, C e Interfaz. La interfaz es el punto de acceso principal del público; solo este contenedor publica el puerto: 5683. El contenedor de la interfaz se conecta a A, B y C durante el inicio. Estoy usando docker-compose file + docker stack deployment, cada servicio tiene un nombre que se usa como host para la interfaz. Todo comienza con éxito y funciona bien. Después de un tiempo (20 minutos, 1 hora, ..) no puedo hacer una solicitud a la interfaz. La interfaz recibe mis solicitudes, pero la aplicación perdió la conexión con el servicio A, B, C o con todos ellos. Si reinicio la interfaz, puede volver a conectarse a los servicios A, B, C.
Primero pensé que era un problema de la aplicación, así que expongo 2 puertos nuevos en cada servicio (interfaz, A, B, C) y me conecto con el generador de perfiles y el depurador. La aplicación se ejecuta correctamente, sin fugas, sin hilos bloqueados, normalmente funcionando y esperando conexiones. El depurador me muestra que cuando realizo una solicitud a la interfaz y la interfaz intenta solicitar el servicio A, se produjo el restablecimiento de la conexión por excepción del par.
Durante esta depuración descubrí cosas interesantes. Adjunté el depurador a la interfaz cuando se iniciaron los servicios y también se desconectó el depurador después de un tiempo. + No pude volver a conectarlo, hasta que hice una solicitud al contenedor -> aplicación. Problema: falló el apretón de manos.
Otra cosa interesante que descubrí fue que no pude solicitar ninguna interfaz. Así que usé wireshark para ver qué estaba pasando y: SYN - ACK estuvo bien. Luego, la aplicación publica algunos datos y la interfaz responde con FIN, ACK. Supongo que esto también sucede cuando la interfaz intenta solicitar el servicio A y FIN la conexión. La base de código de la interfaz, A, B y C es la misma con respecto al servidor de red.
Finalmente, no creo que sea un problema de aplicación. ¿Por qué? Traté de implementar contenedores no como servicios. Ejecuto cada contenedor por separado, publiqué los puertos de cada uno y el punto final de los servicios se configuró en localhost. (no red superpuesta). Y está funcionando. Los contenedores funcionan sin problema. + No dije al principio que las aplicaciones Java (interfaz, A, B, C) se ejecutan sin problemas cuando se ejecutan como una aplicación independiente, no en la ventana acoplable.
me podrian ayudar cual podria ser el problema ¿Por qué la ventana acoplable en caso de red superpuesta está cerrando sockets?
Estoy usando la ventana acoplable más nueva. También usé mayores.
Finalmente, pude resolver el problema.
Lo que estaba pasando, una vez más. La interfaz abre una conexión TCP permanente a A,B,C. Cuando intenta ejecutar estos servicios A, B, C como aplicaciones Java independientes, todo funciona. Cuando los dockerizamos y ejecutamos en enjambre, funcionó solo unos minutos. Extraño fue que la conexión entre la interfaz y otro servicio se interrumpió en el momento en que realizó una solicitud del cliente a la interfaz.
Después de muchas pruebas fallidas y la depuración de cada contenedor, intenté ejecutar cada contenedor acoplable por separado, con puertos asignados y como punto final especifiqué localhost. (cada contenedor expuso los puertos y la interfaz se conectaba a localhost) Sucedió algo gracioso, estaba funcionando. Cuando ejecuta contenedores como este, se utiliza un controlador de red diferente para el contenedor. Puente uno. Si lo ejecuta en enjambre, se utiliza el controlador de red superpuesto.
Así que tenía que ser algo con la red acoplable, no con la aplicación en sí. El siguiente paso fue tcpdump de cada contenedor después de un par de minutos, cuando debería dejar de funcionar. Estuvo muy interesante.
A estaba restableciendo la comunicación TCP abierta después de un par de minutos sin comunicación. ¿Por qué?
Docker usa IP Virtual Server e IPVS mantiene su propia tabla de conexiones. El tiempo de espera predeterminado para las conexiones CLOSE_WAIT en la tabla IPVS es de 60 segundos. Por lo tanto, cuando el servidor envía algo después de 60 segundos, la conexión IPVS ya no está disponible y el paquete parece inválido para una nueva sesión TCP y obtiene RST. En el lado del cliente, la conexión permanece para siempre en el estado FIN_WAIT2 porque la aplicación aún tiene el socket abierto; El temporizador fin_wait del kernel se activa solo para sockets TCP huérfanos.
Esto es lo que leí al respecto y cómo lo entiendo. No estoy seguro si mi explicación del problema es correcta, pero basándome en estas suposiciones, implementé ping-pong entre la interfaz y los servicios A, B, C en caso de que no haya comunicación durante <60 segundos. Y está funcionando.