que - ¿Cómo se actualizan remotamente las aplicaciones Java?
que es java 8 (8)
Tenemos una aplicación de servidor Java que se ejecuta en varias computadoras, todas conectadas a Internet, algunas detrás de firewalls. Necesitamos actualizar remotamente los archivos JAR y las secuencias de comandos de inicio desde un sitio central, sin interrupciones notables en la aplicación.
El proceso debe ser desatendido e infalible (es decir, no podemos darnos el lujo de romper la aplicación debido a interrupciones intempestivas de Internet).
En el pasado, utilizamos una variedad de scripts y utilidades externas para manejar tareas similares, pero debido a que tienen sus propias dependencias, el resultado es más difícil de mantener y menos portátil. Antes de hacer algo nuevo, quiero obtener información de la comunidad.
¿Alguien ha encontrado una buena solución para esto? ¿Tienes alguna idea o sugerencia?
Solo para aclarar: esta aplicación es un servidor, pero no para aplicaciones web (no hay contenedores de aplicaciones web ni archivos WAR aquí). Es solo un programa Java autónomo.
Creo que puede implementar en caliente los archivos JAR si usa un servidor de aplicaciones basado en OSGi como el servidor SpringSource dm . Nunca lo he usado, pero conociendo la calidad general de la cartera de Spring, estoy seguro de que vale la pena echarle un vistazo.
Definitivamente debería echar un vistazo a OSGi, fue creado solo para estos casos (especialmente para productos integrados) y es utilizado por un gran número de compañías. Puede actualizar los "paquetes" de jar, agregarlos y eliminarlos mientras la aplicación se está ejecutando. No lo he usado yo mismo, así que no sé sobre la calidad de los servidores / frameworks de código abierto, pero aquí hay un grupo de enlaces útiles para que comiences:
http://www.osgi.org/Main/HomePage
http://www.aqute.biz/Code/Bnd
http://blog.springsource.com/2008/02/18/creating-osgi-bundles/
http://blog.springsource.com/
http://www.knopflerfish.org/
http://felix.apache.org/site/index.html
Es muy difícil hacer que la actualización sea atómica, especialmente si tiene que actualizar la base de datos.
Pero, si no lo hace, lo que puede hacer primero es asegurarse de que su aplicación pueda ejecutarse desde una ruta relativa. Es decir, puede colocar su aplicación en algún directorio, y todos los archivos importantes se encuentran relacionados con esa ubicación, de modo que su ubicación de instalación real no es realmente importante.
Luego, duplica tu instalación. Ahora, tienes la versión "en ejecución" y tienes la versión "nueva".
Actualice la versión "nueva" utilizando la tecnología que desee (FTP, rsync, cinta de papel, lo que sea que flote su bote).
Verifique su instalación (sumas de verificación, pruebas de unidades rápidas, lo que necesite, incluso si lo desea, inícielo en un puerto de prueba).
Cuando esté satisfecho con la nueva instalación, ejecute la instancia de ejecución original, RENOMINE el directorio original (mv application_old), cambie el nombre del directorio NUEVO (mv application_new) e inícielo nuevamente.
Su tiempo de inactividad se reduce al cierre del servidor y al tiempo de inicio (dado que el cambio de nombre es "libre").
Si, por casualidad, detecta un error crítico, tiene su versión original allí. Detener el nuevo servidor, cambiarle el nombre, reiniciar el antiguo. Muy rápido retrocede.
La otra cosa agradable es que su infraestructura de servicio es estática (como sus scripts rc, trabajos cron, etc.) ya que apuntan al directorio "aplicación" y no cambia.
También se puede hacer con enlaces suaves en lugar de cambiar el nombre de los directorios. de cualquier manera está bien.
Pero la técnica es simple y casi a prueba de balas si tu aplicación coopera.
Ahora, si tienes cambios en la base de datos, bueno, ese es un problema desagradable completamente diferente. Idealmente, si puede hacer que sus cambios DB sean "compatibles con versiones anteriores", entonces con suerte la versión anterior de la aplicación se puede ejecutar en el nuevo esquema, pero eso no siempre es posible.
Los jar no se pueden modificar mientras la JVM se está ejecutando encima de él y provocarán errores. He intentado tareas similares y lo mejor que se me ocurrió es hacer una copia del Jar actualizado y hacer la transición del script de inicio para ver ese Jar. Una vez que tenga el Jar actualizado, enciéndalo y espere a que termine el jar viejo antes de darle la señal para hacerlo. Desafortunadamente esto significa una pérdida de GUI, etc. durante un segundo, pero la serialización de la mayoría de las estructuras en Java es fácil y la GUI actual podría transferirse a la aplicación actualizada antes de que se cierre (¡aunque algunas cosas pueden no ser serializables!).
No especificó el tipo de aplicaciones de servidor: supongo que no está ejecutando aplicaciones web (ya que la implementación de un WAR ya hace lo que está diciendo, y muy rara vez necesita una aplicación web para hacer el tipo de extracción) actualizaciones. Si está hablando de una aplicación web, la siguiente discusión aún puede aplicarse: implementará la verificación de actualización y ping-pong para el archivo WAR en lugar de archivos individuales).
Es posible que desee echar un vistazo a jnlp: WebStart se basa en esto (esta es una tecnología de implementación de aplicaciones cliente), pero estoy bastante seguro de que podría adaptarse a la realización de actualizaciones para una aplicación tipo servidor. A pesar de todo, jnlp hace un buen trabajo al proporcionar descriptores que se pueden usar para descargar las versiones requeridas de los JAR requeridos ...
Algunas consideraciones generales al respecto (tenemos varias aplicaciones en el mismo paquete y estamos considerando un mecanismo de actualización automática):
Considere tener un archivo bootstrap.jar que sea capaz de leer un archivo jnlp y descargar los archivos necesarios / actualizados antes de iniciar la aplicación.
Los archivos JAR se pueden actualizar incluso cuando se está ejecutando una aplicación (al menos en Windows, y ese es el sistema operativo que más probabilidades tiene de mantener bloqueos al ejecutar archivos). Puede encontrarse con problemas si está utilizando cargadores de clases personalizados, o si tiene varios JAR que pueden cargarse o descargarse en cualquier momento, pero si crea mecanismos para evitar esto, sobrescribiendo los JAR y luego relanzando la aplicación debe ser suficiente para la actualización.
Aunque es posible sobrescribir los JAR, es posible que desee considerar un enfoque de ping-pong para su ruta de acceso lib (si todavía no tiene el iniciador de aplicaciones configurado para leer automáticamente todos los archivos jar en la carpeta lib y agregarlos a la ruta de clase automáticamente, entonces eso es algo que realmente quieres hacer). Así es como funciona ping-pong:
La aplicación se inicia y examina lib-ping / version.properties y lib-pong / version.properties y determina cuál es más reciente. Digamos que lib-ping tiene una versión posterior. El iniciador busca lib-ping * .jar y agrega esos archivos al CP durante el lanzamiento. Cuando hace una actualización, descarga archivos jar en lib-pong (o copia archivos jar de lib-ping si quiere ahorrar ancho de banda y el JAR en realidad no cambió; ¡aunque esto rara vez vale la pena!). Una vez que haya copiado todos los archivos JAR en lib-pong, lo último que debe hacer es crear el archivo version.properties (de ese modo, se puede detectar y purgar una actualización interrumpida que da como resultado una carpeta lib parcial). Finalmente, reinicia la aplicación y el programa de arranque detecta que lib-pong es el classpath deseado.
ping-pong como se describe arriba permite un retroceso. Si lo diseñas correctamente, puedes tener una parte de tu aplicación que pruebes y, a continuación, nunca cambies esa comprobación para ver si se debe retrotraer una versión determinada. De esta forma, si se equivoca y despliega algo que rompe la aplicación, puede invalidar la versión. Esta parte de la aplicación solo tiene que eliminar el archivo version.properties de la carpeta bad lib- * y luego volver a ejecutarlo. Es importante mantener esta parte simple de la suciedad porque es su falla.
Puede tener más de 2 carpetas (en lugar de ping / pong, solo tiene lib-aaaammdd y purga todo menos el 5 más nuevo, por ejemplo). Esto permite una reversión más avanzada (¡pero más complicada!) De los JAR.
Recomendaría Capistrano para la implementación de servidores múltiples. Si bien está diseñado para implementar aplicaciones Rails, he visto que se utilizó con éxito para implementar aplicaciones Java.
Usamos Eclipse, que es el sistema de actualización de OSGi, y nuestra experiencia es muy buena.
¡Recomendado!
La última versión de Java Web Start permite inyectar una aplicación en la memoria caché local sin invocar realmente el programa y se puede marcar como "fuera de línea". Como el caché es lo que se utiliza para invocar el programa, se actualizará solo para la próxima ejecución. Para que esto funcione, lo más probable es que necesite jarras con números de versión en su nombre (por ejemplo, nuestra-biblioteca-2009-06-01.jar).