apache process tuning

A long, long time ago I had an opportunity to fine-tune apache processes on a couple hundred hosts. It took one script run on some of the highly-loaded hosts to get specific numbers, and those numbers are what are important.

For shell processing you’ll need bc.

Running the below program on my current host presents the following output:

sudo ./apache_process_tuning.pl
1035:11956224 1036:19152896 1037:16871424 1038:32567296 1039:11386880 1040:13230080 1041:15876096 1042:20291584 2131:14344192 2132:14438400 2133:13373440 10578:15732736 29812:2068480
==========
There are 13 Apache Processes that consume 201,289,728 bytes of RAM
Each process takes an average of 15,483,825 bytes of RAM

You have 2,103,779,328 bytes of RAM, with 1,756,119,040 unused if Apache were not running

You can be ok with a MAX_CLIENTS setting lower than 113

To the gods of perl, I present thee!

#!/usr/bin/perl
use strict;
use warnings
# http://www.perlmonks.org/?node_id=110137
sub commify {
   my $text = reverse $_[0];
   $text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g;
   return scalar reverse $text
}
# step 0, make sure we are sudo
die("Need to sudo this command") if ( not defined $ENV{'SUDO_USER'} );
# Step 1, get system memory information
my $free = `/usr/bin/free -mb`;
my ($mem_total, $mem_used, $mem_free);
for (split /^/, $free) {
   if ($_ =~ /Mem:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/) {
      $mem_total = $1;
      $mem_used = $2;
      $mem_free = $3;
   }
}
die("Cannot get memory statistics") if (not defined $mem_total);
# Step 2, get httpd process
my $processes = `/bin/ps aux`;
my ($process_count, $process_total, $process_mem);
for (split /^/, $processes) {
   if ($_ =~ /(\w+)\s+(\d+)\s+[\d\.]+\s+[\d\.]+\s+\d+\s+\d+\s+[\w\?\/]+\s+[\w\+<]+\s+[\d\w:]+\s+[\d:]+\s+(.+)/) {
      my $proc_owner = $1;
      my $proc_pid = $2;
      my $proc_cmd = $3;
      if ($proc_cmd =~ /httpd$/) {
         # Step 2a, Get some Private_Dirty
         # http://stackoverflow.com/questions/118307/a-way-to-determine-a-processs-real-memory-usage-i-e-private-dirty-rss
         $process_mem = `awk '/Private_Dirty/ {print \$2,\$3}' /proc/${proc_pid}/smaps | sed 's/ tB/*1024 gB/;s/ gB/*1024 mB/;s/ mB/*1024 kB/;s/ kB/*1024/;1!s/^/+/;' | tr -d '\\n' | sed 's/\$/\\n/' | bc`;
         chomp($process_mem);
         $process_count++;
         $process_total+=$process_mem;
         print $proc_pid . ":" . $process_mem . " ";
      }
   }
}
die("Having a problem getting active httpd info") if (not defined $process_count);
# step 3, give some helpful output
my ($process_average, $unused_mem, $max_clients);
print "\n==========\n";
$process_average = sprintf("%d", $process_total / $process_count);
print "There are " . $process_count . " Apache Processes that consume " . commify($process_total) . " bytes of RAM\n";
print "Each process takes an average of " . commify($process_average) . " bytes of RAM\n";
print "\n";
$unused_mem = sprintf("%d", $mem_used - $process_total);
print "You have " . commify($mem_total) . " bytes of RAM, with " . commify($unused_mem) . " unused if Apache were not running\n";
print "\n";
# Math is: "available" RAM with no httpd divided by average process total
$max_clients = sprintf("%d", $unused_mem / $process_average);
print "You can be ok with a MAX_CLIENTS setting lower than " . $max_clients . "\n";
print "\n";

Verses Three

Il Dolce Suono

Italian

