Skip to content

STORM-2204 Adding caching capabilities in HBaseLookupBolt#1783

Closed
ambud wants to merge 8 commits intoapache:masterfrom
ambud:master
Closed

STORM-2204 Adding caching capabilities in HBaseLookupBolt#1783
ambud wants to merge 8 commits intoapache:masterfrom
ambud:master

Conversation

@ambud
Copy link
Contributor

@ambud ambud commented Nov 17, 2016

@ambud ambud changed the title Adding caching capabilities on bolt side STORM-2204 Adding caching capabilities on bolt side Nov 17, 2016
@ambud ambud changed the title STORM-2204 Adding caching capabilities on bolt side STORM-2204 Adding caching capabilities in HBaseLookupBolt Nov 18, 2016
Copy link
Contributor

@revans2 revans2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea. I realize that everything seems to revolve around the guava cache, although there are alternatives to it, and I would prefer that we use one of the alternatives that has less issues with backwards compatibility.

@@ -1,92 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please revert the spacing back to how it was before? Almost every single line changed for what appears to be no reason.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's happened because of my IDE. I would recommend adding the POM-Sort plugin to make sure this is auto fixed when the build runs.

I took a crack at that a few months ago: https://github.com/srotya/srotya-parent/blob/master/pom.xml

<groupId>org.apache.storm</groupId>
<version>2.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove the parent? This allows us to keep a lot of dependency versions in sync so we have more confidence that there are not version conflicts when someone has a topology that includes multiple different sub-pieces

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parent is still there; I believe that is formatting from the IDE causing this.


<artifactId>storm-hbase</artifactId>
<properties>
<hbase.version>1.1.0</hbase.version>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version of hbase should be coming from the parent pom, not being set here. Like I said in the previous comment, we want the parent pom to keep the dependency versions in sync between all of the sub projects.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wait never mind I just saw this was brought over from the original code. You can leave it, but it would still be nice to fix.

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We really should be using the version of guava in the parent pom. And guava always bites people (they really don't like to maintain compatibility) so if we can avoid using it, I would really prefer to do that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with the backwards, what are your thoughts on alternatives.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not really used too many alternatives, So I did a search

https://duckduckgo.com/?q=guava+cache+alternatives&t=ffab&ia=qa

Both https://cache2k.org/ and http://www.ehcache.org/ look interesting, but I have not actually used any of them


protected OutputCollector collector;

protected transient OutputCollector collector;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this transient? I don't see us accessing it from multiple threads, and especially not changing it on multiple threads?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Transient is for serializability errors, I am not sure why it didn't error out in earlier when people tried to use this code.

Since Storm serializes the Bolt code for deployment this should be marked as transient.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right I got confused by the two. Thanks for pointing that out :)

private HBaseValueMapper rowToTupleMapper;
private HBaseProjectionCriteria projectionCriteria;
private transient LoadingCache<byte[], Result> cache;
private transient boolean cacheEnabled;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these transient? The bolt is not multi-threaded.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Transient is for serializability, not to be confused with volatile.

