apache / incubator-hugegraph

A graph database that supports more than 100+ billion data, high performance and scalability (Include OLTP Engine & REST-API & Backends)
https://hugegraph.apache.org
Apache License 2.0
2.63k stars 517 forks source link

[Question] How to disable legacy master-worker mechanism in multi-server #2667

Open shirleyStorage opened 1 day ago

shirleyStorage commented 1 day ago

Problem Type (问题类型)

struct / logic (架构 / 逻辑设计问题)

Before submit

Environment (环境信息)

Your Question (问题描述)

How to disable legacy master-worker mechanism in multi-server

Vertex/Edge example (问题点 / 边数据举例)

No response

Schema [VertexLabel, EdgeLabel, IndexLabel] (元数据结构)

No response

dosubot[bot] commented 1 day ago

To disable the legacy master-worker mechanism in a multi-server setup using Apache HugeGraph, you need to set the server.role configuration option to "computer". This can be done in your configuration file as follows:

server.role=computer

This setting ensures that the RoleElectionStateMachine is not initialized, effectively disabling the legacy master-worker mechanism. Here is the relevant configuration option:

public static final ConfigOption<String> SERVER_ROLE =
        new ConfigOption<>(
                "server.role",
                "The role of nodes in the cluster, available types are " +
                "[master, worker, computer]",
                allowValues("master", "worker", "computer"),
                "master"
        );

By setting server.role to "computer", the supportRoleElection will be false, and the role state machine will not be initialized [1][2].

To continue talking to Dosu, mention @dosu.

imbajin commented 1 day ago

To disable the legacy master-worker mechanism in a multi-server setup using Apache HugeGraph, you need to set the server.role configuration option to "computer". This can be done in your configuration file as follows:

server.role=computer

This setting ensures that the RoleElectionStateMachine is not initialized, effectively disabling the legacy master-worker mechanism. Here is the relevant configuration option:

public static final ConfigOption<String> SERVER_ROLE =
        new ConfigOption<>(
                "server.role",
                "The role of nodes in the cluster, available types are " +
                "[master, worker, computer]",
                allowValues("master", "worker", "computer"),
                "master"
        );

By setting server.role to "computer", the supportRoleElection will be false, and the role state machine will not be initialized [1][2].

To continue talking to Dosu, mention @dosu.

@dosu Thanks for the direct solution, could u also provide more details about the legacy master-worker role code design & usage (As detailed and systematic as possible)?

dosubot[bot] commented 1 day ago

The legacy master-worker role code design in Apache HugeGraph is implemented using an enumeration called NodeRole. This enum defines three roles: MASTER, WORKER, and COMPUTER. Each role is associated with a unique byte code and a name. The NodeRole enum also includes methods to check the role type and retrieve the role's code and name.

Here is the relevant code:

public enum NodeRole implements SerialEnum {

    MASTER(1, "master"),

    WORKER(2, "worker"),

    COMPUTER(3, "computer");

    private final byte code;
    private final String name;

    NodeRole(int code, String name) {
        assert code < 256;
        this.code = (byte) code;
        this.name = name;
    }

    static {
        SerialEnum.register(NodeRole.class);
    }

    @Override
    public byte code() {
        return this.code;
    }

    public String string() {
        return this.name;
    }

    public boolean master() {
        return this == MASTER;
    }

    public boolean worker() {
        return this == WORKER;
    }

    public boolean computer() {
        return this == COMPUTER;
    }
}

Additionally, the RoleListener interface in the org.apache.hugegraph.masterelection package defines methods for handling role changes and errors within the system. This interface includes methods such as onAsRoleMaster, onAsRoleWorker, onAsRoleCandidate, unknown, onAsRoleAbdication, and error, each taking a StateMachineContext parameter to manage the state transitions and handle errors.

Here is the relevant code for the RoleListener interface:

package org.apache.hugegraph.masterelection;

public interface RoleListener {