Il dolce suono mi colpì di sua voce!
Ah, quella voce m’è qui nel cor discesa!
Edgardo! io ti son resa. Edgardo! Ah! Edgardo, mio! Si’, ti son resa!
fuggita io son da’ tuoi nemici. (nemici)
Un gelo me serpeggia nel sen!
trema ogni fibra!
vacilla il piè!
Presso la fonte meco t’assidi alquanto! Si’, Presso la fonte meco t’assidi.
Ohimè, sorge il tremendo fantasma e ne separa!
Qui ricovriamo, Edgardo, a piè dell’ara.
Sparsa è di rose!

Un’armonia celeste, di’, non ascolti?
Ah, l’inno suona di nozze!
Il rito per noi s’appresta! Oh, me felice!
Oh gioia che si sente, e non si dice!
Ardon gl’incensi!
Splendon le sacre faci, splendon intorno!
Ecco il ministro!
Porgimi la destra!
Oh lieto giorno!
Al fin son tua, al fin sei mio,
a me ti dona un Dio.
Ogni piacer più grato,
mi fia con te diviso
Del ciel clemente un riso
la vita a noi sarà.

English

The sweet sound of his voice struck me!
Ah, that voice has entered my heart!
Edgardo! I surrender to you, oh my Edgardo!
I have escaped from your enemies.
A chill creeps into my breast!
Every fibre trembles!
My foot falters!
Sit down by the fountain with me a while!
Alas, the tremendous phantom arises and separates us!
Let us take refuge here, Edgardo, at the foot of the altar.
It is scattered with roses!

A heavenly harmony, tell me, do you not hear it?
Ah, the marriage hymn is playing!
They are preparing the rite for us! Oh, how happy I am!
Oh joy that is felt but not said!
The incense is burning!
The holy torches are shining, shining around!
Here is the minister!
Give me your right hand!
Oh joyful day!
At last I am yours, at last you are mine,
A god gives you to me.
Let me share
The greatest pleasures with you,
Life for us will be
A smile from merciful heaven.


Invictus

Out of the night which covers me,
Black as the pit from pole to pole,
I thank whatever gods may be
For my unconquerable soul.

In the fell clutch of circumstance
I have not winced nor cried aloud.
Under the bludgeoning of chance
My head is bloody, but unbowed.

Beyond this place of wrath and tears
Looms but the Horror of the shade,
And yet the menace of the years
Finds, and shall find me, unafraid.

It matters not how strait the gate,
How charged with punishments the scroll,
I am the master of my fate:
I am the captain of my soul.


The Destruction of Sennacherib

The Assyrian came down like the wolf on the fold,
And his cohorts were gleaming in purple and gold;
And the sheen of their spears was like stars on the sea,
When the blue wave rolls nightly on deep Galilee.

Like the leaves of the forest when Summer is green,
That host with their banners at sunset were seen:
Like the leaves of the forest when Autumn hath blown,
That host on the morrow lay withered and strown.

For the Angel of Death spread his wings on the blast,
And breathed in the face of the foe as he passed;
And the eyes of the sleepers waxed deadly and chill,
And their hearts but once heaved, and for ever grew still!

And there lay the steed with his nostril all wide,
But through it there rolled not the breath of his pride;
And the foam of his gasping lay white on the turf,
And cold as the spray of the rock-beating surf.

And there lay the rider distorted and pale,
With the dew on his brow, and the rust on his mail:
And the tents were all silent, the banners alone,
The lances unlifted, the trumpet unblown.

And the widows of Ashur are loud in their wail,
And the idols are broke in the temple of Baal;
And the might of the Gentile, unsmote by the sword,
Hath melted like snow in the glance of the Lord.


O Fortuna

Original
O Fortuna
velut luna
statu variabilis,
semper crescis
aut decrescis;
vita detestabilis
nunc obdurat
et tunc curat
ludo mentis aciem,
egestatem,
potestatem
dissolvit ut glaciem.

