gpt4 book ai didi

java - 为 Multi-Tenancy 设置 Hazelcast 缓存

转载 作者:行者123 更新时间:2023-12-05 03:54:07 26 4
gpt4 key购买 nike

我目前正在将 JHipster 生成器用于真正的样板代码,其中涉及 HazelCast 作为二级缓存。我能够使用基于 header 的租户上下文来获得 Multi-Tenancy (每个租户的模式)。我现在遇到的问题是,@Cacheable 注释都共享一个上下文。如果缓存很热,我最终会得到跨模式数据。例如,租户 1 从其缓存的表中提取所有记录。租户 2 从他们的表中提取相同的项目,读取缓存,但它永远不会进入实际的租户数据库。一个简单的解决方法是一起禁用缓存,但我不想这样做。我终其一生都无法弄清楚如何让 hazelcast 了解租户上下文——缺少文档。其他一些人已经使用自定义名称解析器解决了这个问题,但它似乎并不像我希望的那样动态(即你必须提前了解所有租户)。想法?

当前缓存配置:

@Configuration
@EnableCaching
public class CacheConfiguration implements DisposableBean {

private final Logger log = LoggerFactory.getLogger(CacheConfiguration.class);

private final Environment env;

private final ServerProperties serverProperties;

private final DiscoveryClient discoveryClient;

private Registration registration;

public CacheConfiguration(Environment env, ServerProperties serverProperties, DiscoveryClient discoveryClient) {
this.env = env;
this.serverProperties = serverProperties;
this.discoveryClient = discoveryClient;
}

@Autowired(required = false)
public void setRegistration(Registration registration) {
this.registration = registration;
}

@Override
public void destroy() throws Exception {
log.info("Closing Cache Manager");
Hazelcast.shutdownAll();
}

@Bean
public CacheManager cacheManager(HazelcastInstance hazelcastInstance) {
log.debug("Starting HazelcastCacheManager");
return new com.hazelcast.spring.cache.HazelcastCacheManager(hazelcastInstance);
}

@Bean
public HazelcastInstance hazelcastInstance(JHipsterProperties jHipsterProperties) {
log.debug("Configuring Hazelcast");
HazelcastInstance hazelCastInstance = Hazelcast.getHazelcastInstanceByName("SampleApp");
if (hazelCastInstance != null) {
log.debug("Hazelcast already initialized");
return hazelCastInstance;
}
Config config = new Config();
config.setInstanceName("SampleApp");
config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(false);
if (this.registration == null) {
log.warn("No discovery service is set up, Hazelcast cannot create a cluster.");
} else {
// The serviceId is by default the application's name,
// see the "spring.application.name" standard Spring property
String serviceId = registration.getServiceId();
log.debug("Configuring Hazelcast clustering for instanceId: {}", serviceId);
// In development, everything goes through 127.0.0.1, with a different port
if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT))) {
log.debug("Application is running with the \"dev\" profile, Hazelcast " +
"cluster will only work with localhost instances");

System.setProperty("hazelcast.local.localAddress", "127.0.0.1");
config.getNetworkConfig().setPort(serverProperties.getPort() + 5701);
config.getNetworkConfig().getJoin().getTcpIpConfig().setEnabled(true);
for (ServiceInstance instance : discoveryClient.getInstances(serviceId)) {
String clusterMember = "127.0.0.1:" + (instance.getPort() + 5701);
log.debug("Adding Hazelcast (dev) cluster member {}", clusterMember);
config.getNetworkConfig().getJoin().getTcpIpConfig().addMember(clusterMember);
}
} else { // Production configuration, one host per instance all using port 5701
config.getNetworkConfig().setPort(5701);
config.getNetworkConfig().getJoin().getTcpIpConfig().setEnabled(true);
for (ServiceInstance instance : discoveryClient.getInstances(serviceId)) {
String clusterMember = instance.getHost() + ":5701";
log.debug("Adding Hazelcast (prod) cluster member {}", clusterMember);
config.getNetworkConfig().getJoin().getTcpIpConfig().addMember(clusterMember);
}
}
}
config.getMapConfigs().put("default", initializeDefaultMapConfig(jHipsterProperties));

// Full reference is available at: http://docs.hazelcast.org/docs/management-center/3.9/manual/html/Deploying_and_Starting.html
config.setManagementCenterConfig(initializeDefaultManagementCenterConfig(jHipsterProperties));
config.getMapConfigs().put("com.test.sampleapp.domain.*", initializeDomainMapConfig(jHipsterProperties));
return Hazelcast.newHazelcastInstance(config);
}

private ManagementCenterConfig initializeDefaultManagementCenterConfig(JHipsterProperties jHipsterProperties) {
ManagementCenterConfig managementCenterConfig = new ManagementCenterConfig();
managementCenterConfig.setEnabled(jHipsterProperties.getCache().getHazelcast().getManagementCenter().isEnabled());
managementCenterConfig.setUrl(jHipsterProperties.getCache().getHazelcast().getManagementCenter().getUrl());
managementCenterConfig.setUpdateInterval(jHipsterProperties.getCache().getHazelcast().getManagementCenter().getUpdateInterval());
return managementCenterConfig;
}

