tutorial interfaz interfaces gui graficas grafica español ejemplos componentes java tomcat grails deployment resin

interfaz - ¿Mejores prácticas para implementar aplicaciones Java con tiempo de inactividad mínimo?



java swing tutorial pdf español (18)

Actualizar:

Desde que se escribió por primera vez esta respuesta, ha surgido una mejor forma de desplegar archivos war a tomcat sin tiempo de inactividad. En versiones recientes de tomcat puede incluir números de versión en sus nombres de archivo war. Entonces, por ejemplo, puede desplegar los archivos ROOT##001.war y ROOT##002.war al mismo contexto simultáneamente. Todo después de ## es interpretado como un número de versión por tomcat y no como parte de la ruta de contexto. Tomcat mantendrá todas las versiones de su aplicación ejecutándose y enviará nuevas solicitudes y sesiones a la versión más nueva que esté completa mientras completa con elegancia las solicitudes y sesiones antiguas en la versión con la que empezaron. La especificación de números de versión también se puede hacer a través del administrador de tomcat e incluso de las tareas de catalina y ant. Más información here .

Respuesta Original:

Rsync tiende a ser ineficaz en los archivos comprimidos ya que su algoritmo de transferencia delta busca cambios en los archivos y un pequeño cambio en un archivo descomprimido puede alterar drásticamente la versión comprimida resultante. Por esta razón, podría tener sentido sincronizar un archivo de guerra sin comprimir en lugar de una versión comprimida, si el ancho de banda de la red resulta ser un cuello de botella.

¿Qué ocurre con el uso de la aplicación de administrador de Tomcat para realizar sus implementaciones? Si no desea cargar todo el archivo de guerra directamente a la aplicación del administrador de Tomcat desde una ubicación remota, puede sincronizarlo (sin comprimir por las razones mencionadas anteriormente) en una ubicación de marcador de posición en el cuadro de producción, volver a empaquetarlo en una guerra, y luego entrégalo al gerente localmente. Existe una buena tarea ant que se envía con Tomcat que le permite realizar scripts de implementaciones mediante la aplicación Tomcat Manager.

Hay un error adicional en su enfoque que no ha mencionado: mientras su aplicación está parcialmente implementada (durante una operación rsync), su aplicación podría estar en un estado inconsistente donde las interfaces modificadas pueden estar fuera de sincronización, las dependencias nuevas / actualizadas pueden no estar disponible, etc. Además, dependiendo de cuánto tiempo tarde su trabajo de sincronización, su aplicación puede reiniciarse varias veces. ¿Sabía que puede y debe desactivar el comportamiento de escuchar para cambiar los archivos y reiniciar en Tomcat? En realidad, no se recomienda para sistemas de producción. Siempre puede hacer un reinicio manual o con guión de su aplicación usando la aplicación de administrador Tomcat.

Su aplicación no estará disponible para los usuarios durante el reinicio, por supuesto. Pero si está tan preocupado por la disponibilidad, seguramente tiene servidores web redundantes detrás de un equilibrador de carga. Al desplegar un archivo war actualizado, puede hacer que el equilibrador de carga envíe temporalmente todas las solicitudes a otros servidores web hasta que finalice la implementación. Enjuague y repita para sus otros servidores web.

Al implementar una aplicación web Java grande (> 100 MB .war), actualmente utilizo el siguiente proceso de implementación:

  • El archivo .war de la aplicación se expande localmente en la máquina de desarrollo.
  • La aplicación expandida es rsync: ed desde la máquina de desarrollo al entorno en vivo.
  • El servidor de aplicaciones en el entorno en vivo se reinicia después de rsync. Este paso no es estrictamente necesario, pero descubrí que reiniciar el servidor de aplicaciones en la implementación evita "java.lang.OutOfMemoryError: PermGen space" debido a la carga frecuente de clases.

Buenas cosas sobre este enfoque:

  • Rsync minimiza la cantidad de datos enviados desde la máquina de desarrollo al entorno en vivo. Cargar todo el archivo .war lleva más de diez minutos, mientras que una rsync tarda unos segundos.

