You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by Joan Carles N��ez <jo...@indibil.com> on 2001/02/22 11:18:42 UTC

System Load

Hi all,

   I have been playing with James and I am very impressed with its design
and stability.
I have been testing it with MySQL, Interbase and I am about to test it with
Oracle. I have written a stress test program which you can find at the end
of this message. When I push the server to handle heavy loads the JDBC driver
for Interbase starts to throws Exceptions when recovering blobs.

Question: Does James deal with system load limits? Looking at the source of 
sendmail I see that they use a function called "shouldQueue" which takes the
system load and if it is higher than 1 then it queues the message. It starts
to deliver more messages when the load goes under 1. In this way it protects
itself like transaction monitors do. With James I have seen my machine go to
load levels of 10 or higher. Does James have/need such functionality? 

Cheers,

       Joan Carles

package org.apache.james.testing;

import javax.mail.*;
import javax.mail.internet.*;
import java.util.*;

/**
 * Program that hammers a James server with multiple threads (5) at a rate
 * stablished in miliseconds (args[0]), a certain number of iterations (args[1]).
 * Two types of threads, SMTPSender which send a message for a particular user and
 * POPReceiver which reads all messages from a particular user and deletes them.
 *
 * @author Joan Carles Núñez  <jo...@indibil.com>
 */
public class StressTesting {
    static String hostSender = "@mydomain.com";
    static String[][] user = {{"jordi","jordi"},{"xavier","xavier"},{"jc","jc"},{"hernan","hernan"},{"marcel","marcel"}};
    public static void main(String[] args) throws Throwable {
        int numThreads = user.length;
        int interval = 1000; 
        int iterations = 1000;
        if (args.length >= 1) interval = Integer.valueOf(args[0]).intValue();
        if (args.length >= 2) iterations = Integer.valueOf(args[1]).intValue();
        for (int i = 0; i < numThreads ; i++) { 
          SMTPSender sender = new SMTPSender("1.1.1.6",user[i][0],user[i][1],interval,iterations);
          POPReceiver receiver = new POPReceiver("1.1.1.6",user[i][0],user[i][1],interval,iterations);
          new Thread(sender).start();         
          new Thread(receiver).start();
        }
    }
}

class SMTPSender implements Runnable {
   private String mailHost;
   private String user;
   private String password;
   private int interval = 1000;
   private int iterations = 1000;
   private Properties prop = new Properties();
   private int messagesSentOk = 0;
   private int messagesWithException = 0;

   public SMTPSender (String host, String user, String password, int interval,int iterations) {
        this.mailHost = host;
        this.user = user;
        this.password = password;
        this.interval = interval;
        this.iterations = iterations;
        prop.put("mail.smtp.host", mailHost);
   }

   public void run() {
        for (int i = 0; i < iterations ; i++) {
           sendMail(i); 
           try {
            Thread.currentThread().sleep(interval);
           } catch (Exception ex) {}
        }

        System.out.println("Summary: Messages Sent OK: " + messagesSentOk + ", Messages Failed: " + messagesWithException);
   }
   
   /** Send a message with msgId as the subject */
   void sendMail(int msgId) {
        try {
            Session session = Session.getDefaultInstance(prop, null);
            MimeMessage msg = new MimeMessage(session);
            msg.setFrom(new InternetAddress(user+StressTesting.hostSender));
            msg.addRecipient(Message.RecipientType.TO, new InternetAddress(user+StressTesting.hostSender));
            msg.setContent("Hola mon", "text/plain");
            msg.setSubject(String.valueOf(msgId));
            Transport.send(msg);
            System.out.println("Sent message OK: " + msgId +
                    " from: " + msg.getFrom()[0] + " To: " +
                    msg.getAllRecipients()[0]);
            messagesSentOk++;
        } catch (Throwable e) {
            messagesWithException++;
            e.printStackTrace();
        }
    }
}

class POPReceiver implements Runnable {
   private String mailHost;
   private String user;
   private String password;
   private int interval = 1000;
   private int iterations = 1000;
   private Properties prop = new Properties();
   private int messagesReceivedOk = 0;
   private int messagesReceivedWithException = 0;

