Skip to main content

Is Java the right language for Micro Services?

[work in progress]
Micro Server for Micro services

Micro services are becoming slowly but steady mainstream programming architecture. People often compare them to web services or rest services witch gives more problems than understanding. And when you look at implementation you'll see that developers are running away from Java to Scala, Nodejs or Python or name it. Is Java old? Is it time to close Java book and learn something new? Learning new things is always good, but I think reason why developers run away from Java is not a language problem, but Java legacy.

Biggest problem why developers avoid Java to make micro services is that there are not so many good tools and servers for micro services in Java or put it better there are many old wrong tools and server to start with. If you are old Java developer you will have problems to grasp this.

When you start to create micro service your focus should be on micro. Project should compile in less than 10s.Your service should have only packages, libraries and frameworks that it really needs, everything else should be striped away. Start of the server should be fast less than 10 sec.

Problem is when you start web project in Java you are entering in dependency hell of big application servers, heavy blocking databases that have ALL that you do NOT need and frameworks that solve all problems that you do not have and have support for everything you do not need.

You will write in Java 10-15 classes that will solve problem of your service, and then you will deploy that on heavy J2EE server, with some REST framework that will add to your project tones of jars you do not need. You will create war package that ziped is 20-200MB, that you need to deploy and start server.

That is wrong J2EE legacy, heavy over engineered solution that should fit all web problems. Problem is not Java itself. Example of wrong tools in Java for micro services are dropwizard, spring roo, tomcat, jetty, any JDBC database.

What do you really need?

You need for your project of 10-15 classes a server that runs as a jar or exe. No deployment, no other applications on that server. You need non blocking fully asynchronous server written in 2-6 classes that starts in less than 5s and it doesn't have ANY additional dependencies. You need asynchronous NoSQL storage. There are few alternative server options from which you can start or you can choose to get your hands dirty and fight yourself for things how they should be.

New simple server will have just 2-6 classes. It will use just java. It will use NIO2 java classes. It will start as simple java app. No wars to deploy, simple start and stop. So it should work almost as nodejs, in one thread. We can add reactor jar if we need better multi-threaded support.


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
package org.avenger.sts.server;

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

public class SingleThreadedServer implements Runnable {

 protected int serverPort = 8080;
 protected ServerSocketChannel serverSocketChannel = null;
 protected Selector selector = null;
 protected boolean isStopped = false;

 public SingleThreadedServer(int port) {
  this.serverPort = port;
 }

 public void run() {

  openServerSocket();
  SocketChannel socketChannel = null;

  while (!isStopped()) {
   System.out.println("is running");
   try {
    int readyChannels = selector.select();
    if (readyChannels == 0) {
     System.out.println("none");
     continue;
    }

    Set<selectionkey> selectedKeys = selector.selectedKeys();
    Iterator<selectionkey> keyIterator = selectedKeys.iterator();

    while (keyIterator.hasNext()) {
     System.out.println("while");

     SelectionKey lkey = keyIterator.next();

     if (lkey.isAcceptable()) {
      // a connection was accepted by a ServerSocketChannel.
      System.out.println("accept");
      try {
       socketChannel = serverSocketChannel.accept();
       if (socketChannel != null) {
        socketChannel.configureBlocking(false);
        socketChannel.socket().setTcpNoDelay(true);
        socketChannel.register(selector,
          SelectionKey.OP_READ);
       }

      } catch (IOException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
      }

     } else if (lkey.isConnectable()) {
      // a connection was established with a remote server.
      System.out.println("connected");
     } else if (lkey.isReadable()) {
      // a channel is ready for reading
      System.out.println("read");
      socketChannel.register(selector, SelectionKey.OP_WRITE);
     } else if (lkey.isWritable()) {
      System.out.println("write");
      try {
       processClientRequest(socketChannel);
      } catch (IOException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
      }
     }

     keyIterator.remove();
    }
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }

  }

  System.out.println("Server Stopped!");
 }

