Single JVM process architecture
Hi everyone,
I’m working on a Java project that will run entirely in a single JVM (deployed via Docker Compose).
Inside the JVM I will have “services” which will handle the business logic. Each service/replica will run in a separate thread giving me async processing. The architecture which I’m going with will pull data from APIs into rabbitmq queue on a set schedule during the day.
I thought of creating a service which will consume the data from queue, do some logic on it and save it to database. There will be a few other such services but I’m not yet at this point. My question is how do I implement health checks for my architecture? I’m using plain Java, I don’t want to mess with spring even though I know it provides that functionality with actuators. My idea was to have another “service” spin up in a separate thread which would call other services and report if they are active. That health check would expose an endpoint to container. The goal is to let Docker Compose’s healthcheck call that endpoint and automatically restart the container if anything goes down (either a component or the beat itself).
My questions:
1. Is an in-JVM scheduled task plus a simple embedded HTTP server the best pattern here, or are there libraries/patterns I’m missing?
2. Are there pitfalls around thread safety or scheduling I should watch out for?
3. Would it ever make sense to route my internal health-check over RabbitMQ instead of direct method calls?
The idea of running it as single JVM came up to save me the pain of managing services while keeping the idea behind them(might not be a good idea but this is what I’m going for).
9 Replies
⌛ This post has been reserved for your question.
Hey @Westu! Please useTIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here./closeor theClose Postbutton above when your problem is solved. Please remember to follow the help guidelines. This post will be automatically marked as dormant after 300 minutes of inactivity.
1. If everything happens in a single JVM/one process, you don't have much scaling - you cannot distribute your workload over multiple machines for example
2. Yes - if your program is multithreaded, your code accessing sshared state must be thread safe.
LinkedBlockingQueue etc can help.
3. If everything runs in a single process/JVM, there's no need for RabbitMQ. But it can be useful if you have different JVMs/containers1. Workload will not be an issue so scaling is not the main concern in my case as the application will be limited by api throughput. Eventually there will be frontend showing the data from the database so I imagine it will be going through another thread though, still I don’t think it will need multiple tenants to work
2. Will look into that, thanks for suggestion
3. I’d like to keep rabbitmq as it gives me a way to scale things if needed in the future (contradicts with 1. But I’d like to keep that option available) without a big rewrite. It also helps with data persistence during restarts without any impactful cons. It also would allow to spin up few containers with the same jvm if needed.
You didn’t touch on health check which is my main concern. If the services within the jvm live on separate threads is there a better way of doing that other than I described before?
if anything in your application relies on it being the same JVM, you cannot split it up.
and if you are doing it like that, it will very likely result in your application being dependent on the services running in the same JVM just by you using the same object in some code here and there - even if you are using RabbitMQ
you wouldn't even notice it
unless you do extra things to ensure there is no common code at which point - just put it in different JVMs
and if you are using a single JVM, you probably don't really need health checks for all the services
You would normally not even use one thread oer service - you'd instead just use a common executor or similar and just execute whatever you need
That gave me something to think about. Will have to sit on it and discuss it, although my concern in that regard is adding more functionalities to the code where at some point that simple approach might not be enough. I still don’t know all the details that the final application will need so I don’t want to block myself and keep it clean. That’s the reason I wanted to structure it more like modular monolith hence one process but service-like implementation.
Thanks for sharing your thoughts on this though
If you are finished with your post, please close it.
If you are not, please ignore this message.
Note that you will not be able to send further messages here after this post have been closed but you will be able to create new posts.
yes but even in a modular monolith, you would have a shared thread pool
you could even do something where you use rabbitmq and your application can take out entries and it's configured to be capable of handling any type of element/entry - if you want to scale, you can then factor out parts of it (e.g. the handling for a few specific types of messages)
Messages are consistent as the APIs are not changing often and always return the same format of message just with different data so in that regard I don’t think there could be any issues.
That said, going full monolith without service-like implementation seems to be the best approach but I’ll still need to make sure that future functionalities will not be blocked by that decision. I’m assuming anything that frontend will ask for will go through that application as well as making reports from the pulled data and other things that I might be forgetting right now.
There is also tracing angle playing a role in the decision where I’d like to be able to trace all changes to the data from api->database but that is specific to architecture which I’ll end up going with
💤 Post marked as dormant
This post has been inactive for over 300 minutes, thus, it has been archived.
If your question was not answered yet, feel free to re-open this post or create a new one.
In case your post is not getting any attention, you can try to use /help ping.
Warning: abusing this will result in moderative actions taken against you.