Cómo implementar una aplicación ASP.NET sin tiempo de inactividad

Para implementar una nueva versión de nuestro sitio web, hacemos lo siguiente:

  1. Comprime el nuevo código y súbelo al servidor.
  2. En el servidor directo, elimine todo el código en vivo del directorio del sitio web de IIS.
  3. Extraiga el archivo zip del nuevo código en el directorio IIS ahora vacío

Este proceso está todo guionado, y ocurre bastante rápido, pero aún puede haber un tiempo de inactividad de 10-20 segundos cuando se eliminan los archivos antiguos y se despliegan los archivos nuevos.

¿Alguna sugerencia sobre un método de tiempo de inactividad de 0 segundos?

Necesita 2 servidores y un equilibrador de carga. Aquí hay unos pasos:

  1. Convierta todo el tráfico en el Servidor 2
  2. Implementar en el servidor 1
  3. Servidor de prueba 1
  4. Convierta todo el tráfico en el Servidor 1
  5. Implementar en el servidor 2
  6. Servidor de prueba 2
  7. Convierta el tráfico en ambos servidores

Lo que pasa es que, incluso en este caso, aún tendrá reinicios de la aplicación y pérdida de sesiones si está utilizando “sesiones adhesivas”. Si tiene sesiones de base de datos o un servidor de estado, entonces todo debería estar bien.

La herramienta de implementación web de Microsoft admite esto hasta cierto punto:

Habilita el soporte del Sistema de archivos transaccionales de Windows (TxF). Cuando el soporte de TxF está habilitado, las operaciones de archivo son atómicas; es decir, tienen éxito o fallan por completo. Esto garantiza la integridad de los datos y evita que los datos o archivos existentes en un estado “a mitad de camino” o dañado. En MS Deploy, TxF está deshabilitado de forma predeterminada.

Parece que la transacción es para toda la sincronización. Además, TxF es una característica de Windows Server 2008, por lo que esta función de transacción no funcionará con versiones anteriores.

Creo que es posible modificar el script para el tiempo de inactividad 0 utilizando carpetas como versiones y la metabase de IIS:

  • para una ruta / url existente:
    • ruta de acceso : \ web \ app \ v2.0 \
    • url : http: // app
  • Copie el sitio web nuevo (o modificado) al servidor bajo
    • \ web \ app \ v2.1 \
  • Modificar la metabase de IIS para cambiar la ruta del sitio web
    • desde \ web \ app \ 2.0 \
    • a \ web \ app \ v2.1 \

Este método ofrece los siguientes beneficios:

  • En caso de que la nueva versión tenga un problema, puede retroceder fácilmente a v2.0
  • Para implementar en varios servidores físicos o virtuales, puede usar su secuencia de comandos para la implementación de archivos. Una vez que todos los servidores tengan la nueva versión, puede cambiar simultáneamente todas las metabases de los servidores mediante la Herramienta de implementación web de Microsoft.

Puede lograr la implementación de tiempo de inactividad cero en un solo servidor mediante el uso del enrutamiento de solicitudes de aplicaciones en IIS como equilibrador de carga de software entre dos sitios IIS locales en diferentes puertos. Esto se conoce como una estrategia de implementación verde azul donde solo uno de los dos sitios está disponible en el equilibrador de carga en un momento dado. Implementar en el sitio que está “inactivo”, calentarlo y llevarlo al equilibrador de carga (generalmente pasando un chequeo de estado del enrutamiento de solicitud de aplicación), luego tomar el sitio original que estaba activo, fuera del “grupo” (nuevamente haciendo que su comprobación de salud falle).

Un tutorial completo se puede encontrar aquí.

Revisé esto recientemente y la solución que surgió fue tener dos sitios configurados en IIS y cambiar entre ellos.

Para mi configuración, tenía un directorio web para cada sitio A y B como este: c: \ Intranet \ Live A \ Interface c: \ Intranet \ Live B \ Interface

En IIS, tengo dos sitios idénticos (mismos puertos, autenticación, etc.) cada uno con su propio grupo de aplicaciones. Uno de los sitios se está ejecutando (A) y el otro está detenido (B). el vivo también tiene el encabezado host en vivo.

Cuando se trata de implementar para vivir, simplemente publico en la ubicación del sitio DETENIDO. Como puedo acceder al sitio B utilizando su puerto, puedo precalentar el sitio para que el primer usuario no provoque el inicio de una aplicación. Luego, usando un archivo de proceso por lotes, copio el encabezado del host en vivo en B, detengo A y comienzo B.