    void onAsRoleMaster(StateMachineContext context);

    void onAsRoleWorker(StateMachineContext context);

    void onAsRoleCandidate(StateMachineContext context);

    void unknown(StateMachineContext context);

    void onAsRoleAbdication(StateMachineContext context);

    void error(StateMachineContext context, Throwable e);
}

The RoleElectionStateMachineTest class provides a test implementation for the role election state machine, demonstrating how roles transition and how the system logs these transitions. The LogEntry class within this test captures the epoch, node, and role for each state change, and the TestConfig class provides configuration details for the state machine.

Here is an excerpt from the RoleElectionStateMachineTest class:

public class RoleElectionStateMachineTest {

    private static class LogEntry {

        private final Integer epoch;
        private final String node;
        private final Role role;

        enum Role {
            master,
            worker,
            candidate,
            abdication,
            unknown
        }

        public LogEntry(Integer epoch, String node, Role role) {
            this.epoch = epoch;
            this.node = node;
            this.role = role;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (!(obj instanceof LogEntry)) {
                return false;
            }
            LogEntry logEntry = (LogEntry) obj;
            return Objects.equals(this.epoch, logEntry.epoch) &&
                   Objects.equals(this.node, logEntry.node) &&
                   this.role == logEntry.role;
        }

        @Override
        public int hashCode() {
            return Objects.hash(this.epoch, this.node, this.role);
        }

        @Override
        public String toString() {
            return "LogEntry{" +
                   "epoch=" + this.epoch +
                   ", node='" + this.node + '\'' +
                   ", role=" + this.role +
                   '}';
        }
    }

    private static class TestConfig implements Config {

        private final String node;

        public TestConfig(String node) {
            this.node = node;
        }

        @Override
        public String node() {
            return this.node;
        }

        @Override
        public String url() {
            return "http://127.0.0.1:8080";
        }

        @Override
        public int exceedsFailCount() {
            return 2;
        }

        @Override
        public long randomTimeoutMillisecond() {
            return 400;
        }

        @Override
        public long heartBeatIntervalSecond() {
            return 1;
        }

        @Override
        public int masterDeadTimes() {
            return 5;
        }

        @Override
        public long baseTimeoutMillisecond() {
            return 100;
        }
    }

    @Test
    public void testStateMachine() throws InterruptedException {
        final int MAX_COUNT = 200;
        CountDownLatch stop = new CountDownLatch(4);
        List<LogEntry> logRecords = Collections.synchronizedList(new ArrayList<>(MAX_COUNT));
        List<String> masterNodes = Collections.synchronizedList(new ArrayList<>(MAX_COUNT));
        RoleListener callback = new RoleListener() {

            @Override
            public void onAsRoleMaster(StateMachineContext context) {
                Integer epochId = context.epoch();
                String node = context.node();
                logRecords.add(new LogEntry(epochId, node, LogEntry.Role.master));
                if (logRecords.size() > MAX_COUNT) {
                    context.stateMachine().shutdown();
                }
                Utils.println("master node: " + node);
                masterNodes.add(node);
            }

            @Override
            public void onAsRoleWorker(StateMachineContext context) {
                Integer epochId = context.epoch();
                String node = context.node();
                logRecords.add(new LogEntry(epochId, node, LogEntry.Role.worker));
                if (logRecords.size() > MAX_COUNT) {
                    context.stateMachine().shutdown();
                }
            }

            @Override
            public void onAsRoleCandidate(StateMachineContext context) {
                Integer epochId = context.epoch();
                String node = context.node();
                logRecords.add(new LogEntry(epochId, node, LogEntry.Role.candidate));
                if (logRecords.size() > MAX_COUNT) {
                    context.stateMachine().shutdown();
                }
            }
        };
    }
}

This design allows for easy role identification, role-specific logic implementation, and handling of role transitions and errors within the HugeGraph system [1][2][3].

To continue talking to Dosu, mention @dosu.