So the first piece of the puzzle was to have individual service running. This is easily solved with Spring Boot. Since most services doesn't even be need to run as Web services (run in a servlet-container) it can be as small as a few mb!
So I wanted all the communication between the services to be solved by messaging.
The "normal" way is point-to-point. The problem is that you are bound by the API, sure you can do good coding and use a interface so you actually can switch the implementation. But somewhere the implementation is bound. When you need to do a swap, that redeployment will disturb the things that uses it.
Can you do a redeploy without disturbing the system?
Answer: Not sure, but I will try!
My thought is this: If you have services that uses messages queues then you can theoretically have several instances of that service handling messages in the same queue (not the same messages but the same type of messages).
If that works then you could have an instance of the old version and an instance of a new version (where a bug is fixed) and then remove the old instance and work would probably not have been interrupted.
This is also the solution for scaling that I'm testing. Can you have several instances of the same service?
So far so good, my fear is when users and session come and messes things upp.
AMQP
So instead of JMS (Java Message System) I'm using AMQP (Advanced Message Queuing Protocol).
One of the reasons is that is has clients for several languages so you can have some services with another language.
"AMQP mandates the behavior of the messaging provider and client to the extent that implementations from different vendors are truly interoperable, in the same way as SMTP, HTTP, FTP, etc. have created interoperable systems. Previous attempts to standardizemiddleware have happened at the API level (e.g. JMS) and thus did not ensure interoperability.[2] Unlike JMS, which merely defines an API, AMQP is a wire-level protocol. A wire-level protocol is a description of the format of the data that is sent across the network as a stream of octets. Consequently any tool that can create and interpret messages that conform to this data format can interoperate with any other compliant tool irrespective of implementation language." (Wikipedia)
Spring, of course, has a project for this: Spring AMQP. I'm using Spring Boot Starter AMQP (not fully sure yet what the "starter" is about)
Status:
So where am I right now (December 23)?
I've done a service which listens to a queue on RabbitMQ (I named the queue and RabbitMQ is running in docker, use the official dockerfile/rabbitmq)
This service will handle every message in that queue, it will print what the message is and change the message.
If the service that sends the message demands that it wants a response, that service will get the changed message.
The other service just sends 10 messages (with Thread.sleep(1000) between each message) to the queue. This now works like a charm!
But I had some big problems with this! First off, I'm new to spring boot and messaging.
So I could quickly make these services with examples from the web.
Problems:
The problem was that this only worked with one instance at a time! No bueno!
I started the MessageHandler-service, no problem.
I started message-sending-service instance 1, no problem.
I started message-sending-service instance 2, the messages got jacked by instance 1!
And instance 1 saw it as the message was sent after the timeout (no kidding! since it actually already got a response before!)
The problem was that the MessageListenerContainer that was used was still running after the response-demand was fulfilled.
If I stated instance 1 and 2 and then started the message-handler (love queues!) they got there responses correct.
So how do I fix this? (many hours of fun)
First came the o-so-fun task of actually finding out what it's called. (send-respond/receive-respond and more)
It seems that most people use either a separate queue for each client or each request!
This seemed like a performance hog.
But in RabbitMQ 3.4.0 there is a function for a pseudo-queue for just these occasions.
It's called Direct-to. We let the code and RabbitMQ handle the response (so that the right message comes to the right sender).
The Docker-RabbitMQ was version 3.4.2 lucky!
Next problem: this is supported in Spring AMQP 1.4.1.
What version does Spring Boot 1.2.0.RELEASE have of AMQP? 1.4.0.... O joy...
I tried that version and it didn't work. I'm not sure if Spring Boot allows me to switch a version of one of its sub-projects. I didn't get it to work, but it might just be my incompetence .
So I took my chance with version 1.2.1.BUILD-SNAPSHOT!
And hey what do you know, it worked! I deleted the response-listener completely in the message-sender, the Direct-to function handles it for ous.
Minor setback:
The "pseudo-queue" for the Direct-to function https://www.rabbitmq.com/direct-reply-to.html#use
Have an official queue name " amq.rabbitmq.reply-to", it needs to be exactly this!
I stumbled upon this in a StackOverflow answer. The Spring Documentation actually had a typo of this: http://docs.spring.io/spring-amqp/reference/html/amqp.html#direct-reply-to
under section 3.7.1 it said " amqp.rabbitmq.reply-to" that "p" should not be there!
And I understand how easy of a mistake this is, I thought it was the other way around, why would it be "amq" instead of "amqp"?
But no problem, I submitted the typo to the Spring Jira issue site (issue AMQP-458) and the awesome Gary Russell has already fixed it, it'll be in the 1.4.2 version: https://github.com/spring-projects/spring-amqp/commit/fca82ce3d54bb2024efa6275a2e661cd20829de6
You got to love Open Source!
I'm happy to help fix this, cause you don't get any fun errors if you do this typo.
You just don't get any response. The message gets handled but that's it. Now the message-senders is just waiting for the postman that never will come.
So I hope this will help someone, I will keep you posted with my findings and results. In the end I will probably give some code, just now it's not so pretty ^^ except the gradle, that is pretty!
If your trying to replicate my idea and get stuck, don't hesitate to comment and I will try to help you as best as I can.
PS: These services will have there own Docker-containers and be run from there. They don't need to know about each other or there respective IP-numbers, you gotta love Messaging systems.
So code away!
No comments:
Post a Comment