 private void processClientRequest(SocketChannel socketChannel)
   throws IOException {
  if (socketChannel == null)
   return;

  long time = System.currentTimeMillis();

  // TODO should direct buffer be used if we need large capacity?,
  // allocate vs allocateDirect
  // when allocateDirect is used socketchannel throws exception
  // TODO create one buffer if possible
  ByteBuffer inbuf = ByteBuffer.allocate(48);
  int bytesRead = socketChannel.read(inbuf);

  //System.out.println(bytesRead);
  //System.out.println("new String(inbuf.array()) 1: "
   // + new String(inbuf.array()));

  // char[] cctest = inbuf.array();

  String read = "";
  while (bytesRead &gt; 0) {
   read = read + new String(((ByteBuffer) inbuf.flip()).array());
   bytesRead = socketChannel.read(inbuf);
   // System.out.println(bytesRead);
   // System.out.println("new String(inbuf.array()) 0: " + new
   // String(inbuf.array()));
   // System.out.println("READ: " + read);
   inbuf.compact();
  }
  System.out.println("READ: " + read);

  // use charBuffer or Trove char listS
  /*
   * CharBuffer read = CharBuffer.allocate(1024); while (bytesRead &gt; 0) {
   * char[] rr = ((ByteBuffer)inbuf.flip()).asCharBuffer().array();
   * read.put(rr); bytesRead = socketChannel.read(inbuf); inbuf.compact();
   * } System.out.println(read.array());
   */

  // TODO parse char[] not string
  HttpRequestParser parser = new HttpRequestParser();
  try {
   parser.parseRequest(read);
   System.out.println("RequestLine: " + parser.getRequestLine());
   System.out.println("Host: " + parser.getHeaderParam("Host"));
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

  String newData = "HTTP/1.1 200 OK\n\n<html><body>"
    + "Singlethreaded Server: " + time + "</body></html>";

  ByteBuffer outbuf = ByteBuffer.allocate(newData.getBytes().length);
  outbuf.clear();
  outbuf.put(newData.getBytes());

  outbuf.flip();

  while (outbuf.hasRemaining()) {
   socketChannel.write(outbuf);
  }

  socketChannel.close();

  System.out.println("Request processed: " + time);
 }

 private synchronized boolean isStopped() {
  return this.isStopped;
 }

 public synchronized void stop() {
  this.isStopped = true;
  try {
   this.serverSocketChannel.close();
  } catch (IOException e) {
   throw new RuntimeException("Error closing server", e);
  }
 }

 private void openServerSocket() {
  try {
   this.serverSocketChannel = ServerSocketChannel.open();
   this.serverSocketChannel.socket().bind(
     new InetSocketAddress(this.serverPort));
   this.serverSocketChannel.configureBlocking(false);

   selector = Selector.open();
   SelectionKey key = this.serverSocketChannel.register(selector,
     SelectionKey.OP_ACCEPT);
  } catch (IOException e) {
   throw new RuntimeException("Cannot open port: " + this.serverPort,
     e);
  }
  System.out.println("Server started ! on port: " + this.serverPort);
 }
}


no J2ee
no big tools
fast compile less than 10s
start jar, no war no deploy,


github link
https://github.com/sasajovancic/avenger

parse url
String Parsing.... Boon has really fast String parsing about 2x
https://github.com/boonproject/boon



links
http://technologyconversations.com/2015/01/07/monolithic-servers-vs-microservices/
http://martinfowler.com/articles/microservices.html
https://www.quora.com/Can-micro-services-be-developed-only-in-Node-js-Cant-we-develop-them-in-other-languages-like-Java
http://blog.erlware.org/monolith-vs-microservices-where-to-start/

Comments

Unknown said…

A quick list of frameworks to build µservices in Java

Synchronous
* http://projects.spring.io/spring-boot/
* http://www.dropwizard.io/0.9.1/docs/
Asynchronous
* http://vertx.io/
* https://github.com/spotify/apollo
* https://github.com/advantageous/qbit

So a lot of choice.
Only when the footprint of the container is of utmost importance, I make the switch from Java to Go.

My 2c
sasajovancic said…
Dropwizard and spring boot i used a lot, they are faster than traditional tomcat apps, but wrong tools for this job.

Vertx is really great, you are right, bit little bit to big already. I think it is possible to create slim variant of vertx.

Thanks for comment.

Popular posts from this blog

Javascript REST client

Note : I still work on text, code example should be fine. REST is the one of the most popular interfaces on the web today. One part to its success it owes to its simplicity. How number of sites that support REST grows we will need some fast and good solution to use those services on client side. Even if its possible to do it all, since REST is based on http, with old AJAX calls, it would be nice to have some little more... This is one approach that i choose. I create in javascript new object that has six methods five for REST methods, four for POST, PUT, GET and REMOVE plus one more to GET all resources, and one more to get html template to display your data. This code is based on jquery and json js libs. function RestServiceJs(newurl) { this.myurl = newurl; this.add = function(model, callback) { $.ajax({ type: 'POST', url: this.myurl, data: JSON.stringify(model), // '{"name":"' + model.name + '"}',

Use JPA with MongoDb and Datanucleus

Web applications nowadays have huge demand for data processing, and they need to get them, process them, and displayed them fast. Traditional relational tables and big SQL engines fail to serve that purpose. NoSQL movement is on the rise. There are huge numbers of alternatives to SQL like BigTable, HBase, CouchDB, Cassandra and MongoDB. They are all fast but you'll need to implement new way to work with them, since all of them have they own query languages. It would be nice that we can use them in similar or same way in our projects, after all ORM layer is there for that to decouple our objects from underlying storage. MongoDB is one of most popular NoSQL solutions and easiest one to install. For HBase i would had to install cygwin or virtual linux, and still will be hard to confgiure it right. MongoDb is easy, it plays out of the box, just unzip it, and it still offers some nice features like MapReduce, Replication and Sharding. Datanucleus is one of the leading ORM provid

Gestalt Diffing algorithm in Java

What we see depends mainly on what we look for. John Lubbock We do not see things as they are, we see things as we are. Anais Nin Gestalt Diffing algorithm in Java Intro When it comes down to diffing or LCS usually story ends with Myers algorithm. It is idea to create BitMatrix (or IntMatrix) of similarities between two strings and then to approach to a problem from graph point, and find the shortest path of changes between two arrays. It sounds as a great solution, and it is, but in reality it has few drawbacks. It is algorithm that gives great results most of the time but it is a slow algorithm for some obvious cases, if strings are equal, or very similar. You create whole matrix but for your solution not all values from matrix are needed. It involves one more algorithm, finding the shortest path in it self. Then improvements of Myers algorithm came, like to check on start are strings are equals, to check for same prefix or suffix, to run snake chase from both