@@ -40,51 +48,85 @@
*
*/
public class HBaseLookupBolt extends AbstractHBaseBolt {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use tab characters for indentation. We are still working on the exact style guides, but we try to keep the style that is currently in the file and it was using spaces before and I expect the style guide to include spaces instead of tabs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to spaces, if this is still a blocked; I will try to reapply the patch to the original file and then update the commits.

this.collector.reportError(e);
this.collector.fail(tuple);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There appears to be a lot of overlap in the code here, between the cache version and the non-cache version. It would really be nice to at least combine most of this. Alternatively we might want to use inheritance in some way to avoid the branching on the cacheEnabled config at all.

@revans2
Copy link
Contributor

revans2 commented Nov 21, 2016

Overall it looks fine to me now. I am still a bit concerned about guava as a dependency, but beyond that it seems like a great addition to the bolt.

@ben-manes
Copy link

@revans2 perhaps Caffeine?

@HeartSaVioR
Copy link
Contributor

I agree it's still better to not relying on Guava since storm-core is shading Guava but external modules are not.
Btw, I didn't use other cache modules too, but ehcache seems to be well-known and widely-used cache library, and Caffeine seems to be a drop-in replacement for Guava cache.

@ben-manes I guess you're the author of Caffeine. Could you introduce Caffeine?

@HeartSaVioR
Copy link
Contributor

Forgot to comment for other side. It looks great.

@ben-manes
Copy link

I was a co-author of Guava's cache, too.

Guava had originally considered soft references an ideal caching scheme, since they offer great concurrency and GC is for memory management. That evolved from ReferenceMap to MapMaker to optimize space, especially in regards to computations (no need for a Future wrapper). Unfortunately soft references result in awful performance outside of a micro-benchmark due to causing full GCs. In parallel, I had been experimenting with approaches for a concurrent LRU cache (CLHM) and when joining Google helped to retrofitted its ideas onto Guava. There was a lot of good that came out of that, but I left before working on optimizing for performance.

Java 8 provided an excuse to start from scratch. Caffeine is much faster and packs in even more features. I also spent time exploring eviction policies, which led to co-authoring a paper on a new technique called TinyLFU. That has a near optimal hit rate, low memory footprint, and amortized O(1) overhead. This is done by tracking frequency in a popularity sketch. The same concurrency model in CLHM and Guava is used (inspired by a write-ahead log), which allows for concurrent O(1) reads and writes.

The HighScalability article provides an overview of the algorithms that I use.

@vesense
Copy link
Member

vesense commented Nov 22, 2016

Overall looks good to me. My major concern is that on-heap caches(like Guava cache, Ehcache) might cause bad GC situations. I didn't use Caffeine in the past, maybe is a candidate.

@revans2
Copy link
Contributor

revans2 commented Nov 22, 2016

Caffeine sounds like a great alternative to Guava and also seems to address some GC concerns.

@vesense I agree storing any large amount of data on heap will impact GC, we do that all the time with all of the queues that we have. I think for the most part as long as GC is tuned properly for the topology, we don't get a lot of full GCs causing promotion in the cache, and TTL in the cache is not too long it will be fine. If we do run into serious GC issues we can then look at off heap cacheing.

@vesense
Copy link
Member

vesense commented Nov 22, 2016

@revans2 Yes, we can find a balance between high rate of cache hits and full GCs. I'm OK for adding a built-in cache if we set parameters carefully.

@revans2
Copy link
Contributor

revans2 commented Nov 22, 2016

@vesense it is off by default so it would be enabled/tuned on a per topology basis.

@ambud
Copy link
Contributor Author

ambud commented Nov 22, 2016

@revans2 @vesense @ben-manes Thanks for the valuable feedback, I am looking into integration with Caffeine. Should have a new commit soon.

@revans2 Indeed the intention is to have the cache tuned based on topology. The ideal use case is where caching actually makes sense and certain keys may have a higher hit frequency then others.

Ideally this bolt should be used with FieldGrouping when caching is enabled so cache misses minimal. Something to be kept in mind is distribution of keys (executor balancing).

@vesense
Copy link
Member

vesense commented Nov 23, 2016

+1

@Override
public Result load(byte[] rowKey) throws Exception {
Get get = hBaseClient.constructGetRequests(rowKey, projectionCriteria);
LOG.debug("Cache miss for key:"+new String(rowKey));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ambud
It would be better to use Cache miss for key: {} instead of +. After fixing this, you can squash commits into one.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ambud
Could you address @vesense comment?
It makes unnecessary creation of String object for non-debug log level.

@HeartSaVioR
Copy link
Contributor

One thing to consider is that Caffeine seems to require Java 8, which means that this patch can't be shipped to 1.x version line. Do we want to keep using Guava for 1.x branch?
@ben-manes Is there any versions for Caffeine which works with Java 7?

@ben-manes
Copy link

Nope. Sorry, since your compilation target is 1.8 I hadn't thought you'd need that.

@ambud
Copy link
Contributor Author

ambud commented Nov 23, 2016

So should I revert back my changes; seems like the build is currently failing; additional tests pushed by upstream?

@HeartSaVioR
Copy link
Contributor

@revans2 What do you think about this? I'm in favor of adopting Caffeine, and I'm even OK to use Caffeine to master and Guava to 1.x.

@revans2
Copy link
Contributor

revans2 commented Nov 28, 2016

@HeartSaVioR I also am find with Caffeine and even Caffeine on 1.x (assuming it is off by default)

@revans2
Copy link
Contributor

revans2 commented Nov 28, 2016

+1 the code looks fine to me.

@HeartSaVioR
Copy link
Contributor

@ambud
The code looks good except what @vesense commented.

Two things more to address:

  1. It would be better to document new configurations. Without documentation, end-users have no idea about added feature. external/storm-hbase/README.md and docs/storm-hbase.md.

  2. The code already uses JDK 8 API (Map.getOrDefault()), so can't get it as it is for 1.x. Could you provide a new PR for 1.x branch?
    It would be also great if you can test it (with Caffeine) on JRE7 (expected to not work but we can document the precondition for JRE version) and JRE8 (expected to work).
    cc. @ben-manes Is my expectation right?

Thanks in advance!

@ben-manes
Copy link

Should fail, e.g. Class version error.

@ptgoetz
Copy link
Member

ptgoetz commented Nov 30, 2016

+1, but I agree with @HeartSaVioR that the new cache configuration options need to be documented before this is merged.

Adding configuration docs to README
@ambud
Copy link
Contributor Author

ambud commented Nov 30, 2016

Added documentation to readme file.

Fixed the debug logging by using isDebugEnabled checks

Are we going to use Guava caching implementation for 1.x? @HeartSaVioR @revans2

@HeartSaVioR
Copy link
Contributor

@ambud I'm OK to use Guava for 1.x. IMHO it would be better to provide complete set of features for guaranteed environment (JDK version) instead of leaving 'warn' to documentation.
And some other external modules also use Guava, too.
@revans2 Are you OK to use Guava only for 1.x? Or you would like to keep using Caffeine for also 1.x and document it?

@ambud
Copy link
Contributor Author

ambud commented Dec 1, 2016

Caffeine is JDK 8 only so won't work for 1.x, since JDK 7 compilation will be tested.

@HeartSaVioR
Copy link
Contributor

@ambud
Yeah if we add unit test for the feature, unit test will fail on JDK 7 which will be always failing on Travis CI. Nice catch. Could you address this to use Guava for 1.x?

@ambud
Copy link
Contributor Author

ambud commented Dec 1, 2016

Sure thing, I will add the Guava patch code originally added for this to 1.x and 0.10.x branches

@vesense
Copy link
Member

vesense commented Dec 1, 2016

+1 for merging to master after updating docs/storm-hbase.md. external/storm-hbase/README.md has been documented.

@revans2
Copy link
Contributor

revans2 commented Dec 1, 2016

I guess guava is OK for 1.x. I would prefer to see it shaded if we do go with Guava, but I am only a -0 if it is not shaded.

@HeartSaVioR
Copy link
Contributor

OK. Since we have other modules which depends on Guava, it might be better to have a rule and apply all of them. +1 to shade Guava on external modules if possible.

@ambud
Copy link
Contributor Author

ambud commented Dec 1, 2016

Can we merge this? @HeartSaVioR @revans2 @vesense

I will need to open another pull request for 1.x branch.

@ambud
Copy link
Contributor Author

ambud commented Dec 1, 2016

1.x branch PR #1810

@ambud
Copy link
Contributor Author

ambud commented Dec 10, 2016

Can we merge this @revans2 @HeartSaVioR @vesense ?

@vesense
Copy link
Member

vesense commented Dec 15, 2016

@ambud Sorry for the delay response. Before we merge this in, can you replace all the tab space to white space?

@ambud
Copy link
Contributor Author

ambud commented Dec 15, 2016

Done @vesense

@asfgit asfgit closed this in 610d58d Dec 15, 2016
@vesense
Copy link
Member

vesense commented Dec 15, 2016

Thanks @ambud Squashed and merged into master. And I added you as the contributor.

@ambud
Copy link
Contributor Author

ambud commented Dec 15, 2016

Thank you @vesense. Could we merge the 1.x pull request as well?

@vesense
Copy link
Member

vesense commented Dec 16, 2016

@ambud I'll wait for other committers to vote for it before merging into 1.x-branch. And this may take some time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants