On the latest episode of the New Relic Modern Software Podcast, we welcome Java guru Ben Evans—who recently joined New Relic’s European Development Center in sunny Barcelona, Spain—to take a close look at the current state of the world’s most popular programming language, New Relic’s support of Java and open source, optimizing Java in a microservices world, Java anti-patterns, and much, much more.
Ben is a Java Champion, three-time JavaOne Rock Star speaker and, a prolific author of Java books, including The Well-Grounded Java Developer, and co-author of Optimizing Java and the new edition of Java in A Nutshell. He spent six years as a member of the Java Community Process Executive Committee (aka the JCPC) helping define standards for the Java ecosystem. Leading Ben’s interview is our inimitable co-host Tori Wieldt, a Java expert in her own right, who managed Oracle’s Java community for five years.
You can listen to the episode right here, or get all the episodes by subscribing to the New Relic Modern Software Podcast on Libsyn or wherever you get your podcasts. Read on below for a full transcript of our conversation with Ben, edited for clarity:
New Relic was the host of the attached forum presented in the embedded podcast. However, the content and views expressed are those of the participants and do not necessarily reflect the views of New Relic. By hosting the podcast, New Relic does not necessarily adopt, guarantee, approve, or endorse the information, views, or products referenced therein.
What’s changed in the world of Java
Tori Wieldt: There’s been some changes in the Java landscape and Oracle has made some recent announcements. At a high level, can you tell us what those changes are?
Ben Evans: The biggest change really is the people. Most enterprises are used to downloading the Java binaries directly from Oracle. And some people might have gotten the idea that Java is open source, and so, therefore, what they were downloading from Oracle were open source binaries, and that’s not actually the case.
Every time you go to Oracle and download those binaries, you’re actually agreeing to a proprietary software license. It’s actually been Oracle’s choice how long it wanted to provide support for those binaries and to provide Java in that way. It has decided to stop providing free binaries for Java 8 and for Java 11. And, obviously, most of the industry is still on Java 8.
This has come as a bit of a surprise to a lot of people. So what’s happening now is if you are a paying customer of Oracle, and you pay for Java support, you can continue to get binaries from Oracle. If you aren’t a paid customer, and you don’t wish to become one, you need to think about how you’re going to have a supported Java runtime that your applications depend upon going forwards.
Now, Oracle’s attitude appears to be that if you want to continue using Java, what you should do if you don’t want to pay is to just come to the latest version of Java each time. Oracle introduced this much faster, more dynamic release schedule, whereby a new major version of Java comes out every six months rather than the two or three years that we have been seeing up to now.
If you think back, there was a big, big gap between Java 6 and Java 7 coming out. And then it was another three years before Java 8 came out after Java 7. And then it was another three years before Java 9 came out. And now we’re suddenly in this world where everything is happening fast, fast, fast. There’s a release of Java every six months. So six months after Java 9 … Java 10. Six months after Java 10 … Java 11. And Java 12 came out in March.
Oracle’s stance is that you should just keep upgrading every six months—”Hey, don’t worry about it. There’s a new Java version out. Just upgrade your applications to use the new version.”
Fredric Paul: Is that something that they wouldn’t want to do? And are there any advantages in having it updated so often?
Ben: Well, I think broadly most enterprises want to have stable platforms and they want to be able to work on new features and fixes for their own applications. They don’t want to be housekeeping every six months. They want to know that the application is going to continue to run without any instability in the platform. Most software teams have a lot on their minds. They want software partners who are going to help them and be receptive to their needs.
Java long-term support releases
Tori: The advantage, though, is that you can get features out much more quickly. So if there is something that the Java community really wants, instead of waiting four or five years to get it, potentially they could get it much faster.
Ben: That’s absolutely right, and that’s great for companies that do want to react more quickly and that have development teams that are super eager to get the new features. But for many enterprises, the people who are concerned with stability—maybe they are in a tightly regulated industry—need a possibility of not having to take this faster upgrade cycle.
That leads us to the discussion of what are being called long-term support releases. Java 11 was the first release to be designated as a long-term support release. And Oracle is targeting to produce these every three years. So the next long-term support release will be Java 17. Again, that’s a huge, staggering, big number.
But then, of course, the vast majority of Java applications are still running on Java 8. Oracle retrospectively grandfathered Java 8 to be a long-term support release as well. But something else has happened— Oracle has now stopped contributing to the open source editions of Java.
The OpenJDK for Java 8 and 11 is actually the reference implementation and it’s the place where all Oracle releases have always started from. From Java 7 onwards, that has been the basis of Oracle’s product. And it has now stopped contributing to it and handed over leadership of the open project to another company. OpenJDK 8 and 11 are now being run by Red Hat.
That’s a huge shift and upheaval in the Java world. What it means is that now if you want to get a free binary of Java 8, you can get one from Red Hat because it’s continuing to produce open source binaries, not the proprietary Java binaries that you’ve traditionally downloaded from Oracle.com.
But now on the OpenJDK sites, you can get a binary, which is equivalent to the Java 8 binary you would have downloaded from Oracle. But it is now a free and open source licensed binary and that means there’s nothing to pay. If you’re an enterprise that wants long-term stability and long-term supported releases, but you also don’t want to pay for a support contract, this may offer the best of both worlds.
The only cost of entry is you have to migrate your systems from using the Oracle binaries—which Oracle now no longer supports unless you’re a paying customer—onto this new open source OpenJDK binary.
Tori: Not doing anything is not an option, right?
Ben: Do nothing is very much not an option. Especially if you want to stay protected and up-to-date with your security patches because there are no more security updates for Java 8 or 11 coming from Oracle unless you pay money for them. I think anyone who is concerned about their applications and wants to ensure that they’re patched and up-to-date really has to make sure that they do make this transition to OpenJDK.
New Relic Java support
Fredric: Now, just so I understand, on the OpenJDK side, if there’s similar vulnerabilities, Red Hat will support patches for them?
Ben: Red Hat and a number of other members of the OpenJDK community will support patches. We’re talking about companies like IBM, Amazon, Microsoft, and some smaller JDK vendors like Azul Systems, which has long been a minor player in the space. We also see some patches from companies like SAP and Alibaba from China.
For customers of New Relic, this means you have choices. Perhaps you already have an existing relationship with IBM, say, or with Red Hat, or perhaps you’re a big AWS customer. Well, you can choose which OpenJDK binary you want to use and whatever choice you make, providing it’s from a major vendor and it’s a certified binary—which from the major vendors they will be—then New Relic will support you. It’s not up to us to tell you how to run your environments. You choose what’s right for your applications, and we’ll have your back.
Fredric: Let’s talk for a moment about how New Relic is involved in all this. What is our support for Java and the Java community?
Ben: Well, first of all, if you are an Oracle JDK user and a paying customer of Oracle, that’s fantastic, of course we’ll support you. If you’ve chosen to stay on Java 8 and transition to an OpenJDK binary, then we’ll support you there too. If it’s going to be IcedTea from Red Hat, we’ll support that. If it’s going to be OpenJDK, which is the community labs open source project that has got a lot of players coming together underneath it, great. That’s one of the main JDKs that we’re going to be using internally at New Relic. If you’re going to use Amazon’s Corretto project, that again is primarily for AWS and Amazon’s own versions of Linux, but if that’s what you have, we will support that. Whatever major vendor you choose, and whatever is right for your applications, New Relic will support it.
Tori: So how will New Relic be more involved in the Java community?
Ben: The watershed that we’ve just gone through, where Oracle is starting to step back and other players are becoming more involved, presents a great opportunity for us here at New Relic to get more involved in the community. Obviously, our interests are in monitoring and in performance analysis because that’s what we provide for our customers. But also, a lot of our own services are written in Java and other JVM languages. So we have a very vested interest in the health and the longevity of the Java platform.
We’ve signed the paperwork that we need to formally join the OpenJDK effort. That means that New Relic engineers will be able to contribute code and other work towards OpenJDK and related projects. I think that demonstrates our long-term commitment to Java and the Java community.
It also means that we are in a position to help our customers get to the bottom of particularly thorny problems. There are some new technologies that are present and open sourced in Java 11, which the community feels will be beneficial to Java 8 as well. And those technologies, because they’re open sourced only on Java 11 at the moment, need to be backported for support on Java 8. And New Relic is going to be involved in some of the early testing of those backports. We run them internally, so we’ll be able to test them out and see whether there is any impact on them being backported into Java 8 to ensure that there were no performance regressions or other side effects. That’s work we’re doing essentially as a gift to the Java community because we think those technologies will be beneficial to our customers.
Java in the world of microservices
Tori: Let’s talk a little bit about Java and optimization. You’ve written a book about it, and I know you were heavily involved in making Java run fast. So I’ve just got to play devil’s advocate: Is Java still relevant in a microservices world?
Ben: When we talk about microservices, there are really two things that I think come together to make up what people think of as microservices. First is the size and the complexity of the application, and the other is the application startup time and the lifetime that a particular process or a particular handler would actually live.
Microservices, as compared to traditional architectures, are smaller in scope for each individual service, and the complexity comes from the composition or aggregation of a large number of services. But they’re also dynamic; they can scale up really quickly because they start out really fast because they’re so simple.
So how is Java still relevant? Or why might people think that Java wasn’t relevant in that world?
Well, traditionally, Java processes start up, and the JVM starts up, and it starts to interpret byte code. But it takes a while for a Java application to reach a steady state because everything has to warm up; in particular, the JIT compiler has to have processed enough transactions and seen enough messages that it can actually figure out what parts of the program were really important so that it can then compile those to super-fast optimized machine code. While Java has extremely good, best-in-class, peak performance, the time it takes to reach that peak performance and get to steady state can be of the order of half a minute, perhaps even a couple of minutes. In a microservices world, that doesn’t sound so appealing.
The challenges for Java really have been twofold. First, can we reduce that warm-up period somehow? Second, can we deal with the size of the Java processes?
There’s no getting away from the fact that Java 8 runtimes come with a certain amount of baggage. The RT.jar, the basic Java runtime, is 150 megabytes by itself. That’s a different order of magnitude to writing some tiny Python program that is going to run in AWS Lambda. That wouldn’t be measured in megabytes—it might be like a megabyte, but certainly not 150!
The good news is that, especially with Java 11, we’ve made some serious progress towards having those be almost completely removed as issues. Java 11 really does move the dial to a place where Java is competitive for microservices development.
For example, with the startup and completion times, there’s new JIT compiling and ahead-of-time compilation options, which you can use for Java 11 to produce very small binaries, which are almost natively compiled. So it’s much more like a Go binary. You can also reduce the size of the footprint because instead of having a monolithic Java runtime, which pulls in Swing and RMI and all of those fully featured Java technologies that enterprises use—if you don’t use that, then why load it up in the first place?
The modularity of Java 11 means that you can start up a Java runtime in a much-reduced amount of space. And, of course, if there’s less stuff to load, it’s going to load much faster. As Java 11 starts to permeate mainstream applications, we’re going to see some interesting and novel deployments.
I think that the things that people love about Java, the richness of the programming environment, the fact that it does have such great developer tooling, such a rich wealth of patterns and experience, and, of course, the fact that for enterprises it’s super easy to hire Java developers … I think all of those strengths are going to continue to play well in the microservices world.
Optimizing Java performance
Tori: So I’m a Java developer—I say my app is too slow, where do you start to make things go faster?
Ben: You just said your app is too slow. What does that mean? We need to ask a question that we can actually measure. The first step is always to understand the problem and to find data and metrics that will enable us to confirm the problem that we think is there is actually there.
This is where tools like New Relic are going to be your friend because it gives you the ability to see that data. We can’t tell you what’s wrong or what’s right for your domain because we’re not the experts in your domain—you are. But what we can do is to give you the tools and the visualizations to see the data, and then it’s up to you to place your own knowledge of your own domain on top of that data and see whether what we’re telling you is good or bad.
Once you’ve determined that it’s bad, then we can help you drill in to find out what you need to fix.
Fredric: Once you have determined that, are there best practices or common threads that you can take to improve the performance of Java apps?
Ben: Absolutely. It’s almost a heuristic process that you can go through to isolate what’s going on. Maybe you’re creating a bunch of Java objects that you don’t need. You’re producing loads and loads of debug-level log messages and then not doing anything with them. That will increase application churn.
And with Java, of course, it’s a garbage collection language. So if you create a bunch of objects that you don’t do anything with, just to make work, then you’re going to increase pressure on the memory. That means you’re going to have to do garbage collection more often, which means that your computer’s resources are diverted away from application processing and actually running the transactions that make up your business.
Tori: All right, now it’s dish time. Tell us some of the anti-patterns you’ve seen out in the wild, the head-slapping things.
Ben: Well, on one occasion before I joined New Relic, I was an independent contractor, and I was asked to come into a bank to have a look at some of their systems. On a whim, I asked to see the source code of their application; they were producing loads of debug log messages that they basically just created and then threw away. Once we took that out, which took about 40 minutes, we could see the memory utilization of their app dropped by 60%. That was supposed to be a two-week engagement, and we were done by lunchtime on the first day!
Other things that I’ve seen: When running Java 8 inside a Docker container, which many people do, lots of people don’t know that because Java 8 predates a lot of the Linux kernels that support Docker properly; there is actually a mismatch between especially earlier versions of Java 8 and the Docker runtime.
What will happen is that Java will see all of the cores that are available on the box. So if you have a box with, let’s say, 128 CPUs, 128 cores in it, and let’s suppose that you are restricted to a Docker container—which gives you access to only four cores. If you don’t explicitly tell Java to constrain its thread number, especially for, let’s say, garbage collection threads, then Java will see 128 cores. When a garbage collection phase starts, it will create 128 garbage collection threads because that matches the number of cores that are on the box.
The problem is that you actually have only eight CPUs allocated to you by Docker. So now what happens is you have 128 tasks that are trying to help clean up your garbage but there are only 8 slots for them to run on. So they fight with each other. There’s contention over trying to get scheduling time on the eight cores that are available.
Tori: It becomes a queuing nightmare?
Ben: Absolutely. Context switching and thrash. That’s another good example of an anti-pattern that we’ve seen.
Of course, that would show up in New Relic because we have a thread profiler, so you could see that, and if you clicked on a Docker container if you hadn’t set the flags properly, you would see, “Wow, this Docker container only has 8 CPUs, but in the profiler, I can see all these garbage collection threads. Why did it make so many?” Those kinds of things can be seen from New Relic as well.
Note: The music for the Modern Software Podcast is courtesy of Audionautix.