Apache Thrift is a remarkable piece of technology. It is orders of magnitude more light weight than any XML or JSON based protocol and it is much easier to use than SOAP, CORBA, or EJB. I wanted to cover some of my bases before I recommend it at work, so I wrote a hello world program.
First, you need to download and install thrift compiler. You can find all of the information you need on the thrift site. It takes awhile to build it from sources, so make sure you have a good cup of coffee ready.
I wanted to write a hello world program and benchmark it against a native Java implementation to see how much overhead I am incurring. This implementation looks like this:
public class HelloWorldNative { public static String hello(String name) { return "Hello, "+name; } public static void main(String args[]) { long start=System.currentTimeMillis(); for (int i=0;i<100000;i++) { System.out.println(hello("world"+i)); } long end=System.currentTimeMillis(); System.out.println((end-start)+" ms"); } }
On my laptop this completed in 1217 ms. Now lets try using RPC with thrift. First you need a hello.idl IDL file:
service HelloWorld { string hello(1: string name) }
You compile it using thrift compiler like this:
thrift --gen java ./hello.idl
Thrift can generate client and server components for all of the languages it supports, including Java and C++.
Now you need to implement the handler for your server:
public class HelloWorldHandler implements HelloWorld.Iface { @Override public String hello(String name) throws TException { return HelloWorldNative.hello(name); } public static void main(String args[]) throws Exception { TServerTransport transport=new TServerSocket(9090); TServer server=new TThreadPoolServer(new TThreadPoolServer.Args(transport) .processor(new HelloWorld.Processor(new HelloWorldHandler()))); System.out.println("Started"); server.serve(); } }
HelloWorld class is generated by the thrift compiler and inside you will find interfaces and classes for you to use. Had I not already had a HelloWorldNative class I would’ve written mine from scratch implementing the HelloWorld.Iface interface. It’s a good practice to keep your code in sync with DDL as closely as possible.
The main class starts a multithreaded server on port 9090.
Now you need the client code:
public class HelloWorldClient { /** * @param args * @throws TException */ public static void main(String[] args) throws TException { TTransport transport; transport = new TSocket("localhost", 9090); transport.open(); TProtocol protocol = new TBinaryProtocol(transport); HelloWorld.Client helloClient=new HelloWorld.Client(protocol); long start=System.currentTimeMillis(); for (int i=0;i<100000;i++) { System.out.println(helloClient.hello("world"+i)); } long end=System.currentTimeMillis(); System.out.println((end-start)+" ms"); } }
Run the client code. On my laptop it completed in 4885 ms. Given all the extra plumbing that is in between the client and the server I’d say this is not unexpected.
Some interesting things to explore are — how do we pool connections ? How does it behave in a multi-threaded environment ? We know it all works because of our experience with Cassandra, but we wanted to use Thrift for our purposes how would we go about it ? But for now, this simple “hello world” works.