Ehcache 集群改造-----增加手动发现方式自动增加减机器机制

上一篇文章说了ehcache基于RMI手动发现集群的搭建 https://blog.csdn.net/java_ying/article/details/103071571
但是手动发现有很多限制,比如不能动态增加机器,使用中有很多不方便
所以就根据ehcache的机制 加了一个轮询功能 类似心跳机制 去检查当前生效的链接

放代码前,先说一下思路:
ehcache 手动发现机制,在项目启动时 会读取xml配置文件的值,然后放到一个map里面。如下
在这里插入图片描述
操作是这个类操作的
在这里插入图片描述
就是简单的map操作而已
map里面 的键就是url 类似 //127.0.0.1:40009/articleCache 这样,值是一个date 我们暂时不用关心

RMICacheManagerPeerProvider 这个类提供了两个方法,分别是注册和反注册

/**
     * Register a new peer
     *
     * @param rmiUrl
     */
    public abstract void registerPeer(String rmiUrl);

    /**
     * Unregisters a peer
     *
     * @param rmiUrl
     */
    public final synchronized void unregisterPeer(String rmiUrl) {
        peerUrls.remove(rmiUrl);
    }

我们就可以利用这两个方法来操作它
上文提到过 每次同步内容的时候 他都会遍历这个map 然后如果发送消息不成功会很浪费时间
我们就做一个监测功能,当我们配置文件的值不生效的时候 就unregisterPeer,如果生效了就registerPeer

这个provider 可以从CacheManager中拿到。放代码

package com.hqjl.communityserv.thread;

import com.hqjl.communityserv.bean.vo.SocketParam;
import com.hqjl.communityserv.cache.EhcacheManager;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.distribution.CacheManagerPeerProvider;
import net.sf.ehcache.distribution.RMICacheManagerPeerProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import java.net.Socket;
import java.util.*;

/**
 * @author chunying
 * @Date: 2019/11/14 0014
 */
@Configuration
@PropertySource(value= {"classpath:eh.properties"}, encoding = "utf-8")
public class RMIUrlsThread{

    @Value("${rmiurls}")
    private String rmiurls;

    private static final Map<Integer, String> urls = new HashMap<>();
    private static final Map<Integer, SocketParam> paramMap = new HashMap<>();
    private static final String RMI_URLS = "rmiUrls";
    private static Boolean flag = false;

    public void loadProps() {
        int key = 0;
        String[] split = rmiurls.split("\\|");
        //这里面根据url 取出IP 和port用于测试连接是否可用
        for (String s : split) {
            urls.put(key, s);
            String substring = s.substring(2);
            String[] splitS1 = substring.split("\\:");
            String IP = splitS1[0];
            String s2 = splitS1[1];
            String[] s2Split = s2.split("\\/");
            String port = s2Split[0];
            SocketParam socketParam = new SocketParam(IP, Integer.parseInt(port));
            paramMap.put(key, socketParam);
            key++;
        }

    }

    public void thread() {
        new Thread(){
            @Override
           public void run() {
               loadProps();
               //这里面获取CacheManager 很简单 我没有放这个类。 不会的话看我前一篇文章
               CacheManager cacheManager = EhcacheManager.getCacheManager();
               Map<String, CacheManagerPeerProvider> cacheManagerPeerProviders = cacheManager.getCacheManagerPeerProviders();
               cacheManagerPeerProviders.forEach((k,v)-> {
                   RMICacheManagerPeerProvider provider = (RMICacheManagerPeerProvider)v;
                   while(true) {
                       urls.forEach((key, url)-> {
                           SocketParam socketParam = paramMap.get(key);
                           Socket socket = null;
                           String IP = socketParam.getIp();
                           Integer port = socketParam.getPort();
                           try {
                               //测试连接是否可用
                               socket = new Socket(IP, port);
                               socket.close();
                               provider.registerPeer(url);
                           }catch(Exception e) {
                               provider.unregisterPeer(url);
                           }
                       });
                       System.out.println("执行一次");
                       try {
                           Thread.sleep(10000);
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }

               });
           }
        }.start();

    }

    public static void main(String[] args) {

    }
}


package com.hqjl.communityserv.bean.vo;

/**
 * @author chunying
 * @Date: 2019/11/15 0015
 */
public class SocketParam {

    private String ip;
    private Integer port;

    public SocketParam(){}

    public SocketParam(String ip, Integer port) {
        this.ip = ip;
        this.port = port;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public Integer getPort() {
        return port;
    }

    public void setPort(Integer port) {
        this.port = port;
    }
}

eh.properties中的值就是我copy了一份 xml中rmiurl的值 比较懒 不想解析xml。。。
这个方法会在项目启动完成后立刻执行,首先把properties中值读出来,放进我们准备好的map,
然后还有一个map 是初次加载时 解析出地址中的IP 和 port ,因为String 的相关操作还是有点耗时的,最好一次操作,一直使用。两个map的key是相同的 用的时候用key做关联。

thread方法,新建了一个不死的线程,里面先通过EhcacheManager 取出 RMICacheManagerPeerProvider
while(true) 保证一直运行,测试连接是否可用 使用java.net的socket 如果通了 说明 连接的机器在运行,那么就注册
如果没通,说明挂了或者没启动,直接反注册。 切记 记得close();
Sleep()方法 是心跳间隔时间,自由发挥即可。

好了 这是一个不完整的博客,这样操作虽然可以实现想要的功能,但是会有一个问题:
我们看这个Map 注意是个SynchronizedMap 这个东西是带操作锁的,一个只有一个线程可以操作他,如果在遍历时有更新操作,那么他会报错的。所以要处理这个问题,还要继续跟踪ehcache的同步机制,是怎么处理异常的。
后续会继续更新~

------------------------------------------------------------------分割线-------------------------------------------------------------------------------------
后续:准备把ehcache源码搞下来,把遍历过程和读写过程加读写锁。最近莫得时间,有时间更改后上代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值