Thursday, September 09, 2010

My AJP connector is sick!!!

Today, I had a problem between my Apache balancer and my Tomcat cluster. A virtual machine that was hosting two Tomcats was frozen. Something was wrong in my config and the Apache didn't show these Tomcats in error in the jk_status web interface. After a few minutes, I realized that the uriworkermap file was not configure on 'balancer' but directly on 'tomcat1' (one of the two Tomcats that were down).

So, I concluded that the Apache jk doesn't do any test on a worker if it isn't mapped with an uri.

But let'go back to my virtual machine that was frozen. It was not completely dead and a telnet 8010 was responding. Thus, my first conclusion was that I had a problem with my Apache. BAD WAY!!! The telnet was not efficient. I demonstrated that with a tiny perl script found on the net made to simulate an ajp ping.

You can use the script as this : time ./ajp_ping.pl server:8009

Many thanks to the author of this script. I don't have the link to his post anymore.

Here is the script content :

#!/usr/bin/perl -w

use warnings;
use strict;

use Socket;

my ($remote, $port) = split /:/, shift @ARGV, 2;

if (! $remote) {
$remote = 'localhost';
}
print "remote = $remote\n";

if (! $port) {
$port = 8009;
}
print "port = $port\n";

my ($iaddr, $paddr, $proto);

# If the port has anything other than numbers, we're assuming it is an
# /etc/services name.
if ($port =~ /\D/) {
$port = getservbyname $port, 'tcp' ;
}

die "Bad port, stopped" unless $port;
print "port = $port\n";

$iaddr = inet_aton($remote) || die "No host: $remote, stopped";
print "iaddr = $iaddr\n";

$paddr = sockaddr_in($port, $iaddr) || die "sockaddr: $!, stopped";
print "paddr = $paddr\n";

# Grab the number for TCP out of /etc/protocols.
$proto = getprotobyname 'tcp' ;
print "proto = $proto\n";

my $sock;
# PF_INET and SOCK_STREAM are constants imported by the Socket module. They
# are the same as what is defined in sys/socket.h.
socket $sock, PF_INET, SOCK_STREAM, $proto || die "socket: $!, stopped";
print "sock = $sock\n";

print "BEFORE CONNECT\n";
connect $sock, $paddr || die "connect: $!, stopped";
print "AFTER CONNECT\n";

# This is the ping packet. For detailed documentation, see
# http://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html
# I stole the exact byte sequence from
# http://sourceforge.net/project/shownotes.php?group_id=128058&release_id=438456
# instead of fully understanding the packet structure.
my $ping = pack 'C5' # Format template.
, 0x12, 0x34 # Magic number for server->container packets.
, 0x00, 0x01 # 2 byte int length of payload.
, 0x0A # Type of packet. 10 = CPing.
;

my @ping_values = unpack 'C5', $ping;
print "ping_values = " , join ' ', @ping_values , "\n";

# This is the expected pong packet. That is, this is what Tomcat sends back
# to indicate that it is operating OK.
my $expected = pack 'C5' # Format template.
, 0x41, 0x42 # Magic number for container->server packets.
, 0x00, 0x01 # 2 byte int length of payload.
, 0x09 # Type of packet. 9 = CPong reply.
;

syswrite $sock, $ping || die "syswrite: $!, stopped";

my $pong;
$pong = 'empty';
print "BEFORE READ\n";
sysread $sock, $pong, 5 || die "read: $!, stopped";
print "AFTER READ\n";

my @pong_values = unpack 'C5', $pong;
print "pong_values = " , join ' ', @pong_values , "\n";

close $sock || die "close: $!, stopped";

exit 0;


1 comment:

Rahul said...

Thanks for the great information in your blog Selenium Training in Chennai

Download Oracle JDK from command line

Found on the web. You can adapt the url with one grabbed from Oracle JDK download page. What I love here is the fact is send Oracle licence ...