   public POPReceiver (String host, String user, String password, int interval,int iterations) {
        this.mailHost = host;
        this.user = user;
        this.password = password;
        this.interval = interval;
        this.iterations = iterations;
        prop.put("java.smtp.host", mailHost);
   }

   public void run() {
        for (int i = 0; i < iterations ; i++) {
           receiveMail(true);
           try {
            Thread.currentThread().sleep(interval);
           } catch (Exception ex) {}
        }

        System.out.println("Summary: Messages Received OK: " + messagesReceivedOk + ", Messages Failed: " + messagesReceivedWithException);
   }
  
   /** Receive Messages from POP3 server, Print details of each message, check that contents are the
    *  the same as the message sent and delete each message if delete flag is true.
    */
   void receiveMail(boolean delete) {
        Store store = null;
        Folder folder = null; 
        try {
            // Fetch INBOX Folder
            Session session = Session.getDefaultInstance(prop, null);
            store = session.getStore("pop3");
            store.connect(mailHost, user, password);
            folder = store.getFolder("INBOX");
            if(folder == null || !folder.exists()) {
                System.out.println("This folder does not exist.");
                return;
            }
            folder.open(Folder.READ_WRITE);
            
            // Process Messages in INBOX folder
            Message[] msgs = folder.getMessages();
            System.out.println("Received " + msgs.length + " messages for " + user);
            for (int i = 0; i < msgs.length; i++) {
              Message msg = msgs[i];
              System.out.println("From: " + msg.getFrom()[0].toString() +"\nTo: " + msg.getRecipients(Message.RecipientType.TO)[0] + "\nSubject: " + msg.getSubject() + "\n-------------------");
              // Check that the contents have not been altered
              //if (msg.getContent().toString().length() != 1500000) System.out.println("Message received with wrong size...");
               
              // Delete the message 
              if(delete) {
                msg.setFlag(Flags.Flag.DELETED, true);
                System.out.println(msg.getSubject() +" Deleted.");
              }
              messagesReceivedOk++;
            }
        } catch (MessagingException e) {
            e.printStackTrace();
            messagesReceivedWithException++;
        } catch (Throwable e) {
            e.printStackTrace();
            messagesReceivedWithException++;
        } finally {
           // Close folder and store...
           try { folder.close(true); store.close(); } catch (Throwable t) {}
        }
    }
}




RE: System Load

Posted by Joan Carles <jo...@indibil.com>.
----- Original Message -----
From: Serge Knystautas <se...@lokitech.com>
To: <ja...@jakarta.apache.org>
Sent: Monday, February 26, 2001 5:27 PM
Subject: Re: System Load


> ----- Original Message -----
> From: "Joan Carles" <jo...@indibil.com>
>
>
> > Correct me if I am wrong, here go some thoughts:
> > It is always desirable that a machine does not go over system load =1.
If
> > this
> > happens very often then it is a matter of upgrading or adding more
> servers.
> > The thing is, the server should handle peak times smoothly without the
> need
> > of upgrading.
> > Sendmail's design is based on forking a process for every request.
That's
> > why
> > it will stop processing mails (and queue them) when the number of
requests
> > is
> > very high and the system load goes over 1, it basically concentrates in
> > keeping
> > up with requests.
> > If James creates a new Thread per request then it should apply the same
> > principle.
> > All in all, it is a matter of avoiding excesive use of resources
(threads,
> > sockets,
> > cpu etc).
> > In the case of RDBMS based queues, processing mail may increase the
> > load quite a lot. System load indicates the average number of processes
> held
> > in
> > the queue waiting for CPU time. In my experience, when load is very high
> the
> > system starts to behave differenly and exponential growth of
> > threads/sockets/queueing
> > is a situation that may bring the server down to its knees.
> >
> > What do you think?
> >
> >    J. C.
>
> I don't think this is how James works.  James starts by defining X number
of
> threads that process mail, Y number of threads that deliver mail.
Incoming
> SMTP and POP3 requests create/destroy their own threads, but this is
> independent of what's being discussed (from what I can tell).  Basically,
> you're looking for James not to exponentially grow thread to process mail
or
> remotely deliver mail, which it does not.  The X and Y threads sleep until
> there's something to do, waking up when something is there for them.  I'd
> say it would be nice to lower the priority on some of these, but I'm not
> sure how feasible that is using Avalon (or rather, what is the best way to
> do that)
>
> What restrictions are you looking to put on the thread behavior?  I'd like
> to understand this better before coming up with a way to monitor load.

