Archive for November, 2006

How To View Processes Using Most Threads Under Linux

Thursday, November 30th, 2006

You can run this command under Linux (tested with RHEL 3.0) to see the processes with the most threads…

find /proc/*/status -exec gawk '/^Name:/ { n=$2}; /^Threads:/ { t=$2}; END{ printf("%-30s %5d\n", n, t);}' {} \; | sort --key=2 -g -r | head -10

This is especially useful on systems (like VPS hosting accounts) where you might have limits on the total number of threads.

Addendum (12/1/2006 1:48p CST):

Based on feedback, here are a few other tips related to this…

  • You can modify the script slightly to also show the process id using this modified version…

    find /proc/*/status -exec gawk '/^Pid:/ { p=$2}; /^Name:/ { n=$2}; /^Threads:/ { t=$2}; END{ printf("%6d %-30s %5d\n", p, n, t);}' {} \; | sort -k3 -g -r | head -10

  • You can create a topthreads alias to this long command allowing to you execute it just by typing topthreads by first executing…

    alias topthreads="find /proc/*/status -exec gawk '/^Pid:/ { p=\$2}; /^Name:/ { n=\$2}; /^Threads:/ { t=\$2}; END{ printf(\"%6d %-30s %5d\n\", p, n, t);}' {} \; | sort -k3 -g -r | head -10"
     

Manipulate a HashMap With Only JSTL Tags in JSP

Tuesday, November 28th, 2006

There is no need to write Java or custom tags when all you need to do is store and retrieve data with a simple HashMap.  The trick is to instantiate the HashMap using a <jsp:useBean> tag and then populate it using a <c:set target=..> tag.  You can instantiate and store data in a HashMap with JSTL tags like this (paste the code into your own test.jsp page and give it a try):

——– CUT HERE ——–
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<jsp:useBean id="exampleMap" class="java.util.HashMap"/>
<c:set target="${exampleMap}" property="KS" value="Kansas"/>
<c:set target="${exampleMap}" property="TX" value="Texas"/>
<c:set target="${exampleMap}" property="OK" value="Oklahoma"/>

<c:set var="state" value="TX"/>

<html>
<body>
    Method 1: ${exampleMap.TX}<br>
    Method 2: ${exampleMap['TX']}<br>
    Method 3: ${exampleMap[state]}<br>
</body>
</html>
——– CUT HERE ——–

The target attribute of the <c:set> tag indicates which HashMap you are manipulating.  The property attribute is the HashMap key. The value attribute is the element to be placed in the HashMap that is associated with the key. 

Running the above JSP page will result in the following output:

Method 1: Texas
Method 2: Texas
Method 3: Texas

Of course you can also populate the HashMap with values from a database by just including the <c:set target=… > tag within a <c:forEach .. > block.

Auto-Restart Your Web Server on Failure Under Linux

Monday, November 27th, 2006

Ever have your busy web server go down when you are unavailable to restart it? If so, you can implement a simple script that will restart your web server automatically if there has been no activity in your access log for a period of time…

  1. Wherever you wish, create an autorestart.sh that looks like this…
    #!/bin/sh

    # Modify the following line to stop your web server
    # /opt/webserver/bin/start.sh stop

    # Wait 3 seconds before restarting
    sleep 3

    # Modify the following line to start your web server
    # /opt/webserver/bin/start.sh start

    # Modify the following line to use your email address
    mail -s “Auto-Restarted Your Web Server” bob@whatever.com < /dev/null

  2. Change the permission on autorestart.sh to allow it to execute…chmod +x autorestart.sh
  3. Add the following to the “start” part of your existing start/stop script for your web server…
    echo "*/5 * * * * root find /opt/webserver/log/access_log -type f -cmin +10 -exec /opt/webserver/bin/autorestart.sh {} \;
    " > /etc/cron.d/autorestart.cron

    You should modify this command as follows…

    • Replace the “5″ in */5 with how often to check the access log (in minutes)
    • Replace /opt/webserver/log/access_log with the location of the current access log
    • Replace the “10″ in +10 with the number of minutes to wait for no entries in your access log before restarting
    • Replace /opt/webserver/bin/autorestart.sh to point to your autorestart.sh
  4. Add this line to the “stop” part of your existing start/stop script for your web server…rm -f /etc/cron.d/autorestart.cron

