Search in sources :

Example 6 with Member

use of io.atomix.cluster.Member in project atomix by atomix.

the class HashBasedPrimaryElection method recomputeTerm.

/**
 * Recomputes the current term.
 */
private synchronized void recomputeTerm(PartitionGroupMembership membership) {
    if (membership == null) {
        return;
    }
    // Create a list of candidates based on the availability of members in the group.
    List<GroupMember> candidates = new ArrayList<>();
    for (MemberId memberId : membership.members()) {
        Member member = clusterMembershipService.getMember(memberId);
        if (member != null && member.isReachable()) {
            candidates.add(new GroupMember(memberId, MemberGroupId.from(memberId.id())));
        }
    }
    // Sort the candidates by a hash of their member ID.
    candidates.sort((a, b) -> {
        int aoffset = Hashing.murmur3_32().hashString(a.memberId().id(), StandardCharsets.UTF_8).asInt() % partitionId.id();
        int boffset = Hashing.murmur3_32().hashString(b.memberId().id(), StandardCharsets.UTF_8).asInt() % partitionId.id();
        return aoffset - boffset;
    });
    // Store the current term in a local variable avoid repeated volatile reads.
    PrimaryTerm currentTerm = this.currentTerm;
    // Compute the primary from the sorted candidates list.
    GroupMember primary = candidates.isEmpty() ? null : candidates.get(0);
    // Remove the primary from the candidates list.
    candidates = candidates.isEmpty() ? Collections.emptyList() : candidates.subList(1, candidates.size());
    // If the primary has changed, increment the term. Otherwise, use the current term from the replicated counter.
    long term = currentTerm != null && Objects.equals(currentTerm.primary(), primary) && Objects.equals(currentTerm.candidates(), candidates) ? currentTerm() : incrementTerm();
    // Create the new primary term. If the term has changed update the term and trigger an event.
    PrimaryTerm newTerm = new PrimaryTerm(term, primary, candidates);
    if (!Objects.equals(currentTerm, newTerm)) {
        this.currentTerm = newTerm;
        LOGGER.debug("{} - Recomputed term for partition {}: {}", clusterMembershipService.getLocalMember().id(), partitionId, newTerm);
        post(new PrimaryElectionEvent(PrimaryElectionEvent.Type.CHANGED, partitionId, newTerm));
        broadcastCounters();
    }
}
Also used : GroupMember(io.atomix.primitive.partition.GroupMember) MemberId(io.atomix.cluster.MemberId) PrimaryElectionEvent(io.atomix.primitive.partition.PrimaryElectionEvent) ArrayList(java.util.ArrayList) GroupMember(io.atomix.primitive.partition.GroupMember) Member(io.atomix.cluster.Member) PrimaryTerm(io.atomix.primitive.partition.PrimaryTerm)

Example 7 with Member

use of io.atomix.cluster.Member in project atomix by atomix.

the class SwimProtocolTest method testSwimProtocol.

