-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(cache): add hazelcast distributed cache option #6645
feat(cache): add hazelcast distributed cache option #6645
Conversation
Unit Test Results (build & test)638 tests +17 634 ✔️ +17 16m 0s ⏱️ -1s Results for commit 988a71b. ± Comparison against base commit fdcb731. This pull request removes 4 and adds 21 tests. Note that renamed tests count towards both.
♻️ This comment has been updated with latest results. |
import lombok.Data; | ||
|
||
|
||
@Data | ||
public class CachedEntityLineageResult { | ||
private final EntityLineageResult entityLineageResult; | ||
private final String entityLineageResult; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we are serializing this result? interesting
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is essentially a DTO wrapper around the result to be able to include the timestamp (and anything else we want to add in later) onto the cached value so any RecordTemplate used within it has to be serialized
private int cacheMaxSize; | ||
|
||
@Value("${searchService.cache.hazelcast.serviceName:hazelcast-service}") | ||
private String hazelcastServiceName; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we have hazelcast in the name of variables here?
isn't the idea that we can swap in differnt impls for the caffeine cache?
does this seem overly-specific?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i see - so we are only accounting for 2 cases: caffeine and hazel. i think i get it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spring Cache Manager is intended for very very simple use cases when switching out cache implementations. Unfortunately our use cases are complex enough where it requires using the provider level interfaces so we would need to reimplement any other implementations we support. This is unchanged from how it previously was, but just exposes the implementation name in the config. It's possible that other providers would also require a headless K8s service for their distributed cache implementation, but unlikely (if we even do implement another underlying supported cache) so I think it's okay to be specific here.
@@ -82,6 +82,10 @@ graphService: | |||
searchService: | |||
resultBatchSize: ${SEARCH_SERVICE_BATCH_SIZE:100} | |||
enableCache: ${SEARCH_SERVICE_ENABLE_CACHE:false} | |||
cacheImplementation: ${SEARCH_SERVICE_CACHE_IMPLEMENTATION:caffeine} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor minor: in terms of config layout, what if we did this
cache:
type: "hazelcase"
config:
hazelcast:
serviceName: .... same
this may read a bit easier. thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, I had it at the upper level to be in line with the enableCache variable, but I think it's fine to start a new pattern here.
Timer.Context cacheAccess = MetricUtils.timer(this.getClass(), "getBatch_cache_access").time(); | ||
K cacheKey = cacheKeyGenerator.apply(batch); | ||
String json = cache.get(cacheKey, String.class); | ||
result = json != null ? toRecordTemplate(SearchResult.class, json) : null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hazelcast requires that the cached object is a string? Or serializable? Cannot record template be serialized by itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Requires that it be serializable, RecordTemplate does not implement Serializable and any RecordTemplate being used in the key or value was throwing errors. Looked into trying to inject a custom deserializer into the Hazelcast deserialization config, but this was much easier.
@@ -0,0 +1,64 @@ | |||
package com.linkedin.gms.factory.search; | |||
|
|||
import com.hazelcast.config.Config; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice test
public class CachedEntityLineageResult { | ||
private final EntityLineageResult entityLineageResult; | ||
public class CachedEntityLineageResult implements Serializable { | ||
private final byte[] entityLineageResult; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: Ideally this detail would be hidden to consumer of the CachedEntityLineageResult. We should auto deserialize it on "getEntityLineageResult"
|
||
@Data | ||
public class CachedEntityLineageResult implements Serializable { | ||
private final byte[] entityLineageResult; | ||
private final long timestamp; | ||
|
||
public CachedEntityLineageResult(EntityLineageResult lineageResult, long timestamp) { | ||
this.entityLineageResult = gzipCompress(toJsonString(lineageResult)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice encapsulation!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
definitely better than having external consumers needing to know about this internal detail
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM if it looks good to others.
…6645) Co-authored-by: Aseem Bansal <[email protected]>
Checklist