Allright then, X and Y do the trick. I believe that when I observed system
loads
of 10 or higher it was due to the fact that I was using a RDBMS queue (JDBC
+ Interbase running on the same machine). So giving less priority to
processing
threads (delivery) or making Y smaller would do keep system load around 1.
I would imagine that server tuning would involve finding the correct Y
value.

Cheers,

          J. C.




Re: System Load

Posted by Serge Knystautas <se...@lokitech.com>.
----- Original Message -----
From: "Joan Carles" <jo...@indibil.com>


> Correct me if I am wrong, here go some thoughts:
> It is always desirable that a machine does not go over system load =1. If
> this
> happens very often then it is a matter of upgrading or adding more
servers.
> The thing is, the server should handle peak times smoothly without the
need
> of upgrading.
> Sendmail's design is based on forking a process for every request. That's
> why
> it will stop processing mails (and queue them) when the number of requests
> is
> very high and the system load goes over 1, it basically concentrates in
> keeping
> up with requests.
> If James creates a new Thread per request then it should apply the same
> principle.
> All in all, it is a matter of avoiding excesive use of resources (threads,
> sockets,
> cpu etc).
> In the case of RDBMS based queues, processing mail may increase the
> load quite a lot. System load indicates the average number of processes
held
> in
> the queue waiting for CPU time. In my experience, when load is very high
the
> system starts to behave differenly and exponential growth of
> threads/sockets/queueing
> is a situation that may bring the server down to its knees.
>
> What do you think?
>
>    J. C.

I don't think this is how James works.  James starts by defining X number of
threads that process mail, Y number of threads that deliver mail.  Incoming
SMTP and POP3 requests create/destroy their own threads, but this is
independent of what's being discussed (from what I can tell).  Basically,
you're looking for James not to exponentially grow thread to process mail or
remotely deliver mail, which it does not.  The X and Y threads sleep until
there's something to do, waking up when something is there for them.  I'd
say it would be nice to lower the priority on some of these, but I'm not
sure how feasible that is using Avalon (or rather, what is the best way to
do that)

What restrictions are you looking to put on the thread behavior?  I'd like
to understand this better before coming up with a way to monitor load.

Serge Knystautas
Loki Technologies
http://www.lokitech.com/


RE: System Load

Posted by Joan Carles <jo...@indibil.com>.
----- Original Message -----
From: Federico Barbieri <sc...@betaversion.org>
To: <ja...@jakarta.apache.org>
Sent: Monday, February 26, 2001 1:37 PM
Subject: Re: System Load


> "Joan Carles Núñez" wrote:
> >
> > Hi,
> >
> >    Ok. Would it be a matter of writing a native C function that queries
system
> > load and call that from the JVM via JNI?
> > Doing this for Linux should be easy, don't know about Windows...
> >
> >        J. C.
> >
>
> On a second though I'm not sure if this can better performances... there
> are mainly three groups of threads... those acceptiong mail (SMTP),
> those processing (mailets) and those providing services (POP3, IMAP).
> In theory acceptiong threads should have always better priority than the
> other two and service threads should be faster than processing threads,
> no matter haw heavy the system load is.
>
> In some extreme situstion it may make sense to freze a group of threads
> (limit the number of active threads in that group):
> If the buffer is full limit accepting threads, if the number of users is
> high limit processing etc.
>
> In all this situation thou I don't see any specific reaction to the
> system load... not sure...

Correct me if I am wrong, here go some thoughts:
It is always desirable that a machine does not go over system load =1. If
this
happens very often then it is a matter of upgrading or adding more servers.
The thing is, the server should handle peak times smoothly without the need
of upgrading.
Sendmail's design is based on forking a process for every request. That's
why
it will stop processing mails (and queue them) when the number of requests
is
very high and the system load goes over 1, it basically concentrates in
keeping
up with requests.
If James creates a new Thread per request then it should apply the same
principle.
All in all, it is a matter of avoiding excesive use of resources (threads,
sockets,
cpu etc).
In the case of RDBMS based queues, processing mail may increase the
load quite a lot. System load indicates the average number of processes held
in
the queue waiting for CPU time. In my experience, when load is very high the
system starts to behave differenly and exponential growth of
threads/sockets/queueing
is a situation that may bring the server down to its knees.

