[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.
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/
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 > 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 > 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
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
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.