Java - Hot deployment - java

Recently, I was reading book about Erlang which has hot deployment feature. The deployment can be done without bringing the system down. All the existing requests will be handled by old version of code and all the new request after deployment will be served by the new code. In these case, both the versions of code available in runtime for sometime till all the old requests are served. Is there any approach in Java where we can keep 2 versions of jar files? Is there any app/web servers support this?

If your intention is to speed up development then JRebel is a tool for just this purpose. I wouldn't however recommend to use it to patch a production system.
JRebel detects whenever a class file has changed and reloads it into the running appserver without throwing any old state away. This is much faster compared to what most appservers do when redeploying a whole war/ear where the whole initialization process must rerun.

There are many ways to achieve hot deployment in the Java world, so you'll probably need to be a bit more specific bout your context and what you are trying to achieve.
Here are some good leads / options to consider:
OSGi is a general purpose module system that supports hot deployment
Clojure is a dynamic JVM language that enables a lot of runtime interactivity. Clojure is often used for "live coding" - pretty much anything can be hot-swapped and redefined at runtime. Clojure is a functional language with a strong emphasis on immutability and concurrency, so in some ways has some interesting similarities with Erlang. Clojure has some very nice web frameworks like Noir that are suitable for hot swapping web srever code.
The Play Framework is designed to enable hot swapping code for productivity reasons (avoiding web server restarts). Might be relevant if you are looking primarily at hot-swapping web applications.
Most Java applicatio servers such as JBoss support some form of hot-swapping for web applications.

The only reason for hot updates on production application is the aim to provide zero downtime to the users.
LiveRebel (based on JRebel) is the tool that could be used in conjunction with Jenkins, for instance. It can do safe hotpatching as well as rolling restarts while draining the sessions on the production cluster.

Technically, you CAN do this yourself. Although, I wouldn't recommend it since it can get complicated quickly. But the idea is that you can create a ClassLoader and load your new version of your class. Then make sure that your executing code knows about the new ClassLoader.
I would recommend just using JBoss and redeploying your jars and wars. Nice and simple for the most part.
In either case, you have make sure you don't have any memory leaks because You'll run out of PermGen space after a few redeployments.

Add RelProxy to your toolbox, RelProxy is a hot class reload for Java (and Groovy) to improve development even for production, with just one significative limitation, reloading only is only possible in a subset of your code.

Related

Advantages of using Fat Jars over Containers

I wanna know the difference between the two and also which one is currently used more according to industry standards. I tried finding resources online but the content about Fat Jars is very less and also almost no contrast is shown between the two anywhere.
It seems not a big deal at a first glance. The reason for that is that the Java packaging system is really mature and grew strong over many years. Many other ecosystems do not benefit from this and can benefit greatly from being packaged into a container image. But containers are not only about packaging. Packaging could almost be considered a side-effect of it.
Amongst others, some benefits of using containers over simple Fat JARS are:
Simplified infrastructure
For a big (or mid-sized) enterprise built around microservices, chances are that not all of them are using the same languages and tools. A container provides a predictable way of deploying all those different things in the same manner, so it greatly simplifies the infrastructure, thus dramatically reducing company costs with it. This becomes even more important when deploying into the cloud, especially in multi-cloud-provider scenarios, and in that case, container orchestration provided by software like Kubernetes help a great deal without much effort.
Consistency
Another benefit of containers over regular JARs is consistency across environments. Imagine for instance that you deploy your JAR into DEV (running Java 8) and then into PROD (running Java 10). For some reason the JVM behaves differently, either because of default Garbage Collector or something else, making your program behave differently in both environments. When you deploy through a container image, the same image will be used across different environments, and thus the same Java version will be always used, making it less error-prone.
Resource isolation
Yet another benefit is resource isolation. Containers can make sure that your application "see" only a predetermined amount of memory and CPUs. Actually, there were some improvements in Java 10 regarding this matter, you can read more about it here.
Hope this provides with a better point of view regarding this matter.
Depending on your needs, you can use either standalone fat jars or fat jars inside containers. Key point I'm making is there is no standoff between the two, in fact they are complimentary.
Fat jar is a primary way to wrap java application so it could be easily containerized.
Of course, you could use fat jars in standalone ways too.
Pros of containerization:
You can take advantage of unified tooling for containers. I.e., you set up docker and you can run any container - be it java with fat jar or node.js or anything else.
You can take advantage of various container orchestration systems (docker compose, docker swarm, kubernetes, etc) - meaning you use unified tooling for healthchecks, monitoring, rolling updates, etc.
You don't need to worry about things like JRE / JDK versions on your system.
When you may still want to use standalone:
When you have java-centric architecture and established processes around that and it would be costly to change from that to modern container orchestration.
When you are using java as primary scripting (or application) platform on your instance and simply don't want any overhead of containers.

