1、背景介绍
营销系统会承接来自收银台的活动查询的请求,理论上是一个1+的请求,通常这是指数级的增加。考虑使用hz做一个前置的缓存,使用请求参数的hash值为key(这里不讨论hash碰撞,事实上这对于业务是没有影响的),考虑到是集群分布所以分布式map是第一选择,无奈的是目前官方对于multiMap的驱逐策略实现是不支持的。
2、解题思路
虽然分布式map不支持驱逐但是imap是支持驱逐的,能不能借助监听器实现共生呢?
第一步先做一个工具类封装put方法,在方法内把值备份到分布式map
@Component("hazelcastHelper")
public class HazelcastHelper {
@Resource(name = "crabMap")
private IMap<Object, Object> hzMap;
@Autowired
private MultiMap<Object, Object> hzMultiMap;
@Value("${multimap_expired_time}")
private int EXPIRED_TIME;
public IMap<Object, Object> getHzMap() {
return hzMap;
}
public MultiMap<Object, Object> getHzMultiMap() {
return hzMultiMap;
}
public HazelcastHelper instance(){
return this;
}
public void put(String key,Object obj){
hzMap.put(key,obj,EXPIRED_TIME, TimeUnit.SECONDS);
hzMultiMap.put(key,obj);
}
第二步 实现一个监听
public class IMapExpiredListener implements EntryAddedListener<String, Object>,
EntryExpiredListener<String,Object>,
EntryRemovedListener<String, Object>, EntryUpdatedListener<String, Object> {
@Autowired
HazelcastHelper hazelcastHelper;
@Override
public void entryAdded(EntryEvent<String, Object> event) {
System.out.println("entryAdded: " + event);
}
@Override
public void entryRemoved(EntryEvent<String, Object> event) {
System.out.println("entryRemoved: " + event);
}
@Override
public void entryUpdated(EntryEvent<String, Object> event) {
System.out.println("entryUpdated: " + event);
}
@Override
public void entryExpired(EntryEvent<String, Object> entryEvent) {
System.out.println("entryExpired: " + entryEvent);
hazelcastHelper.getHzMultiMap().remove(entryEvent.getKey());
第三步 配置监听
<hz:map name="crabMap">
<hz:near-cache time-to-live-seconds="3"/>
<!--<hz:near-cache max-idle-seconds="${multimap_expired_time}"/>-->
<hz:near-cache max-idle-seconds="${multimap_expired_time}"/>
<!--<hz:near-cache time-to-live-seconds="3"/>-->
<hz:entry-listeners>
<hz:entry-listener include-value="false" local="false" class-name="com.wangyin.seapay.crab.biz.rulengine.utils.IMapExpiredListener"/>
<!--<hz:entry-listener implementation="dummyEntryListener" local="true"/>-->
</hz:entry-listeners>
</hz:map>理论上我们可以实现这种共生的关系,但是实际的测试中我们发现hz是无法注入到监听里面的,原因是在实例化监听器的时候hz并没有完成实例化,那么我们在配置文件中先声明bean怎么样呢,经测试还是不行。那么我们就索性做一个单例:
public class HazelcastUtil extends ApplicationObjectSupport{
public TriggerRuleJudger triggerRuleJudger;
public LimitRulerJudger limitRulerJudger;
public RewardRuleJudger rewardRuleJudger;
public ProCalculusService proCalculusService;
public HazelcastHelper hazelcastHelper;
private volatile static HazelcastUtil instance;
private HazelcastUtil (){}
public static HazelcastUtil getInstance() {
if (instance == null) {
synchronized (HazelcastUtil.class) {
if (instance == null) {
instance = new HazelcastUtil();
}
}
}
return instance;
}
}
事实证明也是不起作用的,貌似就无解了这个东西,我们怎么才能在hz实例化之后再注册监听呢?我们将监听类作为内部类写到工具类里面,在put方法被调用的时候手动注册监听,为了避免多次注入我们首先加一个标识,这样程序运行期间保证只注入一次。经测试这种方法是可行的,就是有点绕,代码过于恶心就不贴了,还是希望官方能给予一个良好的支持。如果大家有什么好的思路欢迎交流。
——我只是个敲代码的不要黑我
本文探讨了在营销系统中使用Hazelcast作为前置缓存的场景,由于分布式map(multiMap)不支持驱逐策略,转向使用imap并尝试通过监听器实现驱逐。然而,实践中发现Hazelcast无法注入到监听器中,尝试通过配置文件声明bean也未成功。最终,提出了使用单例模式来解决这一问题。
2585

被折叠的 条评论
为什么被折叠?