Cosas malas sobre este enfoque:

  • Mientras se ejecuta rsync, se reinicia el contexto de la aplicación ya que los archivos se actualizan. Lo ideal es que el reinicio se produzca después de que rsync se complete, no cuando aún esté en ejecución.
  • El reinicio del servidor de aplicaciones provoca aproximadamente dos minutos de inactividad.

Me gustaría encontrar un proceso de implementación con las siguientes propiedades:

  • Mínimo tiempo de inactividad durante el proceso de implementación.
  • Tiempo mínimo dedicado a cargar los datos.
  • Si el proceso de implementación es específico del servidor de la aplicación, entonces el servidor de la aplicación debe ser de código abierto.

Pregunta:

  • Teniendo en cuenta los requisitos establecidos, ¿cuál es el proceso de implementación óptimo?

¿En cuál es tu conjunto de PermSpace? ¿Esperaría ver que esto también crezca, pero debería reducirse después de la recolección de las antiguas clases? (¿O el ClassLoader todavía se sienta?)

Pensando en voz alta, podría rsync a un directorio con una versión o fecha diferente. Si el contenedor admite enlaces simbólicos, ¿podría SIGSTOP el proceso raíz, cambiar la raíz del sistema de archivos del contexto a través de un enlace simbólico y luego SIGCONT?


¿No puede hacer una copia local de la aplicación web actual en el servidor web, rsync a ese directorio y luego, tal vez incluso utilizando enlaces simbólicos, de una "vez", señalar a Tomcat a una nueva implementación sin mucho tiempo de inactividad?


Cargamos la nueva versión de la aplicación web a un directorio separado, luego movemos para intercambiarla con la que está en ejecución, o usamos enlaces simbólicos. Por ejemplo, tenemos un enlace simbólico en el directorio webapps de tomcat llamado "myapp", que apunta a la aplicación web actual denominada "myapp-1.23". Cargamos la nueva aplicación web a "myapp-1.24". Cuando todo esté listo, detenga el servidor, elimine el enlace simbólico y cree uno nuevo que apunte a la nueva versión, luego inicie el servidor nuevamente.

Deshabilitamos la recarga automática en los servidores de producción para el rendimiento, pero aún así, tener archivos dentro de la aplicación web cambiando de forma no atómica puede causar problemas, ya que los archivos estáticos o incluso las páginas JSP pueden cambiar de forma que provoquen enlaces rotos o algo peor.

En la práctica, las aplicaciones web están en realidad ubicadas en un dispositivo de almacenamiento compartido, por lo que los servidores en clúster, balanceados de carga y conmutación por error tienen el mismo código disponible.

El principal inconveniente para su situación es que la carga llevará más tiempo, ya que su método permite que rsync solo transfiera archivos modificados o agregados. Primero puede copiar la carpeta de aplicaciones web anterior a la nueva, y rsync a eso, si hace una diferencia significativa, y si realmente es un problema.


En cualquier entorno en el que se tenga en cuenta el tiempo de inactividad, seguramente está ejecutando algún tipo de clúster de servidores para aumentar la confiabilidad a través de la redundancia. Quitaría un host del clúster, lo actualizaría y luego lo lanzaría de vuelta al clúster. Si tiene una actualización que no puede ejecutarse en un entorno mixto (por ejemplo, se requiere un cambio de esquema incompatible en la base de datos), tendrá que eliminar todo el sitio, al menos por un momento. El truco es mostrar los procesos de reemplazo antes de dejar caer los originales.

Usando tomcat como ejemplo, puede usar CATALINA_BASE para definir un directorio donde se encontrarán todos los directorios de trabajo de tomcat, separados del código ejecutable. Cada vez que despliegue software, despliego a un nuevo directorio base para que pueda tener un nuevo código residente en el disco junto al código anterior. Luego puedo iniciar otra instancia de tomcat que apunta al nuevo directorio base, poner todo en funcionamiento y ejecutarlo, luego cambiar el proceso anterior (número de puerto) por el nuevo en el balanceador de carga.

