Generalidades sobre FastCGI

Generalidades

FastCGI es una forma de hacer que los scripts CGI ejecuten código que consume mucho tiempo (como abrir una base de datos) solo una vez, en lugar de cada vez que se carga el script. En términos técnicos, FastCGI es una extensión abierta, escalable e independiente del lenguaje de CGI que proporciona un alto rendimiento sin las limitaciones de las API específicas del servidor.

Diferencia entre FCGI y CGI

CGI

CGI es un protocolo para servidores web para correr programas web dinámicos.

CGI crea nuevos procesos para cada solicitud, lo que hace que los programas CGI sean simples de implementar, pero limita la eficiencia y la escalabilidad. Con cargas elevadas, la sobrecarga de creación de procesos CGI se vuelve significativa.

FCGI

FCGI es una variación más reciente de CGI que ayuda a reducir la sobrecarga asociada con los programas CGI, lo que permite que un servidor maneje más solicitudes de páginas web a la vez.

FCGI utiliza procesos persistentes para manejar una serie de solicitudes. Cada proceso FastCGI individual puede manejar muchas solicitudes a lo largo de su vida, evitando así la sobrecarga de la creación y terminación del proceso por solicitud.

Diferencias

FCGI es una versión mejorada de CGI que se ejecuta más rápido, sin embargo, dado que los procesos FCGI siempre se están ejecutando, el servidor utiliza más memoria.

En general, FCGI es recomendada.

Detalles de configuración

Esta es la configuración actual de FastCGI (mod_fastcgi) en DreamHost:

FastCgiConfig -autoUpdate -initial-env RAILS_ENV=production -idle-timeout 60 -startDelay 10 -maxClassProcesses 2 -killInterval 300

Estos ajustes son casi exactamente la configuración predeterminada para FastCGI.

En los servidores privados de DreamHost, FastCGI es manejado por mod_fcgid en lugar de mod_fastcgi.

mod_fcgid es un módulo de Apache que proporciona una interfaz FastCGI. Es una alternativa a mod_fastcgi que está específicamente ajustada para la configuración dinámica FastCGI utilizada en los servidores DreamHost.

Hacer cambios en tus scripts

Estructura de un script FastCGI

Los scripts FastCGI tienen dos secciones:

  1. Código que se corre solo una vez (como abrir una base de datos).
  2. Código que se corre todo el tiempo.

Aquí hay un ejemplo con Perl:

#!/usr/bin/perl

#-----------------------
#  CODE THAT RUNS ONCE
#-----------------------
    $counter=0;

#---------------------------------
#  CODE THAT RUNS EVERY TIME
#---------------------------------

use FCGI;
while ( FCGI::accept() >= 0 ) {
     $counter++;
     print "Content-type:text/html\n\n";
     print "I have run $counter times.";
}

Si bien puedes pensar que necesitas imprimir el encabezado solo una vez, de hecho el encabezado debe estar incluido en la sección RUNS EVERY TIME.

Sin exits

Si tu secuencia de comandos termina con algún comando (como exit; o last; en Perl), la secuencia de comandos comienza desde cero la próxima vez que se ejecuta, perdiendo los beneficios de ejecutar cierto código solo una vez. Además, si un script se termina de esta manera, es posible que no se vuelva a ejecutar durante varios minutos.

El síntoma es que el navegador intenta cargar la página durante un par de minutos, y finalmente se da por vencido con "an error occurred while processing this directive". El error es aún más frustrante porque tú (o tus usuarios) tienen que esperar varios minutos para obtenerlo.

La solución es utilizar cualquier control de flujo disponible en tu lenguaje de programación para que el script finalice por sí solo. Aquí hay un ejemplo de antes y después en Perl con algún pseudocódigo:

Wrong way
#!/usr/bin/perl

#-----------------------
#  CODE THAT RUNS ONCE
#-----------------------
     (open a database)

#---------------------------------
#  CODE THAT RUNS EVERY TIME
#---------------------------------

