集群机器循环调用实现,基于SpringBoot

以下的内容纯属理论探讨,除非万不得已最好不要这么干,因为会造成集群的有状态化和维护困难。

假设一个集群中有三台tomcat,在发生某件事情(比如接口调用)的时候我需要首先在本机做某件事情,如果做不了,就调用下一台机器,如此往复,直到最后一台。

我们可以将tomcat定义成为一个环,每台保存自己的标识和下一台的标识,调用的时候带上已经经过的节点,如果下一个节点已经在已经经过的节点中,说明就是最后一台了,不能再往下调用。

/**
 * @author xiongshiyan at 2018/10/24 , contact me with email yanshixiong@126.com or phone 15208384257
 */
public interface NodeNext {
    /**
     * 往下执行
     * @param payload 需要发送的内容
     * @param crossNodes 已经经过的node
     */
    String next(String payload , Set<String> crossNodes) throws IOException;
}
/**
 * @author xiongshiyan at 2018/10/24 , contact me with email yanshixiong@126.com or phone 15208384257
 */
@Component
public class DefaultNodeNext implements NodeNext {
    @Autowired
    private SmartHttpClient smartHttpClient;
    @Autowired
    private Node node;

    @Override
    public String next(String payload , Set<String> crossNodes) throws IOException{
        //如果所有经过的节点包含本节点的下个节点,那么就不干什么
        if(crossNodes.contains(node.getNextName())){
            return "";
        }

        if(null == node.getName()){
            return "";
        }


        Request request = Request.of(node.getUrl());
        Map<String , Object> map = new HashMap<>(2);
        map.put(Node.PAYLOAD, payload);

        crossNodes.add(node.getName());
        //添加本地的名字
        map.put(Node.CROSS_NODES , crossNodes);
        request.setBody(JsonUtil.serializeMap(map));

        return smartHttpClient.post(request).getBody();
    }
}
/**
 * 一个tomcat节点,实现环形调用的数据结构,一个节点保存本节点名和下一个节点名,调用的时候带上已经经过的节点,这样就能知道何时结束
 * @author xiongshiyan at 2018/10/24 , contact me with email yanshixiong@126.com or phone 15208384257
 */
@ConfigurationProperties(prefix = "spring.circle.send")
@PropertySource(value = "file:/mnt/install/tomcat/circle.properties" , ignoreResourceNotFound = true)
@Component
public class Node {
    public static final String PAYLOAD = "payload";
    public static final String CROSS_NODES = "crossNodes";

    private String name;
    private String nextName;
    private String url;

    ...
}

主要的逻辑都在DefaultNextNode中,实现了判断是否应该结束和添加本地节点。Node代表一个节点,有自己的标识名字,下一个节点的标识名字,和访问的URL。为了做到每个tomcat中代码的不修改,这个配置需要放到每个机器的相同位置。

spring.circle.send.name=node1
spring.circle.send.nextName=node2
spring.circle.send.url=http://xxxxxxxx1:8080/api/circle/receive

 

spring.circle.send.name=node2
spring.circle.send.nextName=node3
spring.circle.send.url=http://xxxxxxxx2:8080/api/circle/receive

 

spring.circle.send.name=node3
spring.circle.send.nextName=node1
spring.circle.send.url=http://xxxxxxxx3:8080/api/circle/receive

 

需要在每个tomca中添加一个controller来接收上一台的请求,并作出处理和判断。

@Autowired
    private NodeNext nodeNext;
    @Autowired
    private NodeCurrent nodeCurrent;

    @PostMapping(value = "/receive")
    public String receive(@RequestBody String json) throws Exception{
        boolean jsonObject = JsonUtil.isJsonObject(json);
        if(!jsonObject){
            return null;
        }

        JSONObject object = new JSONObject(json);
        String payload = object.getString(Node.PAYLOAD);

        boolean canDo = nodeCurrent.doWithPayLoad(payload);
        if(canDo){
            return "";
        }


        JsonArray crossNodes = object.getJsonArray(Node.CROSS_NODES);

        int size = crossNodes.size();
        Set<String> nodes = new HashSet<>(size);
        for (int i = 0; i < size; i++) {
            nodes.add(crossNodes.getString(i));
        }
        return nodeNext.next(payload , nodes);

    }

本地处理的方法接口为NodeCurrent,需要返回是否能处理的标识。

public interface NodeCurrent {
    /**
     * 当前节点需要做的事情
     * @param payload 接收到的数据
     * @return 当前是否能做
     */
    boolean doWithPayLoad(String payload);
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值