Thursday, April 10, 2014

Build better software, and the world will still beat a path to your door!

Yesterday I was pleasantly surprised to read an article on the WSJ, that Atlassian was recently valued at $3.3B, and has sold $150M worth of its equity in a secondary sale mostly for the benefit of some of its long time employees.

I first got to know about Atlassian after using the JIRA issue tracker - which they had kindly made available to the Apache Software Foundation projects. It was a great product to use, and every developer I knew who had used it, simply loved it and would promote it without any hesitation wherever they went.

After leaving full time employment in late 2008, I bought my first couple of licenses for JIRA to help support some of the customers I was helping as a freelance consultant. Another great thing about Atlassian is that they help smaller companies at just $10 a piece for most of these really cool products under their Starter Program. Even the $10 goes to the Room to Read charity, and the startup licenses have already contributed more than $3M for charity!

After starting my own entrepreneurial career a few years back, I started to admire Atlassian even more. They actually bootsrapped that great company. I've read so many articles about them, and listened to the talk 'Art of the BootStrap' by the co-founders, where they share many great insights about the bootstrapping process and the rise of Atlassian. Like GitHub, they didn't go looking for funding, but instead focussed on building great products that would sell themselves - due to great experiences the users had, and the resulting feedback and word of mouth referrals. When GitHub bootstrapped, they Optimized for Happiness, since they were happy to build things of value, than about writing business plans with make believe numbers. This also allowed them to throw away things like financial projections, hard deadlines, ineffective executives that make investors feel safe, and everything that hindered employees from building amazing products.

Something even more interesting to know about Atlassian is that they do not  employ any sales folks - and with the money they save, the company invests heavily on research and development. Farquhar states that "Fifteen years ago, as long as you had the best distribution you would win". "It didn’t matter whether Oracle was worse than SAP. These days, people are making decisions based on how good the products are" - which is really true. This is the same sentiment I read on the ReadWrite.com article "The Reasons Businesses Use Open Source Are Changing Faster Than You Realize"

Large enterprises now realize that good Open Source products have great quality behind them, although they may cost significantly less than competition. And the ability to have the source code, and modify it really means that the user can extend a product even if the vendor developing or supporting it does not want to do that for you. I'd leave you to read through the slides from "2014 - The future of Open Source", and possibly the web cast of the panel discussion with Michael Skok  et al. Today 8 out of 10 choose Open Source for Quality.

Atlassian too allows any of its licensed users to download the source code - if they are interested in it. Although I've never had to do that, I feel privileged to have this option available to me - if I ever needed it. I'm sure many of you would have used quite expensive commercial software from very large companies that we all know of. Although these companies spent possibly millions of dollars, that does not make their software bug free. Many years back, I was at a client to install a leading RDBMS from an unopened box that contained the software the client purchased. However, to my surprise I found that to install that database version in that unopened box, I first had to get a service pack applied :) I seriously think that having access to the source code - even for closed proprietary software, is a great thing, since many end-users can innovate faster than some of the large companies can enhance their own products. Open source projects attract features and great ideas from many enterprise architects who use them, and these ideas turn up to be great features to sell to future customers - who are seriously happy to see such features - as they too values them very much.

Last year, a recent Fortune #1 company with ~$450 Billion in revenue selected the UltraESB, when many commercial ESBs, as well as open source alternatives existed on the market, which they could easily afford. This was after extensive analysis of our technical strengths, product stability and code quality all turned up with great results. Like Atlassian, we do not have a sales team either, but only a really strong engineering and support team and a great product that simply finds itself around, including to the top of the Fortune list of companies. We never approached any of our current customers; instead, they all found us. It was like what Emerson said, "Build a better mousetrap, and the world will beat a path to your door"

Earlier this year, we had a similar POC where we were shortlisted against a competitor with well over a hundred million dollars in funding. Again, we were selected on the technical merits, and also since we had handled the customer relationship better than how the sales team of our competitor could. When a potential customer talks to us, he talks directly to those who had written the code, installed it at many enterprises around the world, and who helped many clients before with similar and real problems. Quite obviously, no sales team can beat that - especially when the customer understands technology.

We have exciting times ahead of us now, and a great list of customers already utilizing our software in production, in addition to the recent Fortune #1.

So later this year, we will be looking forward to talk to those who believe in us, our journey so far, and our potential to take on the world. Fortunately, we will have the freedom to make a wise and informed selection, as until now, we've certainly optimized for happiness and for passion!

Monday, April 7, 2014

UltraESB 2.2.0 GA Released!

We've just released the v2.2.0 of the UltraESB, and you can find the news release here.