@Test
public void testSwimProtocol() throws Exception {
    // Start a node and check its events.
    startProtocol(member1);
    checkEvent(member1, MEMBER_ADDED, member1);
    checkMembers(member1, member1);
    // Start a node and check its events.
    startProtocol(member2);
    checkEvent(member2, MEMBER_ADDED, member2);
    checkEvent(member2, MEMBER_ADDED, member1);
    checkMembers(member2, member1, member2);
    checkEvent(member1, MEMBER_ADDED, member2);
    checkMembers(member1, member1, member2);
    // Start a node and check its events.
    startProtocol(member3);
    checkEvent(member3, MEMBER_ADDED, member3);
    checkEvent(member3, MEMBER_ADDED);
    checkEvent(member3, MEMBER_ADDED);
    checkMembers(member3, member1, member2, member3);
    checkEvent(member2, MEMBER_ADDED, member3);
    checkMembers(member2, member1, member2, member3);
    checkEvent(member1, MEMBER_ADDED, member3);
    checkMembers(member1, member1, member2, member3);
    // Isolate node 3 from the rest of the cluster.
    partition(member3);
    // Nodes 1 and 2 should see REACHABILITY_CHANGED events and then MEMBER_REMOVED events.
    checkEvent(member1, REACHABILITY_CHANGED, member3);
    checkEvent(member2, REACHABILITY_CHANGED, member3);
    checkEvent(member1, MEMBER_REMOVED, member3);
    checkEvent(member2, MEMBER_REMOVED, member3);
    // Verify that node 3 was removed from nodes 1 and 2.
    checkMembers(member1, member1, member2);
    checkMembers(member2, member1, member2);
    // Node 3 should also see REACHABILITY_CHANGED and MEMBER_REMOVED events for nodes 1 and 2.
    checkEvents(member3, new GroupMembershipEvent(REACHABILITY_CHANGED, member1), new GroupMembershipEvent(REACHABILITY_CHANGED, member2), new GroupMembershipEvent(MEMBER_REMOVED, member1), new GroupMembershipEvent(MEMBER_REMOVED, member2));
    // Verify that nodes 1 and 2 were removed from node 3.
    checkMembers(member3, member3);
    // Heal the partition.
    heal(member3);
    // Verify that the nodes discovery each other again.
    checkEvent(member1, MEMBER_ADDED, member3);
    checkEvent(member2, MEMBER_ADDED, member3);
    checkEvents(member3, new GroupMembershipEvent(MEMBER_ADDED, member1), new GroupMembershipEvent(MEMBER_ADDED, member2));
    // Partition node 1 from node 2.
    partition(member1, member2);
    // Verify that neither node is ever removed from the cluster since node 3 can still ping nodes 1 and 2.
    Thread.sleep(5000);
    checkMembers(member1, member1, member2, member3);
    checkMembers(member2, member1, member2, member3);
    checkMembers(member3, member1, member2, member3);
    // Heal the partition.
    heal(member1, member2);
    // Update node 1's metadata.
    member1.properties().put("foo", "bar");
    // Verify the metadata change is propagated throughout the cluster.
    checkEvent(member1, METADATA_CHANGED, member1);
    checkEvent(member2, METADATA_CHANGED, member1);
    checkEvent(member3, METADATA_CHANGED, member1);
    // Stop member 3 and change its version.
    stopProtocol(member3);
    Member member = member(member3.id().id(), member3.address().host(), member3.address().port(), version2);
    startProtocol(member);
    // Verify that version 1 is removed and version 2 is added.
    checkEvent(member1, MEMBER_REMOVED, member3);
    checkEvent(member1, MEMBER_ADDED, member);
    checkEvent(member2, MEMBER_REMOVED, member3);
    checkEvent(member2, MEMBER_ADDED, member);
}
Also used : Member(io.atomix.cluster.Member) Test(org.junit.Test)

Example 8 with Member

use of io.atomix.cluster.Member in project atomix by atomix.

the class DefaultClusterEventServiceTest method testClusterEventService.