A few notes…

  • Initially, leave the start/stop lines commented out in autorestart.sh for testing. Uncomments the start/stop lines in autorestart.sh if you receive email notifications only at times when your web server should have been restarted.
  • The above technique depends on a detecting a lack of activity in your web server’s access log. If you have access logging turned off in your web server then the above technique will not work. If you have relatively few visitors to your website the above technique may not work well.
  • The above technique is generic enough to work with almost any web server (Apache, Tomcat, Resin, etc.).

Ideally, this would never be necessary; however, you may have a third-party module loaded in your web server that causes a memory leak, you may run this under a VPS hosting account that runs out of memory occassionally, etc.

Add a Little Color to Your SSH/Telnet Sessions

Wednesday, November 22nd, 2006

As a user or administrator of multiple Linux systems, it is important that you pay very close attention as to what box you are about to issue a command on.  One powerful way to do that is to use a distinct font and/or background color for each server.  This example assumes that you are using the default bash shell on a Red Hat Linux system.

1) Edit the /etc/bashrc using your favorite editor.

2) Search for the string, PROMPT until you reach a statement that looks like:

PROMPT_COMMAND=’echo -ne "\033]0;${USER}@${HOSTNAME%%.*}:${PWD/#$HOME/~}\007"’

3) Insert the string \e[34;1m at the location shown below:

PROMPT_COMMAND='echo -ne "\e[34;1m\033]0;${USER}@${HOSTNAME%%.*}:${PWD/#$HOME/~}\007"’

4) Save the file.

5) Run the command source /etc/bashrc.

