why unix | RBL service | netrs | please | ripcalc | linescroll
hosted services

hosted services

JSP is the land between C and perl. JSP for those who are not aware, is Java Server Pages. Java is a statically typed language, unlike dynamically typed languages the execution speed is relatively fast.

Many people forget that dynamic languages have a high overhead for type checking, so it is worth investing some time in a statically typed language. Take a look at the benchmarks game. Just think, if you're putting a website up that has performance flaws, you're allowing your server(s) to be the subject of a DDoS through potential flash crowds.

If you have unlimited budget for servers then I suppose that it's not an issue for you.

Java has several scalability benefits that dynamic languages could suffer from. Initially it will appear that more work is required, but over time there are benefits once a project grows.

eclipse

In order to write java web code you're probably best off with eclipse. I'm happy to write java system process programs in vim (sort of things that do stuff behind the scenes). However, for web code, its often helpful to write code in the IDE.

Some of the later versions of eclipse like to use the GTK+ 3 libraries, and they just seem to be the computing equivalent of nails on a chalk board. To use the GTK+ 2 libraries execute like so:

$ PATH=/usr/local/jdk/bin:$PATH /usr/local/cache/eclipse/eclipse -vm /usr/local/jdk/bin/java --launcher.GTK_version 2

or however you execute eclipse.

error output

It is often useful to collect a stack trace as a string to print out later, this is accomplished as follows:

StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter( sw );
e.printStackTrace( pw );
String exceptionAsString = sw.toString();

This kind of mucking around gives Java a bad name, why exceptionAsString couldn't be a method of the Exception object is beyond me.

efficiencies

Unlike FCGI, you don't have an interpreter for each thread of execution that the webserver hands to the application. In my experimentations I found that with a dozen perl jobs running under FCGI there would be around 5MB * 12 of RAM consumed. After moving all the scripts to Java I found very much less total memory was consumed, and a slight performance increase, which was a benefit. I briefly touched on threads earlier on pthreads and a socket server.

Java, as a most strictly typed languages are, processes variables much quicker than dynamic languages, such as perl/python. From testing, java often performs close to c when doing things like numerical operations. It'll never match c, but it is close. It may match or surpass poorly implemented code, though.

locking

Often when you have a java process that handles many requests it helps to store some bits in memory, a little like memcache, but without any network over head. This can be useful for a dataset that you maintain in a database, but refresh in the application if required. These objects are best stored statically. So, lets look at an example and discuss:

import java.util.*;
import java.io.*;

public class LoadData {

    static int numbooks;

    private int updatebooks() {
        // do some sql and return the number of books on the system
        // something that could take a few seconds/minutes
        return( 65535 );
    }

    public LoadData() {
        if( LoadData.numbooks == null ) {
            LoadData.numbooks = updatebooks();
        }
    }
}

The point about the above code is that you could have some concurrency issues. If multiple users load the same class from visiting your page, then updatebooks could take time to complete, and you have a race condition on your hands.

You can stop several threads from entering the same area of code easily through making the method synchronized, like the below example.

import java.io.*;
import java.util.*;

public class Synchron implements Runnable {
        static int a;

        synchronized public void adder() {
        Synchron.a++;
        System.out.println( Synchron.a );
        }

        public void run() {
                while( Synchron.a < 65535 ) {
                        adder();
                }
        }
        public static void main( String []args ) {
                ArrayList <Thread>al = new ArrayList<Thread>();

                try {
                        int i;
                        for( i = 0; i<10 ; i++ ) {
                                Synchron s = new Synchron();
                                Thread t = new Thread( s );
                                al.add(t);
                                t.start();
                        }

                        for( Thread t : al ) {
                                t.join();
                        }
                }
                catch( Exception e ) {
                        e.printStackTrace();
                }

        }
}

So, on first run, with sorted/counted output we find this:

/usr/local/jdk/bin/java Synchron > file && sort file | uniq -c | sort -n | tail
   ...
      2 12816

What's going on here, why did the program output two lines the same despite the method being synchronized?

At first glance, one of the issues could be the way that the value of a is incremented. The CPU loads a from RAM and updates it. The update is not immediately coped back to RAM and stays in the cache. This isn't normally an issue for single-core, single-thread CPUs. However, on today's systems it is not that uncommon to find 32-threads, take Sun's T2000 for example, which is only a few hundred pounds from eBay at the moment.

What we can do is set a to volatile, lets run it again with the following change:

volatile static int a;

So, now we get the following output (could vary for you, of course):

      2 534

So, still not quite there are we. A little investigation and trying a different type of synchronized block which locks an object:

        public void adder() {
            synchronized( this ) {
                Synchron.a++;
                System.out.println( Synchron.a );
            }
        }

This time when we run it we get output as follows:

      2 3354

This I believe is down to locking the wrong object this, we need to lock something that the other threads have access to, despite this being a common way that I've seen it done, it isn't quite accurate enough.

        static Object o = new Object();

        public void adder() {
            synchronized( Synchron.o ) {
                Synchron.a++;
                System.out.println( Synchron.a );
            }
        }

This time when we run it, many times we have a stable solution. So, moral of the story, test what you read online, even this :).

high read transaction hashes