@Test
public void testClusterEventService() throws Exception {
    TestMessagingServiceFactory messagingServiceFactory = new TestMessagingServiceFactory();
    TestUnicastServiceFactory unicastServiceFactory = new TestUnicastServiceFactory();
    TestBroadcastServiceFactory broadcastServiceFactory = new TestBroadcastServiceFactory();
    Collection<Node> bootstrapLocations = buildBootstrapNodes(3);
    Member localMember1 = buildNode(1);
    MessagingService messagingService1 = messagingServiceFactory.newMessagingService(localMember1.address()).start().join();
    BootstrapService bootstrapService1 = new TestBootstrapService(messagingService1, unicastServiceFactory.newUnicastService(localMember1.address()).start().join(), broadcastServiceFactory.newBroadcastService().start().join());
    ManagedClusterMembershipService clusterService1 = new DefaultClusterMembershipService(localMember1, Version.from("1.0.0"), new DefaultNodeDiscoveryService(bootstrapService1, localMember1, new BootstrapDiscoveryProvider(bootstrapLocations)), bootstrapService1, new HeartbeatMembershipProtocol(new HeartbeatMembershipProtocolConfig()));
    ClusterMembershipService clusterMembershipService1 = clusterService1.start().join();
    ManagedClusterEventService clusterEventingService1 = new DefaultClusterEventService(clusterMembershipService1, messagingService1);
    ClusterEventService eventService1 = clusterEventingService1.start().join();
    Member localMember2 = buildNode(2);
    MessagingService messagingService2 = messagingServiceFactory.newMessagingService(localMember2.address()).start().join();
    BootstrapService bootstrapService2 = new TestBootstrapService(messagingService2, unicastServiceFactory.newUnicastService(localMember2.address()).start().join(), broadcastServiceFactory.newBroadcastService().start().join());
    ManagedClusterMembershipService clusterService2 = new DefaultClusterMembershipService(localMember2, Version.from("1.0.0"), new DefaultNodeDiscoveryService(bootstrapService2, localMember2, new BootstrapDiscoveryProvider(bootstrapLocations)), bootstrapService2, new HeartbeatMembershipProtocol(new HeartbeatMembershipProtocolConfig()));
    ClusterMembershipService clusterMembershipService2 = clusterService2.start().join();
    ManagedClusterEventService clusterEventingService2 = new DefaultClusterEventService(clusterMembershipService2, messagingService2);
    ClusterEventService eventService2 = clusterEventingService2.start().join();
    Member localMember3 = buildNode(3);
    MessagingService messagingService3 = messagingServiceFactory.newMessagingService(localMember3.address()).start().join();
    BootstrapService bootstrapService3 = new TestBootstrapService(messagingService3, unicastServiceFactory.newUnicastService(localMember1.address()).start().join(), broadcastServiceFactory.newBroadcastService().start().join());
    ManagedClusterMembershipService clusterService3 = new DefaultClusterMembershipService(localMember3, Version.from("1.0.0"), new DefaultNodeDiscoveryService(bootstrapService3, localMember3, new BootstrapDiscoveryProvider(bootstrapLocations)), bootstrapService3, new HeartbeatMembershipProtocol(new HeartbeatMembershipProtocolConfig()));
    ClusterMembershipService clusterMembershipService3 = clusterService3.start().join();
    ManagedClusterEventService clusterEventingService3 = new DefaultClusterEventService(clusterMembershipService3, messagingService3);
    ClusterEventService eventService3 = clusterEventingService3.start().join();
    Thread.sleep(100);
    Set<Integer> events = new CopyOnWriteArraySet<>();
    eventService1.<String>subscribe("test1", SERIALIZER::decode, message -> {
        assertEquals("Hello world!", message);
        events.add(1);
    }, MoreExecutors.directExecutor()).join();
    eventService2.<String>subscribe("test1", SERIALIZER::decode, message -> {
        assertEquals("Hello world!", message);
        events.add(2);
    }, MoreExecutors.directExecutor()).join();
    eventService2.<String>subscribe("test1", SERIALIZER::decode, message -> {
        assertEquals("Hello world!", message);
        events.add(3);
    }, MoreExecutors.directExecutor()).join();
    eventService3.broadcast("test1", "Hello world!", SERIALIZER::encode);
    Thread.sleep(100);
    assertEquals(3, events.size());
    events.clear();
    eventService3.unicast("test1", "Hello world!");
    Thread.sleep(100);
    assertEquals(1, events.size());
    assertTrue(events.contains(3));
    events.clear();
    eventService3.unicast("test1", "Hello world!");
    Thread.sleep(100);
    assertEquals(1, events.size());
    assertTrue(events.contains(1));
    events.clear();
    eventService3.unicast("test1", "Hello world!");
    Thread.sleep(100);
    assertEquals(1, events.size());
    assertTrue(events.contains(2));
    events.clear();
    eventService3.unicast("test1", "Hello world!");
    Thread.sleep(100);
    assertEquals(1, events.size());
    assertTrue(events.contains(3));
    events.clear();
    eventService1.<String, String>subscribe("test2", SERIALIZER::decode, message -> {
        events.add(1);
        return message;
    }, SERIALIZER::encode, MoreExecutors.directExecutor()).join();
    eventService2.<String, String>subscribe("test2", SERIALIZER::decode, message -> {
        events.add(2);
        return message;
    }, SERIALIZER::encode, MoreExecutors.directExecutor()).join();
    assertEquals("Hello world!", eventService3.send("test2", "Hello world!").join());
    assertEquals(1, events.size());
    assertTrue(events.contains(1));
    events.clear();
    assertEquals("Hello world!", eventService3.send("test2", "Hello world!").join());
    assertEquals(1, events.size());
    assertTrue(events.contains(2));
    events.clear();
    assertEquals("Hello world!", eventService3.send("test2", "Hello world!").join());
    assertEquals(1, events.size());
    assertTrue(events.contains(1));
    CompletableFuture.allOf(new CompletableFuture[] { clusterEventingService1.stop(), clusterEventingService2.stop(), clusterEventingService3.stop() }).join();
    CompletableFuture.allOf(new CompletableFuture[] { clusterService1.stop(), clusterService2.stop(), clusterService3.stop() }).join();
}
Also used : IntStream(java.util.stream.IntStream) Node(io.atomix.cluster.Node) MoreExecutors(com.google.common.util.concurrent.MoreExecutors) Address(io.atomix.utils.net.Address) CompletableFuture(java.util.concurrent.CompletableFuture) ClusterEventService(io.atomix.cluster.messaging.ClusterEventService) Namespaces(io.atomix.utils.serializer.Namespaces) ClusterMembershipService(io.atomix.cluster.ClusterMembershipService) DefaultClusterMembershipService(io.atomix.cluster.impl.DefaultClusterMembershipService) MessagingService(io.atomix.cluster.messaging.MessagingService) Collection(java.util.Collection) Set(java.util.Set) Assert.assertTrue(org.junit.Assert.assertTrue) DefaultNodeDiscoveryService(io.atomix.cluster.impl.DefaultNodeDiscoveryService) Test(org.junit.Test) Version(io.atomix.utils.Version) ManagedClusterEventService(io.atomix.cluster.messaging.ManagedClusterEventService) CopyOnWriteArraySet(java.util.concurrent.CopyOnWriteArraySet) Member(io.atomix.cluster.Member) Collectors(java.util.stream.Collectors) BootstrapDiscoveryProvider(io.atomix.cluster.discovery.BootstrapDiscoveryProvider) HeartbeatMembershipProtocolConfig(io.atomix.cluster.protocol.HeartbeatMembershipProtocolConfig) ManagedClusterMembershipService(io.atomix.cluster.ManagedClusterMembershipService) TestBootstrapService(io.atomix.cluster.TestBootstrapService) HeartbeatMembershipProtocol(io.atomix.cluster.protocol.HeartbeatMembershipProtocol) Serializer(io.atomix.utils.serializer.Serializer) Assert.assertEquals(org.junit.Assert.assertEquals) BootstrapService(io.atomix.cluster.BootstrapService) DefaultNodeDiscoveryService(io.atomix.cluster.impl.DefaultNodeDiscoveryService) Node(io.atomix.cluster.Node) CopyOnWriteArraySet(java.util.concurrent.CopyOnWriteArraySet) ManagedClusterMembershipService(io.atomix.cluster.ManagedClusterMembershipService) HeartbeatMembershipProtocolConfig(io.atomix.cluster.protocol.HeartbeatMembershipProtocolConfig) ManagedClusterEventService(io.atomix.cluster.messaging.ManagedClusterEventService) CompletableFuture(java.util.concurrent.CompletableFuture) ClusterMembershipService(io.atomix.cluster.ClusterMembershipService) DefaultClusterMembershipService(io.atomix.cluster.impl.DefaultClusterMembershipService) ManagedClusterMembershipService(io.atomix.cluster.ManagedClusterMembershipService) TestBootstrapService(io.atomix.cluster.TestBootstrapService) DefaultClusterMembershipService(io.atomix.cluster.impl.DefaultClusterMembershipService) Member(io.atomix.cluster.Member) HeartbeatMembershipProtocol(io.atomix.cluster.protocol.HeartbeatMembershipProtocol) TestBootstrapService(io.atomix.cluster.TestBootstrapService) BootstrapService(io.atomix.cluster.BootstrapService) BootstrapDiscoveryProvider(io.atomix.cluster.discovery.BootstrapDiscoveryProvider) MessagingService(io.atomix.cluster.messaging.MessagingService) ClusterEventService(io.atomix.cluster.messaging.ClusterEventService) ManagedClusterEventService(io.atomix.cluster.messaging.ManagedClusterEventService) Test(org.junit.Test)