Sors immanis
et inanis,
rota tu volubilis,
status malus,
vana salus
semper dissolubilis,
obumbrata
et velata
michi quoque niteris;
nunc per ludum
dorsum nudum
fero tui sceleris.

Sors salutis
et virtutis
michi nunc contraria,
est affectus
et defectus
semper in angaria.
Hac in hora
sine mora
corde pulsum tangite;
quod per sortem
sternit fortem,
mecum omnes plangite!

Translation
O Fortune,
like the moon
you are changeable,
ever waxing
and waning;
hateful life
first oppresses
and then soothes
as fancy takes it;
poverty
and power
it melts them like ice.

Fate – monstrous
and empty,
you whirling wheel,
you are malevolent,
well-being is vain
and always fades to nothing,
shadowed
and veiled
you plague me too;
now through the game
I bring my bare back
to your villainy.

Fate is against me
in health
and virtue,
driven on
and weighted down,
always enslaved.
So at this hour
without delay
pluck the vibrating strings;
since Fate
strikes down the strong man,
everyone weep with me!

email.heick.email

Yays!

Today i’ve done it. I’ve acquired my email dream!

I’m talking about a nearly-automated @heick.email

…to explain…

For years, if you ever wanted to send me an email I would say:

“Just put your name at the front of @unliterate.net, and i’ll get it.”

Ever since I setup my email @unliterate.net wrong as a catch-all SPAM domain, I’ve had to deal with the following rigmarole when getting new email setup:

  1. Get the name@unliterate.net figured out
  2. Setup a folder in Thunderbird, my email client
  3. Setup a mail filter rule in my email client to move the received message from my Inbox to that folder

Which things have been working for years, and it’s been a fairly straightforward approach.

Until I got married, and we decided to get the heick.email domain and have all our mail shared.

…how to share the email…

So, the @unliterate.net experiment utilized POP3 as the server for me to get all my catch-all. This was easy to configure, and was fairly straightforward.

We needed to be able to share email across computers and devices, though, and still have the flexibility to do the “folder structure”-thingy that I’ve grown comfortable with the @unliterate.net “mail filter” rules.

So, the only solution is to go from POP3 to IMAP.

IMAP gives us the flexibility of folders on the server, not on the client. It also stores all the mail there, and the protocol (after swallowing that it’s not like POP3) is actually quite orderly and simple.

So, i’ve employed dovecot as my IMAP server, which was also my POP3 server, and configured it simply to enable IMAP and know where I want my users mailboxes to be stored.

After setting up DNS for mail, i’ve got email coming into @heick.email, and I’m happy.

I just need to be able to now do the mail filtering…

How to automate folder-making for IMAP

This was a basic challenge, and I love challenges.

I had to use my programming language of choice (PHP) with the php-imap module loaded, and fancy up a script that runs on a */1 (1 minute) cron task.

The script is as follows:

<?php
/**
 * The whole purpose of this script is to perform the following:
 * 1) Open an IMAP connection to an INBOX
 * 2) Look through all the messages
 * 3) Grab all messages and look for the first "To: " header in each message
 * 4) If the person in the "To: " is in the allowed domain
 * - We grab the user
 * - We check to see if their is a mailbox for that user, and move the messge there
 * - We delete the message
 * 5) If the person is not in the allowed domain
 * - We move the message to a default folder
 */

function get_imap_folders($resource, $config)
{
 // Get a list of mailboxes
 $original_folders = imap_listmailbox($resource, "{" . $config['server'] . ":" . $config['port'] . "}", "*");
 // these come through as {server:port}mailbox, so we just clean them up a bit
 $new_folders = array();
 $to_remove = "{" . $config['server'] . ":" . $config['port'] . "}";
 $folders = str_replace($to_remove, "", $original_folders);
 return $folders;
}

$config = array(
 'server' => 'localhost',
 'port' => '143',
 'username' => 'redacted',
 'password' => 'redacted',
 'folder' => 'INBOX',
 'spam' => 'SPAM',
 'debug' => true,
);
$debug_message = "";

