|
dgc / software / HAPPYMAIL for Qpopper
|
Background
In the University of Chicago's central mail services group, we use
Qualcomm's
Qpopper [1]
POP3 server (along with UW-IMAP) to provide
mail to approximately 25,000 clients. We find that there's always a
subset of users who persistently, almost perniciously, will fetch
their mail as often as possible, whether it's needed now or not --
and, to make things worse, have their mail clients set to "leave mail
on server". With Qpopper particularly, this makes performance drag
unbearably: with several hundred users popping regularly and frequently
from inboxes stuffed with 25 to 100 MB of messages, there's a lot
of unneeded spool I/O that degrades the system for all those other
customers using it more responsibly.
We began by enabling server mode in qpopper, but that wasn't enough -- some people were simple checking mail much, much too often. So we decided that we needed more serious rate limiting, but qpopper didn't have it.
Implementation
The
HAPPYMAIL patch [2]
provides this. It allocates a 256K shared memory segment — essentially,
an array of 2^16 32-bit integers — that is known to each instance of
popper. Each time a user authenticates successfully, the user's UID and
the current time are associated into the shared memory segment. When the
user next authenticates, the current time is compared to the timestamp
in the shared memory. If the user hasn't waited "long enough", he is
rejected with an error message such as:
-ERR [AUTH] Please wait at least 15 minutes between checks
The shared memory segment is good because it avoids filesystem access, and there's never any contention for it between popper instances because each popper only looks at the 4 bytes assigned to the UID it's serving. Failed authentications don't count against you — the check/store doesn't occur until you've successfully authenticated, but before any mailboxes are copied or locked.
Configuration
The check-wait period is not only configurable; it can be dynamically
calculated based on the size of the authenticating user's inbox. There
are four parameters that go into this computation. All are configurable
either in the popper.conf file or on the popper command
line.
|
So, suppose I've set these parameters in popper.conf:
set happymail-base=300 # 5 minutes set happymail-free=10485760 # 10 MB set happymail-rate-seconds=60 # 1 minute set happymail-rate-bytes=5242880 # 5 MBIn this example, no user will be allowed to check more often than once each 5 minutes (
happymail-base); each user may have
10 MB (happymail-free) of mail before additional time is
levied; and above that 10 MB, users will be required to wait an
additional minute (happymail-rate-seconds) per 5 megabytes
(happymail-rate-bytes) in the inbox. So a person with 44 MB of
mail would wait 11 minutes between mail checks — that's
5m + (1m * ( (44mb-10mb) / 5mb )).
If you just want to make everyone wait 15 minutes between
checks, regardless of how much mail they have, you'd just set
happymail-base to 900, and the others to zero.
Inquiry and Adjustment
This system has worked well — it immediately relieved a lot of pressure
on our heavily-laden mail server. But we anticipated that there would be
a lot of calls to our support center over this, as well as an occasional
need to allow someone an immediate mail check even though the timer
would otherwise not allow it. So I wrote a supplementary program called
HAPPYTOOL [3]
. HAPPYTOOL lets you
inquire the last mail check time of:
For more information on this, see the HAPPYTOOL README file [4] .
configure with the
--enable-happymail option. So, a typical installation for me
looks like:
|
happymail-bufsiz in
the popper.conf to configure a larger buffer size for maildrop
copies.
popper.conf.happymail file. Added happymail-max setting and
associated notation. Fixed dumb bug with (happymail-free) checking that
made the whole thing basically not work, but fortunately only existed
in pl7 for a few hours. (Grr.) Improved CAPA's X-HAPPYMAIL
notation. Made happymail-bufsiz take units notation, or assume
small integers to be kilobytes (as previously documented). This lasted
us a year without patching; I really hope I'm done now.