Example 9 with Member

use of io.atomix.cluster.Member in project atomix by atomix.

the class DefaultClusterEventService method gossip.

/**
 * Sends a gossip message to an active peer.
 */
private void gossip() {
    List<Member> members = membershipService.getMembers().stream().filter(node -> !localMemberId.equals(node.id())).filter(node -> node.isReachable()).collect(Collectors.toList());
    if (!members.isEmpty()) {
        Collections.shuffle(members);
        Member member = members.get(0);
        updateNode(member);
    }
}
Also used : Arrays(java.util.Arrays) Address(io.atomix.utils.net.Address) BiFunction(java.util.function.BiFunction) LoggerFactory(org.slf4j.LoggerFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) CompletableFuture(java.util.concurrent.CompletableFuture) ClusterEventService(io.atomix.cluster.messaging.ClusterEventService) Function(java.util.function.Function) ArrayList(java.util.ArrayList) Threads.namedThreads(io.atomix.utils.concurrent.Threads.namedThreads) Lists(com.google.common.collect.Lists) Namespaces(io.atomix.utils.serializer.Namespaces) ImmutableList(com.google.common.collect.ImmutableList) ClusterMembershipService(io.atomix.cluster.ClusterMembershipService) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Duration(java.time.Duration) Map(java.util.Map) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) MemberId(io.atomix.cluster.MemberId) Futures(io.atomix.utils.concurrent.Futures) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) Executor(java.util.concurrent.Executor) MessagingService(io.atomix.cluster.messaging.MessagingService) Collection(java.util.Collection) ManagedClusterEventService(io.atomix.cluster.messaging.ManagedClusterEventService) Maps(com.google.common.collect.Maps) Member(io.atomix.cluster.Member) Collectors(java.util.stream.Collectors) Executors(java.util.concurrent.Executors) TimeUnit(java.util.concurrent.TimeUnit) Consumer(java.util.function.Consumer) AtomicLong(java.util.concurrent.atomic.AtomicLong) List(java.util.List) Subscription(io.atomix.cluster.messaging.Subscription) Stream(java.util.stream.Stream) Namespace(io.atomix.utils.serializer.Namespace) LogicalTimestamp(io.atomix.utils.time.LogicalTimestamp) MessagingException(io.atomix.cluster.messaging.MessagingException) WallClockTimestamp(io.atomix.utils.time.WallClockTimestamp) Serializer(io.atomix.utils.serializer.Serializer) Collections(java.util.Collections) Member(io.atomix.cluster.Member)