By changing the value after the \e[ you can change the font color.  Here is a color list for the font (foreground):

31 = Red
32 = Green
33 = Yellow
34 = Blue
35 = Purple
36 = Aqua
37 = White

The value in the ;1m portion of the string makes the prompt bright.  Alternatively, you can change the value in that portion of the string to change the background color.  Here is a list of background colors:

40 = Black
41 = Red
42 = Green
43 = Yellow
44 = Blue
45 = Purple
46 = Aqua
47 = White

If you do want a colored background, one good color choice might be a yellow font on a blue background: \e[33;44m

If you are using a system other than Red Hat and don’t have an /etc/bashrc file, a good technique for knowing where to insert the prompt is to change to the /etc directory and issue the command grep PROMPT * – that will give you a clue as to where the system’s default prompt is being set.

You can also override just single user’s prompt by editing ~/.bashrc and inserting a similar PROMPT_COMMAND= statement into that file.

Generate Simple Bar Charts From a MySQL Prompt

Monday, November 20th, 2006

We all use SELECT statements to retreive and analyze data in the database. You can improve your ability to quickly analyze data by formatting values into simple bar charts within your SELECT results. Here is an example…

Let’s say you have this data…

mysql> SELECT Name, Value FROM Month;
+-----------+---------+
| Name | Value |
+-----------+---------+
| January | 379.385 |
| February | 906.076 |
| March | 392.224 |
| April | 242.893 |
| May | 37.7936 |
| June | 460.288 |
| July | 188.06 |
| August | 559.437 |
| September | 233.005 |
| October | 486.714 |
| November | 734.555 |
| December | 212.632 |
+-----------+---------+
12 rows in set (0.00 sec)

You can generate a simple bar chart of the values by executing this command…

mysql> select Name, REPEAT("#", Value/20.0+1) Graph FROM Month;
+-----------+------------------------------------------------+
| Name | Graph |
+-----------+------------------------------------------------+
| January | #################### |
| February | ############################################## |
| March | ##################### |
| April | ############# |
| May | ### |
| June | ######################## |
| July | ########## |
| August | ############################# |
| September | ############# |
| October | ######################### |
| November | ###################################### |
| December | ############ |
+-----------+------------------------------------------------+
12 rows in set (0.00 sec)

Within the REPEAT() function, you’ll want to adjust the the constant value appropriately for the scale of your data. While this uses an ultra simple technique to repeat the # character to create the bar charts, this is still an incredibly useful means to improve your ability to quickly analyze the data.

Export Your MySQL Data to XML With a Single Command

Friday, November 17th, 2006

With a single mysqldump command, you can export a subset of your MySQL database to an XML file.  This can save you considerable time in writing a script or application to selectively write out the appropriate data to XML.  Here is how you do this…

Let’s say you have this data…

mysql> select * from Month;
+---------+-----------+
| MonthID | Name      |
+---------+-----------+
|       1 | January   |
|       2 | February  |
|       3 | March     |
|       4 | April     |
|       5 | May       |
|       6 | June      |
|       7 | July      |
|       8 | August    |
|       9 | September |
|      10 | October   |
|      11 | November  |
|      12 | December  |
+---------+-----------+
12 rows in set (0.00 sec)

Now, let’s say you only want to export the months ending in "ber" to XML.  You can execute the following command to do this…

mysqldump -q -X -t -w "Name like '%ber'" mydatabase Month

In this command, the -q turns off buffering of the results (appropriate for large tables), the -X specifies XML output, the -t specifies to turn off writing table meta data, the -w specifies a WHERE clause to run (omit this switch to export all data), the mydatabase is the name of the database, and Month is the name of the table to export.

This results in the following…

<?xml version="1.0"?>
<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<database name="realmetrics">
        <table_data name="Month">
        <row>
                <field name="MonthID">9</field>
                <field name="Name">September</field>
        </row>
        <row>
                <field name="MonthID">10</field>
                <field name="Name">October</field>
        </row>
        <row>
                <field name="MonthID">11</field>
                <field name="Name">November</field>
        </row>
        <row>
                <field name="MonthID">12</field>
                <field name="Name">December</field>
        </row>
        </table_data>
</database>
</mysqldump>

Now, let’s say you want to exclude the "MonthID" field from the results, you could do this by executing the following under Linux…

mysqldump -q -X -t -w "Name like '%ber'" mydatabase Month | fgrep -v "name=\"MonthID\""

This command results in…

<?xml version="1.0"?>
<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<database name="realmetrics">
        <table_data name="Month">
        <row>
                <field name="Name">September</field>
        </row>
        <row>
                <field name="Name">October</field>
        </row>
        <row>
                <field name="Name">November</field>
        </row>
        <row>
                <field name="Name">December</field>
        </row>
        </table_data>
</database>
</mysqldump>

This example is simple but you might use this technique to export all of a customer’s data to XML if requested.

Hey, That Windows Key Is Useful

Friday, November 17th, 2006

Here are a few useful things you can do with your Windows key under Windows XP…

  • Windows Key + E — Launch Explorer
  • Windows Key + F — Launch Search for Files
  • Windows Key + L — Log off Windows
  • Windows Key + M — Minimize all windows
  • Windows Key + Shift + M — Undo minimize all windows
  • Windows Key + R — Launch the Run dialog box
  • Windows Key + Tab — Cycle through the application in the Task Bar

And I always thought that the Windows key was worthless. :)

Avoid the Dreaded “Repair by Key Cache” in MySQL

Thursday, November 16th, 2006

Recently, we ran a simple ALTER statement on a very large table that would normally run in about 2 hours but instead took 2 days to complete the alter (yes, 48 hours).  Here is how we fixed this problem so ALTERs would again run relatively quickly on our large tables.

Using "show processlist", we could see the ALTER had a status of "Repair by Key Cache" instead of the normal "Repair by Sorting".  After some research, we realized our indexes on this table had grown beyond the size that MySQL could use Repair by Sorting with our current configuration.

We did two things to fix this so that future ALTERs would be able to use the much faster "Repair by Sorting" instead of the dreaded "Repair by Key Cache"…

  1. We increased the size of the myisam_max_sort_file_size parameter in MySQL.  This parameter should be larger than the maximum size of any key on the table multiplied by the number of rows in the table.
  2. We changed the tmpdir parameter in MySQL from /tmp to /opt/tmp.  The size of our /tmp partition was also not large enough to handle repairing some of our large tables.

If you manage large MySQL database implementations, probably worth a bit of homework before you run your next alters to make sure that you have the myisam_max_sort_file_size parameter sized properly and you have enough space at the tmpdir parameter location to handle a "Repair by Sorting" versus "Repair by Key Cache".

How To Create a Custom Function in MySQL

Wednesday, November 15th, 2006

With MySQL 5.x, you can create custom functions that can be invoked from other SQL statements.  Here is an example of creating a custom function called OverlapSeconds() that calculates how many seconds of overlap there are between any two time periods…

DELIMITER | ;
CREATE FUNCTION OverlapSeconds(period1Beg DATETIME, period1End DATETIME, period2Beg DATETIME, period2End DATETIME)
RETURNS INT LANGUAGE SQL DETERMINISTIC
BEGIN
    DECLARE time1Beg,time1End,time2Beg,time2End,result INT;
    SET time1Beg = UNIX_TIMESTAMP(period1Beg);
    SET time1End = UNIX_TIMESTAMP(period1End);
    SET time2Beg = UNIX_TIMESTAMP(period2Beg);
    SET time2End = UNIX_TIMESTAMP(period2End);
    IF time2End<=time1Beg THEN
        SET result = 0;
    ELSEIF time2Beg>=time1End THEN
        SET result = 0;
    ELSEIF time2Beg>=time1Beg AND time2End<=time1End THEN
        SET result = time2End-time2Beg;
    ELSEIF time1Beg>=time2Beg AND time1End<=time2End THEN
        SET result = time1End-time1Beg;
    ELSEIF time2Beg<=time1Beg AND time2End>=time1Beg THEN
        SET result = time2End-time1Beg;
    ELSEIF time2Beg<=time1End AND time2End>=time1End THEN
        SET result = time1End-time2Beg;
    END IF;
    RETURN result;
END|

DELIMITER ; |

You can then invoke this function like this…

mysql> SELECT OverlapSeconds(’2006-10-01 10:00′, ‘2006-10-01 10:10′, ‘2006-10-01 10:08′, ‘2006-10-01 10:18′) Overlap;
+———+
| Overlap |
+———+
|     120 |
+———+
1 row in set (0.00 sec)

So, the period from 2006-10-01 10:00 to 2006-10-01 10:10 overlaps with the period 2006-10-01 10:08 to 2006-10-01 10:18 by 120 seconds.

Useful Commands to Analyze Network Connections Under Linux

Wednesday, November 15th, 2006

On a high traffic Linux server, it is often useful to analyze the connections to understand traffic patterns and to check for unusual activity.  Here are a few commands I find useful to summarize the current connections on a Linux server…

Summarize the number of active connections per IP

netstat -nta | fgrep "ESTABLISHED" | cut -b 49-75 | cut -d ‘:’ -f1 | sort | uniq -c | sort -n -r –key=1,7 | head -25

Summarize the number of SYN_RECV connections per IP

netstat
-nta | fgrep
"SYN_RECV" | cut -b 49-75 | cut -d ‘:’ -f1 | sort | uniq -c | sort -n
-r –key=1,7 | head -25

Summarize the number of connections per connection state

netstat -nta | fgrep ":" | cut -b 77-90 | sort | uniq -c

Any IP with unusually high numbers in the first two checks might be cause for concern — that really depends on your system though and how users interact with your server normally.