Implementar nuevo código en vivo

29

¿Cuál es la mejor práctica para implementar un nuevo código en un sitio en vivo (comercio electrónico)?

Por ahora, he detenido Apache durante +/- 10 segundos al cambiar el nombre del directorio public_html_newa public_htmlviejo public_html_old. Esto crea un breve tiempo de inactividad, antes de volver a iniciar Apache.

La misma pregunta se aplica si se usa Git para extraer el nuevo repositorio al directorio en vivo. ¿Puedo obtener el repositorio mientras el sitio está activo? ¿Y qué tal si necesito copiar una base de datos también?

Durante la compresión tar (propósito de copia de seguridad) del sitio en vivo, noté que ocurrieron cambios en el directorio de medios. Eso me indicó que los archivos siguen cambiando periódicamente. Y si estos cambios pueden interferir si Apache no se detiene durante la implementación.

nicoX
fuente

Respuestas:

13

Usar un equilibrador de carga es una buena idea. Si el sitio es lo suficientemente importante como para preocuparse por unos segundos de tiempo de inactividad, es lo suficientemente importante como para preocuparse por la tolerancia a fallas.

Aparte de eso, si esto está en un sistema UNIX, puede poner Apache en espera durante el cambio de nombre (o actualización de enlace simbólico, etc.):

killall -STOP httpd  # Pause all httpd processes
mv public_html public_html_orig
mv public_html_new public_html
killall -CONT httpd  # Resume all httpd processes

Esto evitará que Apache acepte nuevas solicitudes durante el cambio de nombre. Si prefiere enlaces simbólicos o algún otro enfoque, se puede usar la misma idea:

killall -STOP httpd  # Pause all httpd processes
rm /var/www/html
ln -s /var/www/version/03 /var/www/html
killall -CONT httpd  # Resume all httpd processes

Tenga en cuenta que cualquier conexión o paquete pendiente se pondrá en cola en el sistema operativo. Para un sitio extremadamente ocupado, considere ajustar ListenBacklog si es apropiado para su tipo de trabajador httpd, y verifique la configuración de su sistema operativo relacionada con el backlog de escucha TCP.

También puede cambiar DocumentRoot en httpd.conf y hacer un reinicio elegante ( apachectl graceful). El inconveniente aquí es el mayor riesgo de errores, ya que también tendría que actualizar cualquier Directoryconfiguración.

GargantuChet
fuente
¿La sesión de pausa todavía tiene el sitio en ejecución?
nicoX
44
Deja de darle tiempo de CPU a Apache. Si intentó acceder al sitio en un navegador mientras Apache está en pausa, el navegador estará esperando para conectarse hasta que se reanude Apache (o el navegador agota el tiempo de espera, si Apache está en pausa por más tiempo que el tiempo de espera). Si alguien está en el proceso de descargar un archivo, Apache dejará de enviar datos mientras está en pausa, nuevamente porque no está obteniendo ningún tiempo de CPU. Nuevamente, esto solo causará problemas si Apache se detiene durante tanto tiempo que la transferencia agota el tiempo de espera.
GargantuChet
55
Dicho de otra manera, el sitio no responderá mientras Apache esté en pausa, pero las operaciones pendientes finalizarán cuando se reanude. Los usuarios no recibirán "conexión rechazada" y las descargas no se interrumpirán, pero las operaciones solo continuarán cuando se reanude Apache. Esto asegurará que las transacciones existentes puedan finalizar, pero las nuevas solicitudes solo se manejarán después de que su nuevo contenido se traslade a su lugar.
GargantuChet
1
Tenga en cuenta que en cualquier sitio web de alto tráfico, esto podría matar fácilmente su servicio Apache. 200 rq / s eliminarán fácilmente su grupo de conexiones tan pronto como 'desbloquee' su proceso de Apache después del movimiento (si el movimiento toma un tiempo)
CloudWeavers
1
En un sitio de alto tráfico, habrá muchas solicitudes en vuelo para finalizar cuando se reanude Apache. Esto escalonará el procesamiento de nuevas solicitudes. También es un buen argumento para asegurarse de que su configuración de Apache (número máximo de subprocesos / servidores / clientes) es razonable y ajustar la acumulación de TCP en consecuencia. Aunque estoy confundido acerca de lo que quieres decir con "matar" el servicio. Apache es muy sintonizable.
GargantuChet
32

Lo más rápido y fácil es usar un directorio de versiones como

/var/www/version/01
/var/www/version/02

