探讨Hazelcast分布式map的驱逐策略实现

本文探讨了在营销系统中使用Hazelcast作为前置缓存的场景,由于分布式map(multiMap)不支持驱逐策略,转向使用imap并尝试通过监听器实现驱逐。然而,实践中发现Hazelcast无法注入到监听器中,尝试通过配置文件声明bean也未成功。最终,提出了使用单例模式来解决这一问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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方法被调用的时候手动注册监听,为了避免多次注入我们首先加一个标识,这样程序运行期间保证只注入一次。经测试这种方法是可行的,就是有点绕,代码过于恶心就不贴了,还是希望官方能给予一个良好的支持。如果大家有什么好的思路欢迎交流。
                                                                                                                                                                                                                     ——我只是个敲代码的不要黑我


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值