$res = imap_open("{" . $config['server'] . ":" . $config['port'] . "/service=imap/novalidate-cert" . "}" . $config['folder'], $config['username'], $config['password']);
if (!$res)
{
 if ($config['debug'])
 {
 $debug_message = "IMAP Stream Failure";
 }
 die($debug_message);
}

$folders = get_imap_folders($res, $config);

// Lets get all the mail messages in the $config['folder']
$mbox = imap_check($res);
$number_messages = $mbox->Nmsgs;
if ($number_messages == 0)
{
 if ($config['debug'])
 {
 $debug_message = "No Messages";
 }
 die($debug_message);
}
$range = "1:" . $number_messages;

// now, we'll get the messages
$messages = imap_fetch_overview($res, $range);
foreach ($messages as $msg)
{
 $msgno = $msg->msgno;
 $to = $msg->to;

echo "Message: " . $msg->subject . "\n";
 if (strpos($to, "@"))
 {
 $array_to = explode("@", $to);
 $to = $array_to[0];
 }

// do we need to create a folder to move this message into?
 $destination_mbox = "{" . $config['server'] . ":" . $config['port'] . "}" . $to;
 if (!in_array($to, $folders))
 {
 if (imap_createmailbox($res, $destination_mbox))
 {
 echo "> Created folder [$to]\n";
 }
 else
 {
 echo "> Failed to create folder [$to]\n";
 }

}
 $folders = get_imap_folders($res, $config);
 if (imap_mail_move($res, $msgno, $to))
 {
 echo "+ Moved successfully\n";
 }
 else
 {
 echo "- Failed to move message\n";
 }
}
imap_expunge($res);
imap_close($res);
?>

To explain, basically this access my IMAP server, gets all the folders, then gets all the mail. It goes though the “to:” portions of the email addresses and sees if I have a folder that matches what’s in the name part of the email address in the “to:” portion. If it doesn’t exist, it makes the folder. Then, as a final result, it moves the mail to that folder and aborts.

So, this script now runs every minute, checking for new mail, creating the folders necessary and moving the messages.

vivre heick.email!

New Years Resolutions!

Another year, 2015, has gone by!

I have therefore created my LONG, LONG list of new years resolutions:

  1. Get a bit of a daily workout. Specifically, moving arms and legs.
  2. Oral Hygiene needs improvement from once a day to twice a day.
  3. Learn to sing “In Tune”.
  4. Clearing my credit report.
  5. Digitally Archive my memories, pictures, documents, etc, so I can feel comfortable in forgetting.
  6. Try to take over the world.

 

And much like last year, I’m hoping to accomplish most if not all this list.

Eventfully progressive Saturday

Today was…

well..

a very nice Saturday.

It seems that once you start doing one thing you end up doing other things that are somewhat “related”, so you accomplish an amazing amount from the start of one little thing.

It started off with E-Mail. After using Windows Live Mail 2011 for so many years, I had finally got sick of it’s inability to help me actually SORT emails into many, many folders. It took me a matter of 45 minutes to extract, re-import, and re-sort out all my mail into Thunderbird, and then completely obliterate Windows Life Mail. I’m fucking happy beyond belief now.

After this, and during peeks at the selected “Pirates of the Caribbean” Marathon I was actually able to properly configure wordpress so I don’t have to download updates and new shit (since I was a retard at the start in setting it up). After aliasing things and getting permissions setup, I’m happily updated as well.

Finally, I’m overly excited at today being my last day of the Stage 1 Nicotine Patch (21mg, 6 weeks). Tomorrow I can start the Stage 2 for 2 weeks, and follow that with the Stage 3 for 2 weeks. I do have yet to still purchase the Stage 2 patch as I’ve already accidentally purchased the Stage 3 on the third week of the Stage 1. Regardless, my wall is getting full and only has 4 more rows remaining after today.

 100_1474[1]