What do you think?

   J. C.









Re: System Load

Posted by Federico Barbieri <sc...@betaversion.org>.
"Joan Carles Núñez" wrote:
> 
> Hi,
> 
>    Ok. Would it be a matter of writing a native C function that queries system
> load and call that from the JVM via JNI?
> Doing this for Linux should be easy, don't know about Windows...
> 
>        J. C.
> 

On a second though I'm not sure if this can better performances... there
are mainly three groups of threads... those acceptiong mail (SMTP),
those processing (mailets) and those providing services (POP3, IMAP).
In theory acceptiong threads should have always better priority than the
other two and service threads should be faster than processing threads,
no matter haw heavy the system load is.

In some extreme situstion it may make sense to freze a group of threads
(limit the number of active threads in that group):
If the buffer is full limit accepting threads, if the number of users is
high limit processing etc. 

In all this situation thou I don't see any specific reaction to the
system load... not sure...


Fede

Re: System Load

Posted by Joan Carles N��ez <jo...@indibil.com>.
Hi, 

   Ok. Would it be a matter of writing a native C function that queries system
load and call that from the JVM via JNI?
Doing this for Linux should be easy, don't know about Windows...

       J. C.
  

On Sun, 25 Feb 2001 05:51:12 -0800
Federico Barbieri <sc...@betaversion.org> wrote:

> "Joan Carles Núñez" wrote:
> > 
> > Hi all,
> > 
> >    I have been playing with James and I am very impressed with its design
> > and stability.
> > I have been testing it with MySQL, Interbase and I am about to test it with
> > Oracle. I have written a stress test program which you can find at the end
> > of this message. When I push the server to handle heavy loads the JDBC driver
> > for Interbase starts to throws Exceptions when recovering blobs.
> > 
> > Question: Does James deal with system load limits? Looking at the source of
> > sendmail I see that they use a function called "shouldQueue" which takes the
> > system load and if it is higher than 1 then it queues the message. It starts
> > to deliver more messages when the load goes under 1. In this way it protects
> > itself like transaction monitors do. With James I have seen my machine go to
> > load levels of 10 or higher. Does James have/need such functionality?
> > 
> > Cheers,
> > 
> >        Joan Carles
> > 
> 
> If I'm not wrong james impl queque ALL incoming messages so processing
> and sending is done asichronusly. SMTPHandler send messages to james
> wich just queque them (James.java line 403). 
> 
> It could be nice to be able to dynamically change threads priority to
> balance pushes and pops in and from the queque thou I think it's quite a
> pain to query the jvm for system load...
> 
> Fede
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: james-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: james-dev-help@jakarta.apache.org

Re: System Load

Posted by Federico Barbieri <sc...@betaversion.org>.
"Joan Carles Núñez" wrote:
> 
> Hi all,
> 
>    I have been playing with James and I am very impressed with its design
> and stability.
> I have been testing it with MySQL, Interbase and I am about to test it with
> Oracle. I have written a stress test program which you can find at the end
> of this message. When I push the server to handle heavy loads the JDBC driver
> for Interbase starts to throws Exceptions when recovering blobs.
> 
> Question: Does James deal with system load limits? Looking at the source of
> sendmail I see that they use a function called "shouldQueue" which takes the
> system load and if it is higher than 1 then it queues the message. It starts
> to deliver more messages when the load goes under 1. In this way it protects
> itself like transaction monitors do. With James I have seen my machine go to
> load levels of 10 or higher. Does James have/need such functionality?
> 
> Cheers,
> 
>        Joan Carles
> 

If I'm not wrong james impl queque ALL incoming messages so processing
and sending is done asichronusly. SMTPHandler send messages to james
wich just queque them (James.java line 403). 

It could be nice to be able to dynamically change threads priority to
balance pushes and pops in and from the queque thou I think it's quite a
pain to query the jvm for system load...

Fede