Monday, April 13, 2015

Lately, I had to investigate how to make a Java 7 client connect to a server resource (in my case a JMS broker server) using sockets or http traffic over secure TLS v1.2 protocol (and only TLS v1.2... all other communication protocols should be refused). This would all have been a breeze if my client app was on Java 8...but being on Java 7, it was a completely different story.

At first, I thought it'd be easy since my JMS broker server (Terracotta Universal Messaging in this case) already supports TLS v1.2, lets you enforce it through system property (-DSSLProtocols), and also lets you pick which cipher(s) to use. So I thought all I needed was to set that system property on the server side and disable in the UI (called Enterprise Manager) all ciphers for this communication interface BUT the TLS v1.2 ciphers I wanted to use (the "SHA256" cipher suites in this case -- check full list of available ciphers for TLS v1.2 at https://www.openssl.org/docs/apps/ciphers.html)...as shown below in screenshot:

And everything would work fine, right? The client would start the secure handshake with the server, figure out that TLSv1.2 is the only protocol that can be used, and use the right secure protocol version and ciphers as defined by the server.

Well, this theoretical scenario is partially true: Everything is setup properly on the server side, as it rightly says "I only accept TLSv1.2 sessions with the following ciphers". But unfortunately, the Java 7 client does not seem to be able to start a TLSv1.2 secure connection by default (if you're on Java 8, stop reading right now -- unless you're curious of course -- as it would all work fine out of the box)

So this is great! All you and I need is to update the client app's code to specify TLSv1.2 at SSL Context creation!

But wait...what if I'm using a client library to perform all that low level SSLContext connection etc...in that case, it's going to be tricky to update the code, unless specifying the SSL protocol versions and ciphers are exposed to client app in some way (eg. system properties).

If you reach this situation, here are 3 solutions I found (well, I found 1 and 3...solution 2 is credited to a smarter developer :) )

1) If all you want is to create a HTTPS connection (over TLSv1.2) from your client app to the server, you're in luck: all you need is add the following 2 system properties to your client app and the SSL context will be created properly as specified:

https.protocols ==> -Dhttps.protocols=TLSv1.2 (comma-separated list of you want to use several protocols)

https.cipherSuites ==> -Dhttps.cipherSuites=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (comma-separated list of you want to use several ciphers)

2) If you want to use the secure socket protocol (as opposed to HTTPs traffic), the above properties won't work unfortunately...but you could create a "TLSv1.2" SSLContext at application startup and use the "SSLContext.setDefault(ctx)" call to register that new context as the default one.

3) Upgrade your client to JAVA 8, which enables TLSv1.2 protocol by default (at this time, JAVA 8 should be already used anyway, or on most project roadmaps hopefully)

So that's all great and there's a lot to talk about on both these announcements...

But it turns out that one of the first question I got while sharing the news to wider non-tech circles was:
"What's this offheap thing anyway? What's so special about it, and why should I care."

Really fair questions indeed!

So as I wrote my reply and tried hard not to dive in "geeky" land while doing so (please refer to https://github.com/Terracotta-OSS/offheap-store for these technical aspects such as detailed explanations and implementation code), I figured it could be useful to others as well...
So hopefully the following explanation will make sense to a wider non-developper audience (and developers out there too of course!).

So here it is...starting from, well, the start:

Traditionally in Java programming land, the memory space accessible to Java programs (called "heap") is totally managed by the Java Virtual Machine (JVM)...making it much easier for developers to NOT have to think about memory allocations and clean ups (like we used to with programming languages such as C, C++ etc…). And really, "not having to think about memory complexities" is a big part of JAVA’s success over the years.

But the memory management that JAVA performs under-the-hood (refer to as Garbage Collection, or GC) is something that potentially becomes costly performance-wise (lower throughput, higher latencies) especially as the used "heap" space grows (for example, heap space would grow if you started to cache lots of objects in memory)

So to reconcile these 2 contradictory concepts of:

(A) Being able to cache a lot more data (10s of GB or TBs possibly) within your Java application, and
(B) Not incurring a big cost on application performance due to underlying Java memory management operations,

--> Enter Offheap Memory.

Offheap Memory, as the name implies, is a memory space that is "outside the Java heap" (and hence outside the traditional Java memory management responsibilities), but yet still accessible within the Java process through the java.nio API.

So when a product or framework refers to "Offheap" as a general concept, really it means that this product/framework can natively access the machine’s RAM memory directly from the JAVA process (as opposed to doing it the "traditional" way of accessing the machine’s RAM memory through JAVA’s managed memory heap space). In other words, it’s like poking a hole through JAVA’s walls to access the RAM directly.

To the question of why should you care:

With offheap, your Java program can put as much data as it needs in-memory, and access it all within process (there’s no memory limitation aside from the amount of RAM the machine has to offer), even TBs of data (check out this Intel white paper[PDF] showing offheap usage and benchmarks with a single 6TB Intel server)

Your Java program will demonstrate very predictable latencies even if you're storing large amounts of data in-memory (even at the TB scale)...

This is because offheap memory space is not managed by Java in the first place, and as such, storing data in that Offheap space will simply not add any extra JAVA memory management overhead to the picture.

So overall, it’s really the best of both worlds: storing lots of data in memory but not incurring performance unpredictability in the process.

The next question you might have is: if it is such a great concept, why doesn’t everybody do it in their own Java programs?

And the simple answer is that it’s not a straightforward thing to do because you have to create yourself all that low-level memory management when you use the offheap.

And that’s really the "secret" sauce of libraries implementing offheap usage...such as Ehcache/Terracotta libraries (not so secret anymore for ehcache/terracotta since it's officially open-sourced now - refer to offheap-store on github): all these low-level memory mechanisms are done for you and are especially hidden from you so you don’t have to care about them as a Java developer. All you have to know is that you can cache as much as you want/need on a single machine (GBs, TBs even) and that it will not slow down your app unpredictably while doing so (as it would if you were putting all that stuff in the traditional JAVA heap.)