Si me preocupa preservar los datos de la sesión en todo el conmutador, puedo configurar mi sistema para que cada host tenga un socio al que replicar los datos de la sesión. Puedo colocar uno de esos hosts, actualizarlo, traerlo de vuelta para que haga una copia de seguridad de los datos de la sesión y luego cambie los dos hosts. Si tengo varios pares en el clúster, puedo soltar la mitad de todos los pares, luego hacer un cambio masivo, o puedo hacerlos de a dos por vez, dependiendo de los requisitos de la versión, los requisitos de la empresa, etc. Personalmente, sin embargo, prefiero permitir que los usuarios finales sufran la pérdida muy ocasional de una sesión activa en lugar de tratar de actualizar con sesiones intactas.

Es todo un compromiso entre la infraestructura de TI, la complejidad del proceso de lanzamiento y el esfuerzo del desarrollador. Si su clúster es lo suficientemente grande y su deseo lo suficientemente fuerte, es bastante fácil diseñar un sistema que pueda cambiarse sin tiempo de inactividad para la mayoría de las actualizaciones. Los grandes cambios de esquema a menudo fuerzan el tiempo de inactividad real, ya que el software actualizado generalmente no puede acomodarse al esquema anterior, y probablemente no pueda copiar los datos en una nueva instancia db, hacer la actualización del esquema y luego cambiar los servidores al nuevo db, ya que habrás omitido cualquier dato escrito en el antiguo después de que el nuevo db haya sido clonado. Por supuesto, si tiene recursos, puede encargarles a los desarrolladores que modifiquen la nueva aplicación para que usen nuevos nombres de tabla para todas las tablas que estén actualizadas, y pueden poner activadores en su lugar en el db activo que actualizará correctamente las nuevas tablas con datos como está escrito en las tablas antiguas por la versión anterior (o tal vez use vistas para emular un esquema del otro). Abra sus nuevos servidores de aplicaciones y cámbielos al clúster. Hay una tonelada de juegos que puede jugar para minimizar el tiempo de inactividad si tiene los recursos de desarrollo para construirlos.

Quizás el mecanismo más útil para reducir el tiempo de inactividad durante las actualizaciones de software es asegurarse de que su aplicación pueda funcionar en modo de solo lectura. Esto ofrecerá algunas funcionalidades necesarias para sus usuarios, pero le permitirá realizar cambios en todo el sistema que requieren modificaciones de la base de datos, etc. Coloque su aplicación en el modo de solo lectura, luego clone los datos, actualice el esquema, abra nuevos servidores de aplicaciones contra el nuevo db y luego cambie el equilibrador de carga para usar los nuevos servidores de aplicaciones. Su único tiempo de inactividad es el tiempo requerido para cambiar al modo de solo lectura y el tiempo requerido para modificar la configuración de su equilibrador de carga (la mayoría de los cuales puede manejarlo sin ningún tipo de tiempo de inactividad).


En cuanto al contexto temprano reinicia. Todos los contenedores tienen opciones de configuración para deshabilitar la redistribución automática en archivos de clase o cambios de recursos estáticos. Probablemente no pueda deshabilitar las redistribuciones automáticas en los cambios de web.xml, por lo que este es el último en actualizarse. Por lo tanto, si inhabilita la redistribución automática y actualiza el archivo web.xml como el último, verá que el contexto se reinicia después de toda la actualización.


Escribí un script bash que toma algunos parámetros y sincroniza el archivo entre servidores. Acelera mucho la transferencia de rsync para archivos más grandes:

https://gist.github.com/3985742



Esto depende de la arquitectura de su aplicación.

Una de mis aplicaciones se encuentra detrás de un proxy de equilibrio de carga, donde realizo una implementación escalonada, erradicando eficazmente el tiempo de inactividad.


Mi consejo es usar rsync con versiones explosionadas pero implementar un archivo war.

  1. Crea una carpeta temporal en el entorno en vivo donde tendrás la versión explotada de webapp.
  2. Rsync explotó versiones.
  3. Después de exitosa rsync crea un archivo de guerra en la carpeta temporal en la máquina de entorno en vivo.
  4. Reemplace Old War en el directorio de implementación del servidor con uno nuevo de la carpeta temporal.

Se recomienda reemplazar la vieja guerra por una nueva en el contenedor JBoss (que está basado en Tomcat) porque es una operación atómica y rápida y está seguro de que cuando el implementador inicie toda la aplicación estará en estado desplegado.


No es una "mejor práctica" sino algo en lo que he pensado.

¿Qué hay de la implementación de la aplicación web a través de un DVCS como git?

De esta forma, puede dejar que git sepa qué archivos transferir al servidor. También tienes una buena manera de echarte atrás si resulta que está roto, ¡simplemente haz una reversión!


No estoy seguro de que esto responda a su pregunta, pero lo compartiré en el proceso de implementación que uso o encuentro en los pocos proyectos que hice.

De manera similar, nunca recuerdo haber realizado una nueva implementación o actualización de la guerra. La mayoría de las veces, mis actualizaciones están restringidas a unos pocos archivos jsp, tal vez una biblioteca, algunos archivos de clase. Puedo administrar y determinar cuáles son los artefactos afectados y, por lo general, empaquetamos esas actualizaciones en un archivo zip, junto con un script de actualización. Voy a ejecutar el script de actualización. El script hace lo siguiente:

  • Haga una copia de seguridad de los archivos que se sobrescribirán, tal vez en una carpeta con fecha y hora actual.
  • Desempaquetar mis archivos
  • Detener el servidor de aplicaciones
  • Mueva los archivos
  • Inicie el servidor de aplicaciones

Si el tiempo de inactividad es una preocupación, y generalmente lo son, mis proyectos suelen ser HA, incluso si no comparten el estado, sino que usan un enrutador que proporciona un enrutamiento de sesión adhesivo.

Otra cosa que tengo curiosidad sería, ¿por qué la necesidad de rsync? Debería poder saber cuáles son los cambios necesarios, al determinarlos en su entorno de ensayo / desarrollo, sin realizar comprobaciones delta con en vivo. En la mayoría de los casos, tendría que sintonizar su rsync para ignorar los archivos de todos modos, como ciertos archivos de propiedades que definen los recursos que utiliza un servidor de producción, como la conexión a la base de datos, el servidor smtp, etc.

Espero que esto sea útil.


Se ha observado que rsync no funciona bien cuando se introducen cambios en un archivo WAR. La razón de esto es que los archivos WAR son esencialmente archivos ZIP y, de forma predeterminada, se crean con archivos comprimidos de miembros. Pequeños cambios en los archivos del miembro (antes de la compresión) resultan en diferencias de gran escala en el archivo ZIP, lo que hace que el algoritmo de transferencia delta de rsync sea ineficaz.

Una posible solución es usar jar -0 ... para crear el archivo WAR original. La opción -0 le dice al comando jar que no comprima los archivos miembros al crear el archivo WAR. Luego, cuando rsync compara las versiones antiguas y nuevas del archivo WAR, el algoritmo de transferencia delta debería ser capaz de crear pequeñas diferencias. Luego arregle que rsync envíe los diffs (o archivos originales) en forma comprimida; por ejemplo, use rsync -z ... o un flujo de datos comprimido / transporte debajo.

EDITAR: Dependiendo de cómo esté estructurado el archivo WAR, también puede ser necesario usar jar -0 ... para crear archivos JAR de componentes. Esto se aplicaría a los archivos JAR que con frecuencia están sujetos a cambios (o que simplemente se reconstruyen), en lugar de a archivos JAR de terceros estables.

En teoría, este procedimiento debería proporcionar una mejora significativa sobre el envío de archivos WAR regulares. En la práctica, no lo he intentado, así que no puedo prometerle que funcionará.

La desventaja es que el archivo WAR desplegado será significativamente más grande. Esto puede dar como resultado tiempos de inicio de aplicaciones de aplicaciones más largos, aunque sospecho que el efecto sería marginal.

Un enfoque completamente diferente sería mirar su archivo WAR para ver si puede identificar los JAR de la biblioteca que probablemente (casi) nunca cambien. Saque estos archivos JAR del archivo WAR e impleméntelos por separado en el directorio common/lib del servidor Tomcat; por ejemplo, usando rsync .


Si los archivos estáticos son una gran parte de su gran GUERRA (100Mo es bastante grande), colocarlos fuera de WAR y desplegarlos en un servidor web (por ejemplo, Apache) en frente de su servidor de aplicaciones puede acelerar las cosas. Además de eso, Apache generalmente hace un mejor trabajo al servir archivos estáticos que un motor de servlet (incluso si la mayoría de ellos lograron un progreso significativo en esa área).