private MapConfig initializeDefaultMapConfig(JHipsterProperties jHipsterProperties) {
MapConfig mapConfig = new MapConfig();

/*
Number of backups. If 1 is set as the backup-count for example,
then all entries of the map will be copied to another JVM for
fail-safety. Valid numbers are 0 (no backup), 1, 2, 3.
*/
mapConfig.setBackupCount(jHipsterProperties.getCache().getHazelcast().getBackupCount());

/*
Valid values are:
NONE (no eviction),
LRU (Least Recently Used),
LFU (Least Frequently Used).
NONE is the default.
*/
mapConfig.setEvictionPolicy(EvictionPolicy.LRU);

/*
Maximum size of the map. When max size is reached,
map is evicted based on the policy defined.
Any integer between 0 and Integer.MAX_VALUE. 0 means
Integer.MAX_VALUE. Default is 0.
*/
mapConfig.setMaxSizeConfig(new MaxSizeConfig(0, MaxSizeConfig.MaxSizePolicy.USED_HEAP_SIZE));

return mapConfig;
}

private MapConfig initializeDomainMapConfig(JHipsterProperties jHipsterProperties) {
MapConfig mapConfig = new MapConfig();
mapConfig.setTimeToLiveSeconds(jHipsterProperties.getCache().getHazelcast().getTimeToLiveSeconds());
return mapConfig;
}
}

使用 cacheNames 的示例存储库...

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

String USERS_BY_LOGIN_CACHE = "usersByLogin";

String USERS_BY_EMAIL_CACHE = "usersByEmail";

String USERS_BY_ID_CACHE = "usersById";

Optional<User> findOneByActivationKey(String activationKey);

List<User> findAllByActivatedIsFalseAndActivationKeyIsNotNullAndCreatedDateBefore(Instant dateTime);

Optional<User> findOneByResetKey(String resetKey);

Optional<User> findOneByEmailIgnoreCase(String email);

Optional<User> findOneByLogin(String login);

@EntityGraph(attributePaths = "roles")
@Cacheable(cacheNames = USERS_BY_ID_CACHE)
Optional<User> findOneWithRolesById(Long id);

@EntityGraph(attributePaths = "roles")
@Cacheable(cacheNames = USERS_BY_LOGIN_CACHE)
Optional<User> findOneWithRolesByLogin(String login);

@EntityGraph(attributePaths = { "roles", "roles.permissions" })
@Cacheable(cacheNames = USERS_BY_LOGIN_CACHE)
Optional<User> findOneWithRolesAndPermissionsByLogin(String login);

@EntityGraph(attributePaths = "roles")
@Cacheable(cacheNames = USERS_BY_EMAIL_CACHE)
Optional<User> findOneWithRolesByEmail(String email);

Page<User> findAllByLoginNot(Pageable pageable, String login);
}

最佳答案

我正在使用每个数据库 (MySQL) 的租户,但只要您在上面设置线程上下文,这就是我正在做的 - 我正在使用 Spring Boot。我创建了一个自定义缓存 key 生成器,它结合了租户名称 + 类 + 和方法。你真的可以选择任何组合。每当我将那个租户传回时,它都会提取正确的条目。在我的 AppointmentType map 类型的 Hazelcast 命令中心,我看到每个租户的条目数增加。

其他一些可能有用的引用资料:

在你想要缓存的类中(我的是服务类):

@Service
public class AppointmentTypeService {

private static final Logger LOGGER = LoggerFactory.getLogger(AppointmentTypeService.class);

private final AppointmentTypeRepository appointmentTypeRepository;

@Autowired
AppointmentTypeService(AppointmentTypeRepository appointmentTypeRepository) {
this.appointmentTypeRepository = appointmentTypeRepository;
}

//ADD keyGenerator value. Name is the name of the bean of the class
@Cacheable(value="appointmentType", keyGenerator = "multiTenantCacheKeyGenerator")
public List<AppointmentType> list() {
return this.appointmentTypeRepository.findAll();
}

@CacheEvict(value="appointmentType", allEntries=true)
public Long create(AppointmentType request) {
this.appointmentTypeRepository.saveAndFlush(request);
return request.getAppointmentTypeId();
}

@CacheEvict(value="appointmentType", allEntries=true)
public void delete(Long id) {
this.appointmentTypeRepository.deleteById(id);
}

public Optional<AppointmentType> findById(Long id) {
return this.appointmentTypeRepository.findById(id);
}

}

创建 key 生成器类

//setting the bean name here
@Component("multiTenantCacheKeyGenerator")
public class MultiTenantCacheKeyGenerator implements KeyGenerator {

@Override
public Object generate(Object o, Method method, Object... os) {
StringBuilder sb = new StringBuilder();
sb.append(TenantContext.getCurrentTenantInstanceName()) //my tenant context class which is using local thread. I set the value in the Spring filter.
.append("_")
.append(o.getClass().getSimpleName())
.append("-")
.append(method.getName());
}

return sb.toString();
}

}

关于java - 为 Multi-Tenancy 设置 Hazelcast 缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61295458/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com