Cache: complex keys causing very low hit rate and large number of evictions
See original GitHub issueOriginal issue created by jacek99 on 2014-02-11 at 05:13 PM
We have a complex key consisting of a POJO with 4 string fields, an Integer and a DateMidnight (from Joda Time). 2 out of the 4 String fields can be null at any time.
It seems with a simple key (e.g. a single String) the cache is very fast,
However, with a complex key like this the hit rate and number of evictions goes up dramatically, e.g.:
Hit rate: 33.30 % Miss rate: 66.69 % Average load penalty: 5.44 ms Eviction count: 15002 Request count: 24402 Load exception rate: 0.00 %
if we convert all these keys into a single String using a StringBuilder is starts being super fast again with a hit rate of ~99.9%.
The problem with that is in the loading method we have to parse the String to break out the original 6 pieces that made it. Not preferable for an application with near real-time SLAS.
Set up:
cache = CacheBuilder.newBuilder() .maximumSize(100_000) .expireAfterWrite(5, TimeUnit.MINUTES) .concurrencyLevel(100) .recordStats() .build( new CacheLoader<ItineraryResultCacheKey, ItineraryResult>() { @Override public ItineraryResult load(ItineraryResultCacheKey key) throws Exception {
… cache loading code…
});
}
On OpenJDK 7. Tested this with both 14.01 and 16.01, same results.
I’ve tried multiple things (using Date with all hours/minutes/seconds set to 0 to ensure key equality), converting all values to a single string and coding the equals() and hashCode() to use that instead of the other fields.
To no avail.
It seems that if you put in a complex POJO as a key, something goes wrong in the Cache internals and we consistently get a hit rate of ~33%, never more. Very weird that it is always so consistent.
I admit, it is a bizarre issue. Any suggestions on what we may be doing wrong are welcome.
Issue Analytics
- State:
- Created 9 years ago
- Comments:6
Top GitHub Comments
Original comment posted by jacek99 on 2014-02-11 at 05:56 PM
I hang my head in shame. Equals()/hashCode() are not the problem.
We had previously existing code in a totally different section of the app that was actually mutating this key during multiple parts of the processing (one of the fields). This was done as part of a naive attempt to reduce GC pressure by reusing object instances (instead of instantiating them multiple times with minor variations).
Once I removed that and made it properly instantiate a new instance every time every started running properly.
Please close as invalid.
Thanks for sharing this, helped me with a similar issue. Praise!