Entonces, en lugar de producir una gran GUERRA, póngala en la dieta y produzca:

  • un gran ZIP con archivos estáticos para Apache
  • un WAR menos gordo para el motor servlet.

Opcionalmente, vaya más allá en el proceso de hacer el diluyente WAR: si es posible, implemente Grails y otros JAR que no cambian con frecuencia (que es el caso de la mayoría de ellos) en el nivel del servidor de aplicaciones.

Si logras producir un WAR más ligero, no me molestaría en sincronizar directorios en lugar de archivos.

Fortalezas de este enfoque:

  1. Los archivos estáticos pueden ser "implementados" en Apache (por ejemplo, use un enlace simbólico que apunta en el directorio actual, descomprima los archivos nuevos, actualice el enlace simbólico y voilà).
  2. El WAR será más delgado y llevará menos tiempo desplegarlo.

Debilidad de este enfoque:

  1. Hay un servidor más (el servidor web) por lo que esto agrega (un poco) más complejidad.
  2. Tendrá que cambiar los scripts de compilación (no es un gran problema IMO).
  3. Necesitarás cambiar la lógica rsync.

Simplemente use 2 o más servidores tomcat con un proxy sobre él. Ese proxy puede ser de apache / nignix / haproxy.

Ahora en cada uno de los servidores proxy hay una url "in" y "out" con los puertos configurados.

Primero copie su guerra en el tomcat sin detener el servicio. Una vez desplegada la guerra, el motor tomcat la abre automáticamente.

Observe la verificación cruzada unpackWARs = "true" y autoDeploy = "true" en el nodo "Host" dentro de server.xml

Se ve así

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">

Ahora mira los registros de Tomcat. Si no hay ningún error, significa que está funcionando correctamente.

Ahora acierta todas las API para probar

Ahora ve a tu servidor proxy.

Simplemente cambie la asignación de url de fondo con el nombre de la nueva guerra. Como el registro con los servidores proxy como apache / nignix / haProxy tomó muy poco tiempo, sentirá un tiempo de inactividad mínimo

Consulte https://developers.google.com/speed/pagespeed/module/domains para correlacionar URL


Su enfoque para sincronizar la guerra extraída es bastante bueno, también el reinicio, ya que creo que un servidor de producción no debe tener habilitada la implementación en caliente. Entonces, el único inconveniente es el tiempo de inactividad cuando necesita reiniciar el servidor, ¿verdad?

Supongo que todo el estado de su aplicación se mantiene en la base de datos, por lo que no tiene problemas con algunos usuarios que trabajan en una instancia del servidor de aplicaciones, mientras que otros usuarios están en otra instancia del servidor de aplicaciones. Si es así,

Ejecute dos servidores de aplicaciones : inicie el segundo servidor de aplicaciones (que escucha en otros puertos TCP) y despliegue allí su aplicación. Después de la implementación, actualice la configuración de httpd de Apache (mod_jk o mod_proxy) para apuntar al segundo servidor de aplicaciones. Reiniciando con gracia el proceso httpd de Apache. De esta forma, no tendrá tiempo de inactividad y los nuevos usuarios y solicitudes se redireccionarán automáticamente al nuevo servidor de aplicaciones.

Si puede utilizar la compatibilidad de replicación de sesión y clúster del servidor de la aplicación, será incluso más fácil para los usuarios que están actualmente conectados, ya que el segundo servidor de la aplicación se sincronizará tan pronto como se inicie. Luego, cuando no haya accesos al primer servidor, apáguelo.


Tomcat 7 tiene una bonita función llamada " implementación paralela " diseñada para este caso de uso.

Lo esencial es que expandas el .war en un directorio, directamente debajo de webapps / o enlazado simbólicamente. Las versiones sucesivas de la aplicación se encuentran en los directorios denominados app##version , por ejemplo myapp##001 y myapp##002 . Tomcat manejará las sesiones existentes yendo a la versión anterior, y las sesiones nuevas irán a la nueva versión.

El problema es que tienes que tener mucho cuidado con las fugas de PermGen. Esto es especialmente cierto con Grails que usa mucho PermGen. VisualVM es tu amigo.