use FCGI;
while ( FCGI::accept() >= 0 ) {
      print "Content-type:text/html\n\n";

      if (some test) { exit;}

      more code;
}
Right way
#!/usr/bin/perl

#-----------------------
#  CODE THAT RUNS ONCE
#-----------------------
     (open a database)

#---------------------------------
#  CODE THAT RUNS EVERY TIME
#---------------------------------

use FCGI;

while ( FCGI::accept() >= 0 ) {
      print "Content-type:text/html\n\n";

      if (some test) { goto(EXITLABEL) }

      more code;

      EXITLABEL: {}
}

Usar $ENV{'QUERY_STRING'} en vez de @ARGV

No puedes obtener la cadena de consulta en FastCGI utilizando la matriz @ARGV. Debes usar $ENV{'QUERY_STRING'} en su lugar.

Errores y solución de problemas

Los scripts incorrectos no devolverán un error de inmediato; debes esperar un par de minutos hasta que se agote el tiempo de espera del script. Si la secuencia de comandos está en una página web, parece que la página se bloquea, e incluso cuando se agota el tiempo de espera de la secuencia de comandos, es posible que no se registre el mensaje de error real y que solo vea un error 500. Esto significa que las pruebas con FastCGI no son prácticas. El desarrollo debe realizarse con CGI estándar o en tu computador local. El FastCGI debe agregarse después de que el script ya haya sido depurado.

Además, si bien es tentador desarrollar en un servidor en vivo, es peligroso y lo convierte en un mal vecino para el alojamiento compartido.

Para ver inmediatamente si un script falla (no verificará todos los casos porque % ENV es diferente), pruébalo desde la línea de comando:

[server]$ perl ~/example.com/myscript.fcgi

o, para una verificación más profunda, si puedes usar el depurador:

[server]$ perl -d ~/example.com/myscript.fcgi

Si has introducido un error en una secuencia de comandos, es posible que corregir el error no lo solucione de inmediato, porque a veces el servidor todavía está ejecutando una versión anterior de la secuencia de comandos desde la memoria por varias razones. (Se supone que el servidor debe mirar la fecha de modificación del archivo para que siempre esté ejecutando la versión más reciente, pero este no suele ser el caso. Cuando el servidor falla al hacer esto, ejecutar touch en el archivo no ayuda, tampoco).

Para que el servidor ejecute la versión actual del script, busca el proceso anterior y elimínalo:

[server]$ killall -USR1 scriptname.fcgi     (replace scriptname.fcgi with the name of the process)

El comando anterior no siempre puede convencer a todos los procesos de que se detengan. Para obligarlos a parar, usa:

[server]$ killall -9 scriptname.fcgi   (replace scriptname.fcgi with the name of the process)

Ocasionalmente, es posible que debas utilizar ruby1.8 como ID de tarea:

[server]$ killall -9 ruby1.8

Mi FastCGI no funciona

Asegúrate de que el script que estás intentando ejecutar esté configurado como ejecutable:

[server]$ chmod +x myscript.fcgi

Verifica el registro de errores si estás obteniendo el error:

[Fri Sep 05 11:55:03 2008] [error] [client 123.45.67.89] FastCGI: comm with (dynamic) server "/home/username/example.com/myscript.fcgi" aborted: (first read) idle timeout (60 sec)

Asegúrate de verificar los permisos de tu archivo y directorio. El directorio que contiene el fcgi, y el propio fcgi, debe ser propiedad de tu grupo Unix predeterminado y ser de escritura grupal:

[server]$ chgrp -R `groups | awk '{print $1}'` ~/example.com/
[server]$ chmod -R g+w ~/example.com/

Además, verifica si tienes una directiva similar:

RewriteRule ^(.*)$ scriptname.cgi [QSA,L]

Debe ser cambiada a:

RewriteRule ^(.*)$ scriptname.fcgi [QSA,L]

Finalmente, intenta borrar todas las sesiones de tu carpeta /tmp (si estás en un servidor VPS o Dedicado).

Ver también

¿Este artículo ha respondido sus preguntas?

Última actualización el PST.

¿Aún no encuentra lo que busca?