y use un enlace simbólico actual como su raíz_tml:

/var/www/html -> /var/www/version/02

Esta técnica se integra perfectamente en un sistema de control de revisión (svn, git, mercurial, ...) ya que puede retirar ramas y etiquetas, cambiar el enlace simbólico y volver a cargar Apache. El tiempo de inactividad es mínimo con esta técnica y permite una reversión muy fácil .

También se integra bien con un sistema de implementación más complejo, como paquetes RPM o infraestructura de gestión de cambios de configuración (chef, puppet, etc.).

CloudWeavers
fuente
44
La solución más simple siempre es la mejor ... :-) Por supuesto, no olvide mencionar que algunos FollowSymlinks y tales indicadores de apache en las configuraciones pueden ser necesarios.
Peter dice reinstalar a Mónica el
Tenga especial cuidado con lo que dijo @PeterHorvath. Apache puede ponerse muy malhumorado cuando trabaja con DocumentRoots con enlaces simbólicos. ¡Asegúrese de probar con cuidado!
mhutter
@mhutter Gracias :-) Lo que realmente problemático es que permite FollowSymLinks en Apache puede causar problemas de seguridad ...
Peterh dice Restablecer Mónica
Actualizar un enlace simbólico no es una operación atómica. Incluso usando algo como ln -snfpara bloquear el enlace simbólico original, la operación subyacente es una unlinky symlink. Existe la posibilidad de que los usuarios obtengan un 404 durante la actualización. Esto no es mejor que simplemente renombrar el directorio original y renombrar uno nuevo en su lugar (suponiendo que no esté cruzando sistemas de archivos). Vea la respuesta anterior con una marca de verificación al lado, que aborda esta preocupación.
GargantuChet
14

Cambiar el nombre de los directorios sin apagar Apache debería funcionar también. Eso acortará la ventana significativamente. mv public_html public_html_old && mv public_html_new public_htmldebería terminar en una fracción de segundo.

Un par de inconvenientes es que este enfoque dará respuesta 404a cualquier solicitud que aún se logre durante la ventana. Y si ejecuta el comando anterior sin tener un public_html_newdirectorio, fallará y le dejará un sitio dando 404cada solicitud.

Hacerlo atómicamente con directorios no es compatible. Pero podrías hacerlo con enlaces simbólicos. En lugar de tener un directorio llamado public_html, tenga un directorio llamado public_html.version-numbery un enlace simbólico llamado public_htmlapuntando a ese directorio. Ahora puede crear un directorio llamado public_html.new-version-numbery un nuevo enlace simbólico llamado public_html.new.

Luego puede cambiar el nombre public_html.newa public_htmlpara cambiar atómicamente. Tenga en cuenta que mves "demasiado inteligente" para realizar ese cambio de nombre, pero podría hacerse os.renamedesde Python o cualquier otra cosa que llame a la llamada del renamesistema sin intentar ser inteligente.

Lo que debe hacer con la base de datos depende de la base de datos que esté utilizando y para qué la esté utilizando. Debe proporcionar muchos más detalles sobre la base de datos antes de que podamos darle una buena respuesta a esa parte de su pregunta.

kasperd
fuente
1
En mi sistema Debian, mvtiene una -Topción que evita que siga el enlace simbólico. Esto le permitirá cambiar public_html.newel nombre atómicamente public_html, suponiendo que ambos sean enlaces blandos.
GargantuChet
11

Symlinks y mv son sus amigos, sin embargo, si realmente necesita evitar que los usuarios finales obtengan una página de error al implementar una nueva versión, debe tener un proxy inverso o un equilibrador de carga frente a al menos 2 servidores de fondo (apache en tu caso).

Durante la implementación, solo necesita detener un back-end a la vez, implementar el nuevo código, reiniciarlo y luego iterar en los backends restantes.

El proxy siempre dirigirá a los usuarios finales a buenos backends.

Giovanni Toraldo
fuente
44
Estaba trabajando en esta respuesta cuando vi que ya la publicaste. Los servidores Balancer + 2 hacen que el proceso sea invisible y más fácil de recuperar de una mala actualización ...
Bart Silverstrim
9

Si está aplicando cambios regularmente en un sistema de producción, me encargaría de un ciclo de vida estructurado. Una buena práctica es Capistrano http://capistranorb.com/ . Esta es una solución de código abierto para implementar software en uno o más servidores en varias plataformas y configuraciones.