Easy deployment of a jvm based web server on a remote machine

I wanted to know what is the easiest way to deploy a web server made using java or kotlin. With nodejs, I just keep all the server code on remote machine and edit it using the sshfs plugin for vscode. For jvm based servers, this doesn't appear as easy since intellij doesn't provide remote editing support. Is there a method for jvm based servers which allows quick iterative development cycle?
Do you have to keep your server code on remote machine? How about developing and testing it locally, and only when you want to test it on the actual deployment site, then deploy it?
I once tried to use SSH-FS with IntelliJ, and because of the way IntelliJ builds its cache, the performance was terrible. The caching was in progress, but after 15 minutes I gave up. And IntelliJ without its caching and smart hints would be close to a regular editor.
In my professional environment, I also use Unison from time to time: https://www.cis.upenn.edu/~bcpierce/unison/. I have it configured in a way to copy only code, not the generated sources. Most of the times it works pretty well, but it tends to have its quirks which can make you waste half a day on debugging it.
To sum up, I see such options:
Developing and testing locally, and avoiding frequent deployments to the remote machine.
VSCode with sshfs plugin, because why not, if it's enough for you for nodejs?
A synchronization tool like Unison.
Related answers regarding SSHFS from IntelliJ Support (several years old, but, I believe, still hold true):
https://intellij-support.jetbrains.com/hc/en-us/community/posts/206592225-Indexing-on-a-project-hosted-via-SSHFS-makes-pycharm-unusable-disable-indexing-
https://intellij-support.jetbrains.com/hc/en-us/community/posts/206599275-Working-directly-on-remote-project-via-ssh-
A professional deployment won't keep source code on the remote server, for several reasons:
It's less secure. If you can change your running application by editing source code and recompiling (or even if edits are deployed automatically), it's that much easier for an attacker to do the same.
It's less stable. What happens to users who try to access your application while you are editing source files or recompiling? At best, they get an error page; at worst, they could get a garbage response, or even a leak of customer data.
It's less testable. If you edit your source code and deploy immediately, how do you test to ensure that your application works? Throwing untested buggy code directly at your users is highly unprofessional.
It's less scalable. If you can keep your source code on the server, then by definition you only have one server. (Or, slightly better, a small number of servers that share a common filesystem.) But that's not very scalable: you're clearly hosted in only one geographic location and thus vulnerable to all kinds of single points of failure. A professional web-scale deployment will need to be geographically distributed and redundant at every level of the application.
If you want a "quick iterative development cycle" then the best way to do that is with a local development environment, which may involve a local VM (managed with something like Vagrant) or a local container (managed with something like Docker). VMs and containers both provide mechanisms to map a local directory containing your source code into the running application server.

Can multiple JVM processes share memory for common classes?

I'd like to run multiple Java processes on my web server, one for each web app. I'm using a web framework (Play) that has a lot of supporting classes and jar files, and the Java processes use a lot of memory. One Play process shows about 225MB of "resident private" memory. (I'm testing this on Mac OS X, with Java 1.7.0_05.) The app-specific code might only be a few MB. I know that typical Java web apps are jars added to one server process (Tomcat, etc), but it appears the standard way to run Play is as a standalone app/process. If these were C programs, most of that 200MB would be shared library and not duplicated in each app. Is there a way to make this happen in Java? I see some pages about class data sharing, but that appears to apply only to the core runtime classes.
At this time and with the Oracle VM, this isn't possible.
But I agree, it would be a nice feature, especially since Java has all the information it needs to do that automatically.
Of the top of my hat, I think that the JIT is the only reason why this can't work: The JIT takes runtime behavior into account. So if app A uses some code in a different pattern than app B, that would result in different assembler code generated at runtime.
But then, the usual "pattern" is "how often is this code used." So if app A called some method very often and B didn't, they could still share the code because A has already paid the price for optimizing/compiling it.
What you can try is deploy several applications as WAR files into a single VM. But from my experience, that often causes problems with code that doesn't correctly clean up thread locals or shutdown hooks.
IBM JDK has a jvm parameter to achieve this. Check out # http://www.ibm.com/developerworks/library/j-sharedclasses/
And this takes it to the next step : http://www.ibm.com/developerworks/library/j-multitenant-java/index.html
If you're using a servlet container with virtual hosts support (I believe Tomcat does it) you would be able to use the play2-war-plugin. From Play 2.1 the requirement of always being the root app is going to be lifted so you will probably be able to use any servlet container.
One thing to keep in mind if that you will probably have to tweak the war file to move stuff from WEB-INF/lib to your servlet container's lib directory to avoid loading all the classes again and this could affect your app if it uses singleton or other forms of class shared data.
The problem of sharing memory between JVM instances is more pressing on mobile platforms, and as far as I know Android has a pretty clever solution for that in Zygote: the VM is initialized and then when running the app it is fork()ed. Linux uses copy-on-write on the RAM pages, so most of the data won't be duplicated.
Porting this solution might be possible, if you're running on Linux and want to try using Dalvik as your VM (I saw claims that there is a working port of tomcat on Dalvik). I would expect this to be a huge amount of work, eventually saving you few $s on memory upgrades.

What are my options in distributing a J2EE app on multiple servers?

I'm using JSP+Struts2+Tomcat6+Hibernate+MySQL as my J2EE developing environment. The first phase of the project has finished and it's up and running on a single server. due to growing scale of the website it's predicted that we're gonna face some performance issues in the future.
So we wanna distribute the application on several servers, What are my options around here?
Before optimize anything you should detect where your bottleneck is (Services, Database,...). If you do not do this, the optimization will be a waste of time and money.
And then the optimization is for example depending on you use case.
For example, if you have a read only application, add the bottleneck is both, Java Server and Database, then you can setup two database servers and two java servers.
Hardware is very important too. May the easiest way to to update the hardware. But this will only work if the hardware is the bottleneck.
You can use any J2EE application server that supports clustering (e.g. WebLogic, WebSphere, JBoss, Tomcat). You are already using Tomcat so you may want use their clustering solution. Note that each offering provides different levels of clustering support so you should do some research before picking a particular app server (make sure it is the right clustering solution for your needs).
Also porting code from a standalone to a cluster environment often requires a non-negligible amount of development work. Among many other things you'll need to make sure that your application doesn't rely on any local files on the file system (this is a bad J2EE practice anyway), that state (HTTP sessions or stateful EJB - if any) gets properly propagated to all nodes in your cluster, etc. As a general rule, the more stateless, the smoother the transition to a cluster environment.
As you are using Tomcat, I'd recommend to take a look at mod_cluster. But I suggest you to consider a real application server, like JBoss AS. Also, make sure to run some performance tests and understand where is the bottleneck of your application. Throwing more application servers is ineffective if, for instance, the bottleneck is at the database.

Is it better to keep libraries in the application lib or in common/lib?

I'm doing some Spring development and I'm trying to decide if libraries should always be kept in the application lib, even if they end up being common to more than one app. Doesn't Tomcat startup slowdown if a bunch of jar files end up in the common/lib? I'm also fearful of versions and dependencies. Isn't that less of a problem if the application maintains its own copy of everything? Are there going to be occasions where Tomcat absolutely needs a library to be in common/lib because the jar is specific to the functionality of the container and not really the application?
Unless there is very good reason to make them common, then keep individual copies for each application.
You may run into VERY nasty classloader problems if you make them common.
I tend towards keeping libraries common to the application, and not being shared.
If you have more than one application using these libraries, and you have to upgrade a library (for a feature, or a bug fix), then you're going to have to retest (perhaps even recompile/deploy) all those applications.
Keeping libraries with the applications means that you're not locked into testing all your apps if you need to change just the one. Each application is effectively sandboxed.
(you may find for speed of development that it helps to share the common libraries in your development environment. However that's distinct from the final deployment scenario)

Categories