This release stabilizes some of the deployment aspects introduced in the 2.0 and 2.1 releases, and allows the externalization of some of the aspects for easier management and control. The release also fixes some defects related to classloading from deployment units, and also introduces a few changes to the public API to make the ESB API more user friendly and intuitive.

The release also adds support for the FIX (Financial Information Exchange) transport utilizing the QuickFixJ open source FIX library, and supports JSONPath - similar to XPath for XML payloads. We have also begun to move common utility functions to UTerm, and as a first step, the UTerm now includes the ability to run the JavaBench (clone of Apache Bench) load testing client easily from the command line, with repeated testing capabilities.

You can download the latest release as usual from http://www.adroitlogic.org/download.html

Thursday, November 7, 2013

Nausea with Tomcat after biting too much?

About an year back I wrote a post "Does Tomcat bite more than it can chew" about how Tomcat accepts more TCP connections that it can handle, and resets them later on. I also wrote a follow-up post "How to stop biting, when you cant chew more.." and explained how the UltraESB does it using Apache HttpComponents NIO underneath. I raised the issue on the Tomcat mailing list too, but found that most of the folks over there did not like what I had to say, and refused to change Tomcat.

This week one of our clients was running a load test using the UltraESB in front of a Tomcat instance, and wanted to measure the performance of the UltraESB to use WS-Security signatures over a Tomcat service. However, at 1000 concurrent users, the UltraESB started to report an XML parse exception with a "Premature end of file" for the responses.

After detailed investigations to reproduce the issue in our environment, we found the culprit to be Tomcat. However, proof of the issue was not that simple, and we used a standalone Java client to issue fixed sized asynchronous HTTP post requests to Tomcat, and measured the size of the responses received. The message size used was 5120 bytes, and thus a response of equal size was expected.

However, under load, Tomcat accepted a 5K request, but replied with an HTTP status code of 200, but without any payload. It sent the Content-Length header value as "0". Here is what Wireshark reported:

Here are the response headers that Tomcat sent back:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Length: 0
Date: Thu, 07 Nov 2013 10:15:14 GMT
Connection: close
It's also interesting to note that Tomcat sometimes returns error responses which states that an internal error occurred; but with a HTTP status code of 200, instead of the expected 500 error code. Here is an example of such a payload returned:
<html><head><title>Apache Tomcat/7.0.28 - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 500 - </h1><HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b> <u></u></p><p><b>description</b> <u>The server encountered an internal error () that prevented it from fulfilling this request.</u></p><HR size="1" noshade="noshade"><h3>Apache Tomcat/7.0.28</h3></body></html>
It would have been so much better for many, if Tomcat did not bite fast, when it cannot chew!

Monday, October 14, 2013

ESB Performance Testing - Round 7 Published!

We have just published the results for the long awaited Round 7 - of ESB performance benchmarking. This round compares 4 of the leading free and open source ESBs, Mule CE 3.4.0, Talend ESB SE 5.3.1, WSO2 ESB 4.7.0 and the UltraESB 2.0.0
Although at first glance the above image may indicate that the WSO2 ESB and the UltraESB have very similar performance characteristics, the Devil is indeed in the detail.

During the testing we discovered several issues with the previously published article Round 6.5 from WSO2, including a severe response corruption for messages over 16,384 bytes when the default pass-through transport is being used. However, what's most surprising is that this issue remains in versions 4.6.0 and 4.7.0 of the WSO2 ESB, as well as the latest Milestone 4 of the soon to be released version 4.8.0.

Sadly, the WSO2 engineers conducting the Round 6.5 also failed to notice a complete failure of all of the XSLT test cases, but nevertheless published numbers obtained for the failed test cases as high performance numbers over the other ESBs.

Read about these and other flaws of the Round 6.5 in the article Why the Round 6.5 results published by WSO2 is flawed

Tuesday, August 27, 2013

UltraESB 2.0.0 is released!

Yeah, its been quite sometime since we did a major release of the UltraESB! Although the last GA release was extremely stable and widely used, we've made significant improvements for the long awaited 2.0.0 release.

Since the beginning, we have been privileged to work closely with some of the best architects actually using our software in production. The suggestions and improvements proposed by them helped us implement key features that set the UltraESB apart. These were real requirements that meant a lot for large scale production deployments running 24 x 7 x 365 with zero downtime. For the 2.0.0 release, we've implemented many features that have been similarly inspired by the requirements of a top Fortune #10 company. These include a built-in metrics management and alerting functionality, and a programmatic instance management capability - coupled with annotation driven extensibility, especially for custom message interception at various stages.