Para Magento incluso hay un complemento: https://github.com/augustash/capistrano-ash/wiki/Magento-Example

Para un solo servidor y transiciones casi perfectas, recomiendo usar enlaces simbólicos.

Skiaddict
fuente
4

La forma en que lo hago es comprometer mis cambios desde mi entorno de desarrollo local a un repositorio Git en línea como Github. Mi entorno de producción se ejecuta en un repositorio remoto, por lo que todo lo que necesito hacer es enviar ssh al servidor y ejecutarlo git pullpara eliminar los últimos cambios. No es necesario detener su servidor web.

Si tiene archivos en su proyecto cuya configuración y / o contenido difieren de su versión local (como archivos de configuración y cargas de medios), puede usar variables de entorno y / o agregar estos archivos / directorios a un .gitignorearchivo para evitar la sincronización con el repositorio.

harryg
fuente
3

Mi primera idea es:

# deploy into public_html_new, and then:
rsync -vaH --delete public_html_new/ public_html/

Una buena solución fue usar rsync. Cambió solo los archivos realmente cambiados. Tenga cuidado, las barras al final de las manchas son aquí importantes.

Normalmente Apache no necesita reiniciar, no es el mundo de Java. Comprueba el cambio de cada archivo php a pedido y vuelve a leer (y vuelve a tokenizar) el cambio automáticamente.

Git pull fue similarmente eficiente, aunque fue un poco más difícil de escribir. Por supuesto, permitió un amplio espectro de diferentes posibilidades de detección de fusión / cambio.

Esta solución funcionará sin problemas solo si no hay cambios realmente importantes: si hay grandes cambios en la implementación, no se puede cerrar un poco de peligro, porque no hay un intervalo de tiempo insignificante, cuando el código se cambiará parcialmente y en parte no.

Si hay grandes cambios, mi sugerencia fue su solución inicial (dos renombrar).


Aquí hay un poco de hardcore, pero una solución 100% atómica:

(1) haga un montaje alternativo de su sistema de archivos, donde se lleva a cabo su magento

mount /dev/sdXY /mnt/tmp

(2) realice un --bindmontaje de public_html_new a public_html:

mount --bind /path/to/public_html_new /path/to/public_html

Desde este punto, el apache verá su nueva implementación. Cualquier cambio de un 404 es imposible.

(3) realice la sincronización con rsync, pero en el punto de montaje alternativo):

rsync -vaH --delete /mnt/tmp/path/to/public_html_new/ /mnt/tmp/path/to/public_html/

(4) retire el soporte de unión

umount /path/to/public_html
Peter dice que reinstalar a Mónica
fuente
¿El comando eliminará public_html e implementará public_html_new en él?
nicoX
@nicoX No, solo copiará los cambios.
Peter dice reinstalar a Mónica el
@nicoX Se ejecuta en ambas estructuras de directorio, y si encuentra una diferencia (archivo nuevo, archivo modificado, archivo eliminado), modifica el segundo directorio para que coincida con el primero, según sea necesario. El resultado si eliminó public_html y luego movió public_html_new a su lugar, pero sin ninguna posibilidad de un problema 404 temporal.
Peter dice reinstalar a Mónica el
1
No, esta no es una buena idea. Dependiendo de los cambios, es posible que tenga un breve período de tiempo en el que el código public_htmlesté en un estado inconsistente y no quiera aprovechar esta oportunidad.
Sven
@SvW Tienes razón, mi idea solo está bien si solo hay cambios menores. Extendí mi respuesta en consecuencia.
Peter dice reinstalar a Mónica el
1

Mover / reemplazar la http_publiccarpeta se puede lograr con simples mvo ln -scomandos o equivalentes mientras su servidor http sigue funcionando. Puede realizar algunas secuencias de comandos para reducir significativamente el tiempo de inactividad, pero verifique cuidadosamente los códigos de retorno de sus comandos en la secuencia de comandos si automatiza el proceso.

Dicho esto, si no desea lograr ningún tiempo de inactividad, su aplicación también debe admitirlo. La mayoría de las aplicaciones usan una base de datos para la persistencia. Tener la versión N de su aplicación jugando con la versión N + 1 (o al revés) de su modelo de datos puede romper las cosas si el equipo de desarrollo no lo prevé.

Por experiencia, mantener esa consistencia a través de actualizaciones no es un hecho para la mayoría de las aplicaciones. Un apagado adecuado, a pesar del tiempo de inactividad, es una buena manera de evitar problemas de coherencia.

Uriel
fuente