For a while I wanted a simple solution for Java that allowed for many fast lookups without concurrency issue. Something like a tie BDB in Perl. Nothing seems to exist sadly. There is JDBD2, though, but that doesn't survive concurrent requests, unfortunately.

Eventually I found sg-cdb. This is a port of CDB to Java, and it works really well.

Even if JDBD2 did handle concurrency, it is still far slower than the CDB method. However, CDB, being a constant database, doesn't handle amendments in any shape or form.

connection pools

After some rather hard work and much effort I figured out how to do effective connection pools with Tomcat. It is relatively easy, but does take a little setting up. Here's what I did.

Firstly, you'll need a META-INF/context.xml file, this defines your DB properties, db server location, number of connections, login, password, db driver, all that jazz. Here's what I have in mine:

<Context>
    <!-- maxActive: Maximum number of database connections in pool. Make sure you
         configure your mysqld max_connections large enough to handle
         all of your db connections. Set to -1 for no limit.
         -->

    <!-- maxIdle: Maximum number of idle database connections to retain in pool.
         Set to -1 for no limit.  See also the DBCP documentation on this
         and the minEvictableIdleTimeMillis configuration parameter.
         -->

    <!-- maxWait: Maximum time to wait for a database connection to become available
         in ms, in this example 10 seconds. An Exception is thrown if
         this timeout is exceeded.  Set to -1 to wait indefinitely.
         -->

    <!-- username and password: MySQL username and password for database connections  -->

    <!-- driverClassName: Class name for the old mm.mysql JDBC driver is
         org.gjt.mm.mysql.Driver - we recommend using Connector/J though.
         Class name for the official MySQL Connector/J driver is com.mysql.jdbc.Driver.
         -->

    <!-- url: The JDBC connection url for connecting to your MySQL database.
         -->

  <Resource name="jdbc/Data" auth="Container" type="javax.sql.DataSource"
               maxActive="50" maxIdle="20" maxWait="10000"
           username="muppet" password="correcthorsebatterystaple" 
           driverClassName="com.mysql.jdbc.Driver"
           url="jdbc:mysql://localhost:3306/Data"
               factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
                />
</Context>

You'll also need to set this as a resource in WEB-INF/web.xml:

  <resource-ref>
      <description>DB Connection</description>
      <res-ref-name>jdbc/Data</res-ref-name>
      <res-type>javax.sql.DataSource</res-type>
      <res-auth>Container</res-auth>
  </resource-ref>

Once you've done that, you're all set to start using it in your code.

Be careful though. Connections will be persistent, if your code allocates a connection, and does it's work, and finishes without returning the connection to the pool, well, you guessed it, the pool will get cluttered and exhausted. It is critical that you reap your connections prior to descending the stack.

DBConnectionPool.java

public class DBConnectionPool {
    public DBConnectionPool() {
    }

    public Connection getConnection() {
        try {
            Context initContext = new InitialContext();
            Context envContext  = (Context)initContext.lookup("java:/comp/env");
            DataSource datasource = (DataSource)envContext.lookup("jdbc/DNSData");
            Connection conn = datasource.getConnection();                          
            return( conn );
        }
        catch( Exception ex ) {
            System.err.println( CommonFunctions.exception_as_string( ex ) );
        }
        return( null );
    }
}

When used, it is done so like (DBConnectionPool is normally a class member):

    DBConnectionPool dbcp = new DBConnectionPool();
    ...
    PreparedStatement ps = null;
    ResultSet rs = null;
    Connection conn = null;
    try {
        conn = dbcp.getConnection();
        ps = conn.prepareStatement( sql );
        ...
        rs = ps.executeQuery();
    }
    CommonFunctions.close_rs_ps_conn( rs, ps, conn );

close_rs_ps_conn is defined as:

    public static void close_rs_ps_conn( ResultSet rs, PreparedStatement ps, Connection conn ) {
        try {
            if( rs != null ) {
                rs.close();
            }
        }
        catch( Exception ex ) {
        }

        try {
            if( ps != null ) {
                ps.close();
            }
        }
        catch( Exception ex ) {
        }

        try {
            if( conn != null ) {
                conn.close();
            }
        }
        catch( Exception ex ) {
        }
    }

backends

There are two main ways to communicate between Apache and Tomcat. There is the jakarta module (jakarta-servlet) and proxy_ajp (ProxyPass ajp://127.0.0.1:8009/...).

Using Apache HTTPd's proxy balancer is the new and preferred way. It is simple and does not require non-standard Apache configuration methods, by that I mean it keeps in with normal proxy balancer configuration that System Admins will be familiar with.

<Location /JSPContent>
    ProxyPass               balancer://jspbalancer/JSPContent
    ProxyPassReverse        balancer://jspbalancer/JSPContent
</Location>

<Proxy balancer://jspbalancer>
        BalancerMember ajp://127.0.0.1:8009 loadfactor=1
    BalancerMember ajp://127.0.0.2:8009 loadfactor=1
    BalancerMember ajp://127.0.0.3:8009 loadfactor=1
    BalancerMember ajp://127.0.0.4:8009 loadfactor=1
</Proxy>

So, if you wish to reload all your Tomcat servers it is trivial to drop one of your members from load simply by commenting it out, reloading your config and waiting for the content to trickle away. Then restart. Seamless.