Utilizando la clase ServerManager de Microsoft.Web.Administration puede desarrollar su propio agente de implementación.

El truco consiste en cambiar PhysicalPath de VirtualDirectory, lo que da como resultado un cambio atómico en línea entre aplicaciones web antiguas y nuevas.

¡Tenga en cuenta que esto puede dar lugar a que AppDomains antiguos y nuevos se ejecuten en paralelo!

El problema es cómo sincronizar los cambios en las bases de datos, etc.

Al sondear la existencia de AppDomains con PhysicalPaths viejos o nuevos, es posible detectar cuándo terminaron los AppDomain (s) antiguos, y si los nuevos AppDomain (s) se han iniciado.

Para forzar que un AppDomain se inicie, debe realizar una solicitud HTTP (IIS 7.5 admite la función Autostart)

Ahora necesita una forma de bloquear solicitudes para el nuevo AppDomain. Utilizo un mutex con nombre, creado y propiedad del agente de implementación, atendido por Application_Start de la nueva aplicación web y luego liberado por el agente de implementación una vez que se han realizado las actualizaciones de la base de datos.

(Utilizo un archivo de marcador en la aplicación web para habilitar el comportamiento de espera mutex) Una vez que se ejecuta la nueva aplicación web, elimino el archivo de marcador.

De acuerdo, ya que todos están bajando la respuesta que escribí allá en 2008 * …

Le diré cómo lo hacemos ahora en 2014. Ya no usamos sitios web porque ahora estamos usando ASP.NET MVC.

Ciertamente no necesitamos un equilibrador de carga y dos servidores para hacerlo, eso está bien si tiene 3 servidores por cada sitio web que mantiene, pero es un exceso total para la mayoría de los sitios web.

Además, no confiamos en el último asistente de Microsoft: demasiado lento y demasiada magia oculta, y demasiado propenso a cambiar su nombre.

Así es como lo hacemos:

  1. Tenemos un paso posterior a la comstackción que copia los archivos DLL generados en una carpeta ‘bin-pub’.

  2. Usamos Beyond Compare (que es excelente **) para verificar y sincronizar archivos cambiados (a través de FTP porque es ampliamente compatible) hasta el servidor de producción

  3. Tenemos una URL segura en el sitio web que contiene un botón que copia todo en ‘bin-pub’ a ‘bin’ (tomando primero una copia de seguridad para permitir una reversión rápida). En este punto, la aplicación se reinicia. Luego, nuestro ORM verifica si hay tablas o columnas que se deben agregar y crear.

Eso es solo un tiempo de inactividad de milisegundos. El reinicio de la aplicación puede tomar uno o dos segundos, pero durante el reinicio las solicitudes se almacenan en el búfer por lo que efectivamente no hay tiempo de inactividad.

Todo el proceso de implementación lleva de 5 segundos a 30 minutos, dependiendo de cuántos archivos se cambien y cuántos cambios se revisen.

De esta forma, no tiene que copiar un sitio web completo en un directorio diferente, sino simplemente en la carpeta bin. También tiene control total sobre el proceso y sabe exactamente qué está cambiando.

** Siempre hacemos un rápido vistazo a los cambios que estamos implementando, como una verificación doble de última hora, para saber qué probar y si algo se rompe, estamos listos. Usamos Beyond Compare porque le permite fácilmente diff archivos a través de FTP. Nunca haría esto sin BC, no tienes idea de lo que estás sobrescribiendo.

* Desplácese hasta la parte inferior para verla 🙁 Por cierto, ya no recomendaría sitios web porque son más lentos de comstackr y pueden fallar con la mitad de los archivos temporales comstackdos. Los usamos anteriormente porque permitían archivos más ágiles por archivo. implementación. Muy rápido para solucionar un problema menor y puede ver exactamente lo que está implementando (si usa Beyond Compare por supuesto, de lo contrario, olvídelo).

Los únicos métodos de inactividad cero que puedo pensar involucran el alojamiento en al menos 2 servidores.

Refinaría la respuesta de George un poco, como sigue, para un solo servidor:

  1. Utilice un proyecto de implementación web para precomstackr el sitio en una única DLL
  2. Comprime el nuevo sitio y súbelo al servidor
  3. Descomprímalo en una nueva carpeta ubicada en una carpeta con los permisos correctos para el sitio, para que los archivos descomprimidos hereden los permisos correctamente (quizás e: \ web, con las subcarpetas v20090901, v20090916, etc.)
  4. Use el Administrador de IIS para cambiar el nombre de la carpeta que contiene el sitio
  5. Mantenga la carpeta vieja por un tiempo, para que pueda recurrir a ella en caso de problemas

