2011-07-12 24 views
6

Acabo de escribir un conjunto de clases de envío masivo de correos para manejar enormes cantidades de correos electrónicos y analizar su contenido de acuerdo con los parámetros pasados. Si pruebo un correo electrónico en 1000 destinatarios aleatorios y 1000 remitentes aleatorios de mi base de datos, hasta el punto en que el script acierta en la parte send() (lo comenté por ahora), obtengo un rendimiento de alrededor de 2 segundos y 20 MB de memoria máxima , Lo cual es genial.PHP, sendmail y transportes: cómo acelerar el envío de correos

Sin embargo, si descomiento la parte de envío, el envío tarda 30 segundos. Esto es inaceptable, y me gustaría acelerarlo de alguna manera. Es evidente por las pruebas que la demora es causada por nada menos que la llamada $ mail-> send(), como si estuviera esperando que devuelva algo antes de continuar el ciclo y enviar el siguiente correo electrónico.

Lo que me pregunto es: ¿cómo puedo acelerar la llamada a send()? ¿Qué puedo hacer para que sea más rápido? Intenté usar dos métodos de envío:

  1. Zend Transporte SMTP, conectándose directamente al servidor y simplemente enviando. Esto demora 30 segundos por cada 1000 correos electrónicos.
  2. Sendmail vía Zend_Mail. Simplemente llame a la función de envío de Zend_Mail después de preparar cada correo electrónico. Esto toma 60 segundos.

Tenga en cuenta que hacer cola es definitivamente una opción, y la he incorporado a mis clases. Todo lo que se necesita es activar un cron y funciona como un hechizo. Pero me pregunto sobre el envío real y cómo acelerarlo. Por lo tanto, la llamada real send().

Respuesta

2

me gustaría guardar los correos en un directorio y enviarlos usando un script de shell (cron/daemon/...):

Zend_Mail::setDefaultTransport(
    new Zend_Mail_Transport_File(
     array(
      'path' => __DIR__, 
      'callback' => function() { 
       do { 
        $file = 'email-' . date('Y-m-d_H-i-s') . '_' . mt_rand() . '.eml'; 
       } while (file_exists($file)); 
       return $file; 
      }, 
     ) 
    ) 
); 
+0

Corrígeme si me equivoco, pero una buena consulta de MySQL siempre superará la lectura de un archivo. El mecanismo de puesta en cola ya está hecho de cualquier manera, y no necesita ninguna mejora en este momento. Del mismo modo, nuestros correos electrónicos tienen cada uno un contenido diferente. Entonces, mientras enviamos 1000 correos electrónicos en 2 segundos, cada uno de ellos tiene un destinatario diferente, un remitente diferente y contenido diferente. Creo que este aspecto que muestra aquí puede ser útil solo en correos electrónicos masivos, ¿sí? Donde el contenido es idéntico en todos los mensajes? De lo contrario, la pregunta sigue siendo: ¿podría ser esto más rápido que hacer cola en la base de datos? Soy escéptico – Swader

+0

¡Pensé que el problema es ENVIAR NO GENERAR! :) Puede haber algún servidor de correo optimizado, que pueda cargar masivamente gazzilions de mensajes. Anycase: sería más rápido que el método sendmail de php. El acceso directo al servidor debe ser muchas veces mayor que php (puede, por ejemplo, usar una conexión persistente). –

+0

Hmmm, está bien. Un correo electrónico preparado podría guardarse fácilmente en el disco en formato eml y, a partir de ese momento, un script tomaría el relevo. Esto también podría servir decentemente como una cola alternativa. ¿Tiene algún ejemplo de esto de manera eficiente? Me encantaría echar un vistazo a algunos. – Swader

2

Deberá acelerar el MTA en el servidor. Recomiendo Postfix y que realmente leas cada configuración para que sepas cómo ajustarla. Para una solución comercial, escuché que PowerMTA es una buena opción, pero nunca lo he probado.

Puede exprimir tanto rendimiento de una máquina, pero un servidor dedicado regular debería poder entregar una cantidad bastante impresionante de correo una vez que lo haya configurado correctamente. El cuello de botella de mayor rendimiento suele ser el de las unidades de disco en las que se almacena la cola de correo, así que considere usar SAS (10k o incluso 15k RPM) o unidades SSD.

+0

Definitivamente voy a mirar en esto. Nuestra salida de correo electrónico aumentará significativamente muy pronto, y tal aumento podría ser bastante necesario. – Swader

+0

Hemos comenzado a planificar este enfoque, pero también incluiremos la respuesta de Tomás en nuestra solución. En realidad, ha demostrado ser increíblemente increíble, hasta ahora. – Swader

0

Puede intentar profundizar en la función PHP pcntl-fork. Por lo tanto, puede dejar el envío en otro proceso mientras analiza el siguiente correo electrónico.

PLAN B

Puede serializar y guardar el objeto de correo electrónico en una cola de base de datos y dejar que otro script para enviarlos en el fondo. Este script podría ejecutarse en bucle infinito (while true) con un poco de sleep en cada iteración. Incluso puede ejecutar varias instancias de este script, pero asegúrese de que dos scripts no comiencen a enviar el mismo correo electrónico simultáneamente.

Para asegurarse de que la secuencia de comandos todavía se está ejecutando, puede usar monit en máquinas Unix. Puede iniciar el script si la instancia anterior ha fallado por algún motivo.

+0

Hmm, esto parece muy atractivo, pero ¿no es un hecho que las funciones de PCNTL no están disponibles si PHP se ejecuta como un módulo de Apache? Me parece recordar haber leído algo sobre eso en alguna parte, pero ya no puedo encontrar la información. Además, PCTNL no está disponible en máquinas con Windows, y desarrollo esta aplicación en todo tipo de sistema operativo, dependiendo de dónde estoy en un momento dado. – Swader

+0

Tengo plan agregado B. – Gedrox

+0

Ya estoy usando este tipo de colas. Los datos del correo electrónico se serializan y se guardan en el DB con la prioridad dada. El cronjob maneja el envío periódicamente obteniendo 500 de los correos electrónicos de mayor prioridad cada 15 minutos, y parece estar todo bien. Pero lo que realmente quiero es acelerar la función send(), y un servidor dedicado probablemente sea la única y la mejor solución a largo plazo. – Swader

Cuestiones relacionadas