Introduction to Grizzly-Thrift and sharing the benchmarking results

This page is for introducing Grizzly-Thrift server/client modules and sharing various benchmarking results.

Object serialization/deserialization of Java comes expensive. For improving this lack, we sometimes used to use other frameworks for RPC such as Protobuf and Thrift which support various programming languages, RPC and own data structures.

Especilally, Thrift has already provided various transport types. Basically, there are TSimpleServer, TThreadPoolServer, TNonblockingServer and THsHaServer for server and there is TSocket for client.

But Thrift's transport layer can be replaced for performance improvement by other NIO frameworks. So I tried to make another transports based on Grizzly and benchmark it experimentally. It's Grizzly-Thrift server/client module.

For using Grizzly-Thrift server, you should add ThriftFrameFilter and ThriftServerFilter to Grizzly transport. For using Grizzly-Thrift client, you should add ThriftFrameFilter and ThriftClientFilter to Grizzly transport.

If you are already familiar to Thrift, this is easy. If you aren't, I recommend that you review Thrift's tutorial examples first. (See the JavaServer.java and JavaClient.java in Thrift's tutorial.)

Grizzly-Thrift modules already include basic unit tests based on Thrift's tutorial. (See the ThriftTutorialTest.java in Grizzly-Thrift.)

If you are using maven in your project, here are pom.xml's dependencies.

--- pom.xml ---

...

<dependency>

<groupId>org.glassfish.grizzly</groupId>

<artifactId>grizzly-framework</artifactId>

<version>2.2.3</version>

</dependency>

<dependency>

<groupId>org.glassfish.grizzly</groupId>

<artifactId>grizzly-thrift</artifactId>

<version>1.0</version>

</dependency>

...

In addition, Grizzly provides various IO strategies such as worker-thread, same-thread and leader-follower so I also tried to test Grizzly-Thrift modules with each IO strategy. If you would like to know more Grizzly's IO strategies, please see the this.

- Benchmarking -

I also benchmarked various Thrift Server-Client modules which are TSocketServer/Client, TThreadpoolServer, TTNonblockingServer, Netty Server/Client and Grizzly Server/Client. I used business operations based on Thrift's tutorial for test but modified a bit logic for packet size.

Netty client had the performance issue unfortunately, so I would exclude it for next benchmarking.

3M + Binary + 40 Connections

Server Types

TSocket Client

Grizzly Client

TThreadPoolServer

11,219

11,215

TNonblockingServer

11,221

11,221

Netty

11,213

11,221

Grizzly

11,220

11,222

In 3M test, Compact/Binary and Server/Client tests were meaningless with regards to performance.

3K + Compact + 40 Connections

Server Types

Grizzly Client

TThreadPoolServer

8,283,705

TNonblockingServer

5,801,319

Netty

9,058,550

Grizzly

8,964,358

Grizzly(SameIO)

9,098,590

TNonblockingServer had the performance issue. And Netty and Grizzlys' results were better than Thrift server modules'.

3K + Binary + 40 Connections

Server Types

TSocket Client

Grizzly Client

TThreadPoolServer

7,619,693

8,163,692

TNonblockingServer

5,444,630

6,032,290

Netty

8,254,168

8,930,896

Grizzly

8,204,097

8,833,978

Grizzly(SameIO)

8,257,918

8,960,497

Grizzly client module had better performance than TSocket client so I would use only Grizzly client for next benchmarking.

In 3K test, Compact protocol was better than Binary protocol. And Netty and Grizzlys' results were better than Thrift server modules' so I would use only Netty and Grizzly server for next benchmarking.

300Bytes + Compact + 20 Connections

Server Types

Grizzly Client

Netty

10,269,876

Grizzly(SameIO)

10,349,440

Grizzly(LeaderF)

9,654,216

300Bytes + Compact + 40 Connections

Server Types

Grizzly Client

Netty

14,569,820

Grizzly(SameIO)

14,770,452

Grizzly(LeaderF)

13,674,641

300Bytes + Compact + 60 Connections

Server Types

Grizzly Client

Netty

15,783,774

Grizzly(SameIO)

15,962,425

Grizzly(LeaderF)

15,227,426

300Bytes + Compact + 80 Connections

Server Types

Grizzly Client

Netty

16,964,578

Grizzly(SameIO)

16,712,315

Grizzly(Worker)

15,890,537

Grizzly(LeaderF)

16,252,280

300Bytes + Compact + 100 Connections

Server Types

Grizzly Client

Netty

15,879,803

Grizzly(SameIO)

15,781,153

Grizzly(Worker)

16,136,977

Grizzly(LeaderF)

16,437,650

300Bytes + Compact + 120 Connections

Server Types

Grizzly Client

Netty

15,904,968

Grizzly(SameIO)

15,985,106

Grizzly(Worker)

16,097,609

Grizzly(LeaderF)

16,164,636

300Bytes + Compact + 150 Connections

Server Types

Grizzly Client

Netty

15,952,442

Grizzly(SameIO)

16,109,154

Grizzly(Worker)

16,261,584

Grizzly(LeaderF)

15,923,040

300Bytes + Compact + 500 Connections

Server Types

Grizzly Client

Netty

12,463,442

Grizzly(SameIO)

12,499,963

Grizzly(Worker)

12,461,131

Grizzly(LeaderF)

12,532,517

300Bytes + Compact + 1000 Connections

Server Types

Grizzly Client

Netty

11,867,630

Grizzly(SameIO)

11,903,400

Grizzly(Worker)

11,906,507

Grizzly(LeaderF)

11,812,262

In many connections(more than 120 connections), most of servers didn't receive proper requests of client because the client machine of this environment used too much resouces such as high CPU usages. So I think that more client machines are needed to calculate meaningful data of more connections. In 100 connections, Netty and Grizzly's same-thread IO strategy's throughput decreased but Grizzly's woker-thread IO and leader-follower IO strategies' throughput increased.

In my test cases and environments, worker-thread IO strategy and leader-follower IO strategy were more effective than same-thread IO strategy if servers should have more than 100 connections.

- Conclusion -

Results of 300Bytes + Compact + 40 Connections

Server Types

TSocket Client

Netty Client

Grizzly Client

TServer

741,417

604,558

TThreadPoolServer

14,731,560

12,747,230

TNonblockingServer

6,060,111

6,723,402

Netty

14,749,519

14,569,820

Grizzly(SameIO)

14,931,745

9,066,525

14,770,452

Results of 3KBytes + Compact + 40 Connections

Server Types

TSocket Client

Netty Client

Grizzly Client

TServer

631,300

526,341

TThreadPoolServer

7,708,088

8,283,705

TNonblockingServer

5,264,995

5,801,319

Netty

8,372,804

9,058,550

Grizzly(SameIO)

8,381,352

3,718,431

9,098,590

300Bytes + Compact + 100 Connections

Server Types

Grizzly Client

Netty

15,879,803

Grizzly(SameIO)

15,781,153

Grizzly(Worker)

16,136,977

Grizzly(LeaderF)

16,437,650

Server Module

Grizzly same-thread IO strategy was best in a few connections. Grizzly leader-follower IO strategy was best in many connections.

In small packets, TSocket was best. In larget packets, Grizzly client was best.

Thrift Protocol

In this scenario, Compact protocol was best.

Finally, I decided that our company, Kakao would use worker-thread IO strategy for Grizzly-Thrift server in real fields because it was very stable. For client I decided that I would use same-thread IO Strategy because of efficiency.

If you are already using Thrift or have a plan to use Thrift for RPC, just try to apply Grizzly-Thrift!

(I think these results are only for reference so you could meet different results according to your environments and benchmarking logic).