Thoughts on microservices. Part 1. Does my app deserve to be microservice–based?

Ok, its ten minutes past 6.00 p.m. I’m on my way from Plovdiv to Sofia just right after the wonderful #jProfessional Plovdiv 2019. Although there are only 130 km between two cities, an express train makes them them for two hours and a half through beautiful Balkan mountaines. Just enough time to summarize some thoughts on microservices I recently had. I still wonder aren’t this thoughts too stupid, but they still bother me.

Just to mention, that this #jProfessionals Plovdiv was EPIC! It totally worth a separate post.

So:

Картинки по запросу microservices everywhere

Everybody writes microservices, no matter the reason, for good or for bad. Most of the talks on conferences are about microservices. Every new project is expected to be with microservices architecture. If there is no buzzword “Microservices” nobody from customers would ever listen to you. Some of the juniors I have on my teams say – “Of course microservices! Is there another way? Monoliths? Ah, they are bad! Why? It’s obvious!”

So, technically, I see everybody trying to make their software with this architecture. Or they say the do microservices, although the most projects I’ve seen usually consist of 2–3 fat services. Those projects look like a monolith artificially chunked into pieces that talk REST to each other. People try to decouple this chunked elements as much as they can, but most of the time it’s really obvious that these parts are still logically very coupled and cant live without each other.

I quite often have the following conversation when I consult some project:

– “Ok, you’ve got 40 request per day. The interface is for internal use. You’ve got a team of four developers. Why are you doing six microservices, you’re routing requests with Istio, you’ve got an angular UI”

– “Pretty cool, ah?”

– “How do you spread responsibility in the team, each of you develop his own service?”

– “No, everybody is responsible for all of the code.”

– “What will happen if one of the services will fail?”

– “We throw exception and render code 500.”

– “How do you deploy it?”

– “We’ve got one ubuntu VM on AWS right now. There is docker installed there.”

– “You will run all of the services there?”

– “Yes, and the database.”

– “Will you ever scale?”

– “No.. may be up to 50 requests.”

– “What about security?”

– “Oh.. It will run in secure environment!”

– “What do you mean by secure secure environment?”

– “It will run in intranet.”

– “Ok, now a general question: what is the problem you are trying to solve with microservices?”

– “What do you mean?”

– “Why would you split the app in 6 independent apps?”

– “They are logically split. What’s wrong?”

– “Ok, 50 request per day, it can’t work if one or more services stop… Isn’t a JSF/Vaadin small app just enough for this?”

– “Man! You are such a retrograde!”

I start thinking to myself, well, may be I’m getting old. I believe many C developers think the same about us Java developers – “Look how much overhead they make!!!”.

But still I wonder, is it really worth making everything as microservices? Will this automatically guard you from all of the architecture problems? Or would it create new problems you didn’t have before?

This architecture IMHO should not be considered as absolutely universal. Quite often this causes additional unnecessary overhead. The same time most of the developers I use to know sincerely believe that this is the only way of doing things. They don’t even consider other approaches.

I believe, that we as developers/architects should first ask ourselves – “What are the problems are we going to solve when applying microservices architecture? Do I really need it?”.

Before starting a new project, I personally do a list of answers on a single question: “Why this app should not be a monolith?”. If I find myself at least three technical answers different from “This is modern!”, “Everybody does this!”, “We can do it with one team!”, I start considering microservices as a potential architecture for the requested app.

And every time I start a new project I remember myself the dialog above. Does my app deserve to be microservice–based?

This doesn’t mean, microservices are bad and monolith is good. This means, we as professionals should make the right choice for the right case. It is very hard to give recipes, but it is always a good idea just to think before applying a certain architecture!

By the way, there are two great talks by Daniel Bryant “Seven deadly sins of microservices” and “Seven (more) deadly sins of microservices” (available in youtube.). They are very useful.

The interesting thing is that my current project really nicely suits to microservices architecture. We have several teams doing their own services. The services can run independently and they follow the main idea that “A microservice should be doing one thing, but in the best way!”. There will be pressure and scalability issues. Microservices architecture will help us solve these problems.

But there I have some thoughts about the way a current microservice should be implemented. This will be the subject for the next post.

And yes, train is a nice place to work. Especially if there is an A/C plug.

Oh, here is Sofia. It has beautiful renewed central station.

Quarkus: a blast from the future

Yep, Quarqus has definitely exploded just few weeks ago. As one of my friends said, it was marketing lvl8080! Just listen to the slogan – “Supersonic Subatomic Java!”. “A Kubernetes Native Java stack tailored for GraalVM & OpenJDK HotSpot, crafted from the best of breed Java libraries and standards”. Damn, so many buzzwords in one place! The twitter literally exploded as well. Literally everybody twitted about Quarkus.

I said – nah! Yet another microservices framework. There are many available now. The choice is really big. So, I almost ignored it. I’m honest here. Still the last Sunday I’ve downloaded it and played with some examples. My first experience was a failed build. I’ve submitted an issue in GitHub, and it turned to be my local maven issue. The fix was just to upgrade it. But as result this issue opened a discussion, and very same Sunday a maven version enforcer was added. The power of OSS! There are no weekend in OSS! Kudos to the team!