Example 10 with Member

use of io.atomix.cluster.Member in project atomix by atomix.

the class DefaultClusterEventService method broadcast.

@Override
public <M> void broadcast(String topic, M message, Function<M, byte[]> encoder) {
    byte[] payload = SERIALIZER.encode(new InternalMessage(InternalMessage.Type.ALL, encoder.apply(message)));
    getSubscriberNodes(topic).forEach(memberId -> {
        Member member = membershipService.getMember(memberId);
        if (member != null && member.isReachable()) {
            messagingService.sendAsync(member.address(), topic, payload);
        }
    });
}
Also used : Member(io.atomix.cluster.Member)

Aggregations

Member (io.atomix.cluster.Member)11 CompletableFuture (java.util.concurrent.CompletableFuture)5 Address (io.atomix.utils.net.Address)4 BootstrapService (io.atomix.cluster.BootstrapService)3 MemberId (io.atomix.cluster.MemberId)3 Node (io.atomix.cluster.Node)3 MessagingService (io.atomix.cluster.messaging.MessagingService)3 Test (org.junit.Test)3 Lists (com.google.common.collect.Lists)2 Maps (com.google.common.collect.Maps)2 ClusterMembershipEvent (io.atomix.cluster.ClusterMembershipEvent)2 ClusterMembershipService (io.atomix.cluster.ClusterMembershipService)2 ManagedClusterMembershipService (io.atomix.cluster.ManagedClusterMembershipService)2 TestBootstrapService (io.atomix.cluster.TestBootstrapService)2 BootstrapDiscoveryProvider (io.atomix.cluster.discovery.BootstrapDiscoveryProvider)2 ClusterEventService (io.atomix.cluster.messaging.ClusterEventService)2 ManagedClusterEventService (io.atomix.cluster.messaging.ManagedClusterEventService)2 HeartbeatMembershipProtocol (io.atomix.cluster.protocol.HeartbeatMembershipProtocol)2 HeartbeatMembershipProtocolConfig (io.atomix.cluster.protocol.HeartbeatMembershipProtocolConfig)2 RaftMember (io.atomix.protocols.raft.cluster.RaftMember)2