El paso 4 hará que el proceso de trabajo de IIS se recicle.

Esto es solo tiempo de inactividad cero si no está usando sesiones InProc; use el modo SQL en su lugar si puede (incluso mejor, evite el estado de la sesión por completo).

Por supuesto, es un poco más complicado cuando hay varios servidores y / o cambios en la base de datos ….

Para ampliar la respuesta de sklivvz, que se basaba en tener algún tipo de equilibrador de carga (o simplemente una copia en espera en el mismo servidor)

  1. Dirigir todo el tráfico al sitio / servidor 2
  2. Opcionalmente, espere un poco para asegurarse de que el menor número de usuarios tenga flujos de trabajo pendientes en la versión implementada.
  3. Implementar en el Sitio / Servidor 1 y calentarlo tanto como sea posible
  4. Ejecutar migraciones de base de datos de forma transaccional (esforzarse para que esto sea posible)
  5. Dirija inmediatamente todo el tráfico al Sitio / Servidor 1
  6. Implementar en Sitio / Servidor 2
  7. Tráfico directo a ambos sitios / servidores

Es posible introducir un poco de prueba de humo, creando una instantánea / copia de la base de datos, pero eso no siempre es factible.

Si es posible y necesario, utilice las “diferencias de enrutamiento”, como diferentes URL de inquilino: s (customerX.myapp.net) o diferentes usuarios, para implementar primero en un grupo desconocido de conejillos de indias. Si nada falla, libera a todos.

Como las migraciones de bases de datos están involucradas, volver a una versión anterior es a menudo imposible.

Hay formas de hacer que las aplicaciones jueguen mejor en estos escenarios, como usar colas de eventos y mecanismos de reproducción, pero dado que estamos hablando de implementar cambios en algo que está en uso, realmente no hay una manera infalible.

Así es como lo hago:

Requisitos mínimos del sistema absoluto:
1 servidor con

  • 1 equilibrador de carga / proxy inverso (por ejemplo, nginx) que se ejecuta en el puerto 80
  • 2 ASP.NET-Core / mono reverse-proxy / fastcgi chroot-jails o docker-containers que escuchan en 2 puertos TCP diferentes
    (o incluso solo dos aplicaciones de proxy inverso en 2 puertos TCP diferentes sin ningún sandbox)

Flujo de trabajo:

iniciar transacción myupdate

try Web-Service: Tell all applications on all web-servers to go into primary read-only mode Application switch to primary read-only mode, and responds Web sockets begin notifying all clients Wait for all applications to respond wait (custom short interval) Web-Service: Tell all applications on all web-servers to go into secondary read-only mode Application switch to secondary read-only mode (data-entry fuse) Updatedb - secondary read-only mode (switches database to read-only) Web-Service: Create backup of database Web-Service: Restore backup to new database Web-Service: Update new database with new schema Deploy new application to apt-repository (for windows, you will have to write your own custom deployment web-service) ssh into every machine in array_of_new_webapps run apt-get update then either apt-get dist-upgrade OR apt-get install  OR apt-get install --only-upgrade  depending on what you need -- This deploys the new application to all new chroots (or servers/VMs) Test: Test new application under test.domain.xxx -- everything that fails should throw an exception here commit myupdate; Web-Service: Tell all applications to send web-socket request to reload the pages to all clients at time x (+/- random number) @client: notify of reload and that this causes loss of unsafed data, with option to abort @ time x: Switch load balancer from array_of_old_webapps to array_of_new_webapps Decomission/Recycle array_of_old_webapps, etc. catch rollback myupdate switch to read-write mode Web-Service: Tell all applications to send web-socket request to unblock read-only mode end try 

Sugeriría guardar los archivos viejos allí y simplemente sobrescribirlos. De esta forma, el tiempo de inactividad se limita a los tiempos de sobrescritura de un solo archivo y solo falta un archivo a la vez.

Sin embargo, no estoy seguro si esto ayuda en una “aplicación web” (creo que estás diciendo que eso es lo que estás usando), y es por eso que siempre usamos “sitios web”. Además, la implementación de “sitios web” no reinicia su sitio y elimina todas las sesiones de los usuarios.