我有多个与HazelCast内核以及相关的问题。
让我先说明一下情况。
我们有一个监视多个网络基础设施的监控系统。
我有一个Spring应用程序,它可以作为负载平衡器后面的多个节点部署。除此之外,这个应用程序还可以在多个基础设施中运行,只需运行不同的配置文件,如infra-1-prod、infra-2-prod等。
它的水平可伸缩以及多用途。这一特性是通过使用不同配置文件运行应用程序来实现的。
随着其他事情的发生,这个概要文件改变了底层DB连接到一个包含特定基础结构的配置数据的关系数据库。
查看应用程序的相关体系结构。

同一个spring引导应用程序可以作为不同基础设施的节点运行,生成自己的HazelCast实例节点。如果应用程序有6个节点,那么HazelCast集群将有6个节点。他们都会同步的。
现在我有了一个名为Repository的RuleRepository,它返回特定规则别名的Rule数据。
@Repository
public interface RuleRepository extends JpaRepository<Rule, Long> {
@Cacheable(value = Constants.CACHE_ALIAS)
Optional<Rule> findByAlias(String ruleAlias);
//some other functions
}现在的问题是,由于规则别名是由DB序列自动生成的,别名R_123指向Infra-1和Infra-2节点的不同数据,但由于所有HazelCast节点都是同步的,因此不正确的数据将被覆盖。
为此,我想为每个基础设施给缓存指定不同的名称,这样缓存的数据就不会乱七八糟。
这样做并不是直截了当的,因为我们不能将属性注入缓存名称。为此,我们需要实现我们自己的自定义CacheResolver和CacheManager。
在我提出第一个问题之前,我将阐述我对HazelCast的理解。
每个HazelCast实例都可以有多个Map配置,这些配置基本上就是不同的缓存。每个CacheManager都可以用一个HazelCast实例链接,该实例内部将包含多个缓存。
问题1:如果CacheManager和HazelCastInstance之间的关系是一对一的,那么我将如何确定将哪个方法数据缓存到哪个缓存中(Map )。
以下是我目前的未完成的实现。
public class CacheableOperations {
private final CacheManager cacheManager;
private final CacheManager noOpCacheManager;
public CacheableOperations(CacheManager cacheManager, CacheManager noOpCacheManager) {
this.cacheManager = cacheManager;
this.noOpCacheManager = noOpCacheManager;
}
private Map<String, CacheableOperation<?>> opMap;
public void init() {
List<CacheableOperation<? extends Class>> ops = new ArrayList<>();
ops.add(new CacheableOperation.Builder(RuleRepository.class)
.method("findByAlias")
.cacheManager(cacheManager)
.build());
postProcessOperations(ops);
}
public CacheableOperation<?> get(CacheOperationInvocationContext<?> context) {
final String queryKey = getOperationKey(context.getTarget().getClass().getName(),
context.getMethod().getName());
return opMap.get(queryKey);
}
private void postProcessOperations(List<CacheableOperation<? extends Class>> ops) {
Map<String, CacheableOperation<?>> tempMap = new HashMap<>();
for (CacheableOperation<?> op : ops) {
for (String methodName : op.getMethodNames()) {
tempMap.put(getOperationKey(op.getTargetClass().getName(), methodName), op);
}
}
opMap = ImmutableMap.copyOf(tempMap);
}
private String getOperationKey(String first, String second) {
return String.format("%s-%s", first, second);
}下面是CacheConfiguration的类
@Configuration
@AllArgsConstructor
public class CacheConfiguration extends CachingConfigurerSupport {
private final CacheProperties cacheProperties;
private SysdiagProperties sysdiagProperties;
@Bean
@Override
public CacheManager cacheManager() {
return new HazelcastCacheManager(hazelcastInstance());
}
@Bean
@Profile("client")
HazelcastInstance hazelcastInstance() {
Config config = new Config();
config.getNetworkConfig().getJoin().getTcpIpConfig().addMember(sysdiagProperties.getCache().getMemberIps()).setEnabled(true);
config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(false);
config.setInstanceName("restapi-master-cache-" + sysdiagProperties.getServiceName());
return Hazelcast.newHazelcastInstance(config);
}
@Bean
@Override
public CacheResolver cacheResolver() {
return new CustomCacheResolver(cacheProperties, operations(), noOpCacheManager());
}
@Bean
public CacheManager noOpCacheManager() {
return new NoOpCacheManager();
}
@Bean
public CacheableOperations operations() {
CacheableOperations operations = new CacheableOperations(cacheManager(), noOpCacheManager());
operations.init();
return operations;
}下面是CacheableOperation类
public class CacheableOperation<T> {
private final Class<T> targetClass;
private final String[] methodNames;
private final CacheManager cacheManager;
private CacheableOperation(Class<T> targetClass, String[] methodNames, CacheManager cacheManager) {
this.targetClass = targetClass;
this.methodNames = methodNames;
this.cacheManager = cacheManager;
}
public Class<T> getTargetClass() {
return targetClass;
}
public String[] getMethodNames() {
return methodNames;
}
public CacheManager getCacheManager() {
return cacheManager;
}
public static class Builder<T> {
private final Class<T> targetClass;
private String[] methodNames;
private CacheManager cacheManager;
private Map<String, Method> methods = new HashMap<>();
public Builder(Class<T> targetClass) {
this.targetClass = targetClass;
Arrays.stream(targetClass.getDeclaredMethods())
.forEachOrdered(method -> methods.put(method.getName(), method));
}
public Builder<T> method(String... methodNames) {
this.methodNames = methodNames;
return this;
}
public Builder<T> cacheManager(CacheManager cacheManager) {
this.cacheManager = cacheManager;
return this;
}
public CacheableOperation<T> build() {
checkArgument(targetClass != null);
checkArgument(ArrayUtils.isNotEmpty(methodNames));
checkArgument(Arrays.stream(methodNames).allMatch(name -> methods.get(name) != null));
return new CacheableOperation<T>(targetClass, methodNames, cacheManager);
}
}
}最后是CacheResolver
public class CustomCacheResolver implements CacheResolver {
private final CacheableOperations operations;
private final CacheProperties cacheProperties;
private final CacheManager noOpCacheManager;
public CustomCacheResolver(CacheProperties cacheProperties, CacheableOperations operations, CacheManager noOpCacheManager) {
this.cacheProperties = cacheProperties;
this.operations = operations;
this.noOpCacheManager = noOpCacheManager;
}
@Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
if (!cacheProperties.isEnabled()) {
return getCaches(noOpCacheManager, context);
}
Collection<Cache> caches = new ArrayList<>();
CacheableOperation operation = operations.get(context);
if (operation != null) {
CacheManager cacheManager = operation.getCacheManager();
if (cacheManager != null) {
caches = getCaches(cacheManager, context);
}
}
return caches;
}
private Collection<Cache> getCaches(CacheManager cacheManager, CacheOperationInvocationContext<?> context) {
return context.getOperation().getCacheNames().stream()
.map(cacheName -> cacheManager.getCache(cacheName))
.filter(cache -> cache != null)
.collect(Collectors.toList());
}
}问题2:在整个代码库中,我无法找到缓存名称和方法名称之间的链接,就像我在第一个代码段中所做的那样。我所能看到的就是方法名称和
cacheManager实例之间的链接。我该把它定义在哪里?
在这种情况下,我所读到的关于Spring和HazelCast的所有问题和文档似乎都不够深入。
问题3:有人能直接为我定义
CacheResolver和CacheManager的角色吗?
谢谢你的耐心。即使是一个问题的答案也可能对我有很大帮助。:)
发布于 2020-02-07 08:15:20
可以在@Cacheable注释中指定参数。例如:
@Cacheable("books")
public String getBookNameByIsbn(String isbn) {
return findBookInSlowSource(isbn);
}它将决定所使用的内部映射/缓存的名称。
https://stackoverflow.com/questions/60088208
复制相似问题