Ruwan has already blogged about some of the metrics graphs generated by the UConsole in the 2.0.0 release, and you could find more documentation at http://docs.adroitlogic.org The 2.0.0 release also migrates to Apache HttpComponents/Core 4.2.4 and Spring framework / Spring security 3.1.1 and introduces a concept of a 'Deployment Unit' that can be deployed/updated or removed at runtime. Deployment units now has the ability to re-load dependency JAR files into the runtime as well, and support atomic updates as before, which allows all changes to be deployed into ESB nodes servicing client requests - without causing inconsistencies.

The Mediation API has also been cleaned up and streamlined with the introduction of 'Support Interfaces'. While being backwards compatible, the changes will help users utilize the UltraESB mediation API more easily.

Check out the full news release here, and refer to the documentation to get started!

Saturday, February 23, 2013

What drives talent out?


A few days back I saw the famous presentation from Netflix about its culture, and three interesting slides from it was about what drives talent out of a company.


Today I came across a poster created by හිච්චි කොලුවා which shows another aspect from a more Sri Lankan point of view, and it says its the 'තිත්ත ඇත්ත' .. interesting points to think about!



PS: If you aim the moon, believe that you WILL get there. If a planes' limit is the clouds.. get onto a rocket.. do not deviate from achieving your goal!

Monday, November 5, 2012

How to stop biting, when you cant chew more..

This is a follow up to my earlier post 'Does Tomcat bite more than it can chew?' and illustrates a pure Java program that utilizes Java NIO to stop accepting new messages when one is not able to handle the load, without any dependence on the TCP backlog etc.

Program Implementation

We open a selector, and invoke the startListening() method, that opens a ServerSocketChannel and then binds it to port 8280. The channel is configured as non-blocking, and finally we register our interest in OP_ACCEPT to handle incoming connections.

    private void startListening() throws IOException {
        server = ServerSocketChannel.open();
        server.socket().bind(new InetSocketAddress(8280), 0);
        server.configureBlocking(false);
        server.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("\nI am ready to listen for new messages now..");
    }


If you telnet to the port via a command line after the server starts up, you would see a message "Hi there! type a word". The server accepts the incoming connection as a non-blocking connection, and registers OP_READ to read the content typed in.


To illustrate how the server can prevent another client from connecting to it while it serves the currently connected client, it prints "I accepted this one.. but not any more now" on its console, cancels the SelectionKey and closes the channel.

A new telnet session will see the "Connection refused" error as expected.

Next, I would type a small word into the first telnet session, and the server would print it in its console, and close the connection.

At the same time, it prints the message "I am ready to listen for new messages now.." on its console, and invokes the above startListening() method again - making it ready to listen and accept a new client.

We re-try the connection from the same command prompt that received the 'Connection refused' earlier, and as expected are greeted with the welcome message again.

What did we learn?

A low level NIO server can stop accepting new connections, if it can determine that its not able to serve new clients. Once it stops accepting connections this way, any client connection attempt will see a 'Connection Refused' error. This may not be the case if our server was implemented differently (See my last article and its example and how Tomcat behaves under load).

Complete source code

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class TestAccept2 {

    private ServerSocketChannel server = null;
    private Selector selector = null;

    public static void main(String[] args) throws Exception {
        new TestAccept2().run();
    }

    private void run() throws Exception {
        selector = Selector.open();
        startListening();

        while (true) {
            selector.select();

            for (Iterator i = selector.selectedKeys().iterator(); i.hasNext(); ) {
                SelectionKey key = i.next();
                i.remove();
                if (key.isAcceptable()) {
                    SocketChannel client = server.accept();
                    client.configureBlocking(false);
                    client.socket().setTcpNoDelay(true);
                    client.register(selector, SelectionKey.OP_READ);

                    System.out.println("I accepted this one.. but not any more now");
                    key.cancel();
                    key.channel().close();
                    sayHello(client);

                } else if (key.isReadable()) {
                    readDataFromSocket(key);
                }
            }
        }
    }

    private void startListening() throws IOException {
        server = ServerSocketChannel.open();
        server.socket().bind(new InetSocketAddress(8280), 0);
        server.configureBlocking(false);
        server.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("\nI am ready to listen for new messages now..");
    }

    private void sayHello(SocketChannel channel) throws Exception {
        channel.write(ByteBuffer.wrap("Hi there! type a word\r\n".getBytes()));
    }

    private void readDataFromSocket(SelectionKey key) throws Exception {
        SocketChannel socketChannel = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(32);
        if (socketChannel.read(buffer) > 0) {
            buffer.flip();
            byte[] bytearr = new byte[buffer.remaining()];
            buffer.get(bytearr);
            System.out.print(new String(bytearr));
            socketChannel.close();

            startListening();
        }
    }

}