The twit flow nevertheless continued to appear in my feed. This somehow forced to open the Quarkus website and explore more. There was one logo that grabbed my attention:

I said – mmm MicroProfile. Lovin’ it! So it looks like I may try to pack a microservice (which is not Spring) in a GraalVM native image.

Ok, I need to try! This thought came to my mind about 3 a.m. this Thursday. Well, technically it was Friday already…

Luckily enough about a month ago we have deployed some CSV aggregation service. Yet another stage of some fancy bloody enterprise infinite process to generate some invoices. We have made it the most modern way using only MicroProfile specs, on WildFly server, running in some OpenShift pods (yes, we have a lot of RedHat licences). Mmm, a loot of cool buzzwords as well!

The service itself was completely stateless. With three rest clients we gather some data from there other services, mash them up in some CSV and serve it as a plain text on rest request! Technically it is insanely stupid! … making it the perfect candidate to be tested with Quarkus. By the way, all of the pipeline is still under development, so thus we’re not going to ruin someone’s bill and invoice.

Still the service has to work under some pressure. Thus OpenShift scales by adding pods. Since the service is stateless, we are totally ok with that! We also don’t have to care about rest providers from the other side. It’s their responsibility to scale 🙂

So, now comes the fun part!!! I’ve started a new project by copying some of the Quarkus quick–starters. Yes, I can generate a pom from an architype.. but I’m lazy.

I then just copy-pasted the code from my old project.. and it shined red.. Especially the the MicroProfile annotations.. ah. What’s wrong? 3 minutes of googling told me that for the MicroProfile stuff I need to add some Smallrye Quarkus extentions.. Ok, copy–pasted in the pom.xml.. Yay, the red is gone.

mvn clean package

… and BUILD SUCCESSFUL!

Ok, you made me sweat! Now let us:

mvn quarkus:dev

.. and .. http://localhost:8080/api/v1/invoicingRXT/1253211 (some contract)

AND I HAVE THE RESULT! That’s a WOW!!! This was one the fastest migrations I’ve ever done! I LOVE STANDARDS! Long live MicroProfile!!!

Ok, I have earned my coffee. It took me.. 17 minutes. Yes, this was mostly copy–paste, but look how cool is that!

… But, thats not over! Quarkus documentation says if I add -Pnative to the maven build command it’ll produce a native image! Let’s do it! Luckily I had already setup the GraalVM installation.

mvn clean package -Pnative

Waiting.. 1 minute… 2 minutes.. BUILD SUCCESSFUL! Lovely! Yes, it takes some time to build an image! I should admit, that the business logic code was written in quite straightforward way, without any fancy constructions, just some POJOs. There were no GraalVM specific issues.

Now let us just run the executable:

./invoicingRTXApp-runner

and the service is up and running in about a second! Although the console says the startup time is 0,212 sec. Technically from the run command to running service is about 2 seconds. THAT DOESN’T COMPARE to ~49 seconds startup time of the WildFly server..

Ok, now lets go to http://localhost:8080/api/v1/invoicingRXT/1253211 and what I see:

“”,””,””,””,””

Something went wrong!!! Why the example from the quick-starters work? Hmm… It looks like I’m missing one annotation over some classes – @RegisterForReflection. Reflection works a little different in GraalVM. Building it once again. Waiting another two minutes. Oh, how can two minutes can last so long..

Good! BUILD SUCCESSFUL! Now lets go to http://localhost:8080/api/v1/invoicingRXT/1253211 and what I see:

data1,data2,data3

IT WORKED!!! (Now imagine the famous Dexter from Dexter’s lab cartoon shouting this loud). That is so damn cool!!!

Картинки по запросу dexters lab it works

Nice! It’s been 42 minutes since the beginning of the experiment (coffee break included)!

Ok, now let us go back to the OpenShift setup. It will be nice to see if it’s ok in our test environments under some pressure. After making some yaml permutations I’ve rerouted 10% of the traffic to go the new native image pod. After 4 hours watching it work I see no errors! Only sometimes I receive some messages from surprised testers like “Something’s wrong, some pods start in 3 seconds only…”. And I say “Haha! This is magic.”

Now some intermediate conclusions:

– WildFly 78 Mb image, Native 21 Mb image;

– WildFly ~49 seconds start-up, Native ~2 seconds start-up time;

– WildFly ~300 ms per request, Native ~270 ms per request (we are dependent on other services).

– Wildfly ~359 Mb RAM (serving 1 request), Native ~22 Mb RAM (serving 1 request)

Lovely! Just, Lovely!

What can I say – Quarkus is definitely a good thing to play with. It showed extremely well in (almost) production code. Yes, I know the example is really stupid, but that’s a real world demand. The migration took me about 40 minutes by just copy–paste. I love standards!

The coming Monday I’ll make a full native setup, we’ll see how it goes! May be even in production soon..

Disclaimer: Sorry, I can’t share the code. It’s corporate..