如何强制JGroups哪个节点创建协调器?

时间:2012-05-31 22:24:05

标签: java cluster-computing jgroups

我正在寻找一种强制JGroups使用特定服务器作为协调器的方法,如果该服务器不存在,请选择一个新的协调器,直到指定的协调器重新加入群集并接管为协调器。

在这种情况下,我们会通过协调员听取主题进行更新来推送到集群的一些信息,但是取出&处理这些更新可能是资源密集型的,因此我们不希望它向外界提供任何服务。因此,在集群前面的负载均衡器中,我们将其设置为不发送给协调器。但由于协调器是随机选出的,我们基本上需要关闭群集,直到只有一台机器在那里,然后重新启动群集的其余部分。

3 个答案:

答案 0 :(得分:5)

目前无法做到这一点。 Jgroups花了相当多的时间确保协调器可以是组中的任何节点。维护和监视组成员列表健康状况的所有任务在组中的所有成员之间共享,以确保协调员职责不会过多地影响协调员的性能。标准GMS(Group MembershipService)协议栈类负责协调器选择。目前它只是视图列表中的第一个主机。

要获得此行为,您将不得不实现自己的协议堆栈。有趣的是,我一直在为Jgroups开发一个协议栈,它实现了你所要求的,但它还没有为黄金时间做好准备。

然而,其他人可能会对这个问题感到不满。我建议在jgroups mailing list上发帖并提出同样的问题。

答案 1 :(得分:1)

只是偶然发现了这篇文章。在JGroups中有一种简单而标准的方法可以做到这一点:[1]。从本质上讲,我们让用户代码控制视图的生成。

[1] http://www.jgroups.org/manual4/index.html#MembershipChangePolicy

答案 2 :(得分:0)

您可以将所需节点设置为协调器。 : github sample

我在所有节点和完整代码中添加完成更改的同步块:

public static final String GMS_DELTA_VIEW_FIELD_NAME = "use_delta_views";

/**
 * Change coordinator to {@code desiredCoordinator}. Must be invoked from coordinator.
 * @param desiredCoordinator
 * @return {@code true} if changes success, {@code false} overwise 
 */
boolean changeCoordinator(JChannel currentChannel, Address desiredCoordinator) {

    if(!Util.isCoordinator(currentChannel.getAddress)) {
        throw new RuntimeException("The current node is not coordinator.");
    }

    ArrayList<Address> newMembersOrder = Lists.newArrayList(currentView.getMembers());        

    // Switch desired node to first place
    Collections.swap(newMembersOrder, 0, newMembersOrder.indexOf(desiredCoordinator));        

    // Create new view
    long newId = currentView.getViewId().getId() + 1;
    View newView = new View(newMembersOrder.get(0), newId, newMembersOrder);

    GMS gms = (GMS)clusterChannel.getProtocolStack().findProtocol(GMS.class);
    CustomProtocol protocol = new CustomProtocol(newMembersOrder.stream()
            .filter(item -> !item.equals(currentChannel.getAddress()))
            .collect(Collectors.toSet()));

    boolean oldUseDeltaViews = (Boolean)gms.getValue(GMS_DELTA_VIEW_FIELD_NAME);
    try {
        // Disable using_delta_views at GMS
        gms.setValue(GMS_DELTA_VIEW_FIELD_NAME, false);

        // Insert custom protocol below GMS for synchronizing with VIEW_ACK events
        currentChannel.getProtocolStack().insertProtocolInStack(protocol, gms, ProtocolStack.BELOW);
        gms.castViewChange(newView, null, newMembersOrder);

        // Wait no more than 30 seconds to all VIEW_ACK responses
        if (!protocol.collector.waitForAllAcks(TimeUnit.SECONDS.toMillis(30))) {                
            return false;
        }

        return true;
    }
    finally {
        // Repair old state
        gms.setValue(GMS_DELTA_VIEW_FIELD_NAME, oldUseDeltaViews);
        currentChannel.getProtocolStack().removeProtocol(protocol);
    }
}

private class CustomProtocol extends Protocol implements UpHandler {

    AckCollector collector;

    public CustomProtocol(Collection<Address> waitedAddresses) {
        collector = new AckCollector(waitedAddresses);
    }

    @Override
    public Object up(Event evt) {

        if(evt.getType() == Event.MSG) {
            final Message msg=(Message)evt.getArg();
            GmsHeader hdr=(GmsHeader)msg.getHeader(proto_id);
            if(hdr != null && hdr.getType() == GmsHeader.VIEW_ACK) {                    
                collector.ack(msg.getSrc());
            }
        }

        return super.up(evt);
    }
}