GOSSIP-22 New failure detector

This commit is contained in:
Edward Capriolo
2017-01-06 20:59:32 -05:00
parent 18c9f911d1
commit f56d282d30
16 changed files with 428 additions and 235 deletions

View File

@ -23,6 +23,7 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.UUID;
@ -31,8 +32,6 @@ import java.util.concurrent.TimeUnit;
import org.apache.log4j.Logger;
import org.apache.gossip.event.GossipListener;
import org.apache.gossip.event.GossipState;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.jupiter.api.Test;
@ -46,31 +45,20 @@ public class ShutdownDeadtimeTest {
@Test
public void DeadNodesDoNotComeAliveAgain()
throws InterruptedException, UnknownHostException, URISyntaxException {
GossipSettings settings = new GossipSettings(1000, 10000);
GossipSettings settings = new GossipSettings(1000, 10000, 1000, 1, 5.0);
String cluster = UUID.randomUUID().toString();
log.info("Adding seed nodes");
int seedNodes = 3;
List<GossipMember> startupMembers = new ArrayList<>();
for (int i = 1; i < seedNodes + 1; ++i) {
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (50000 + i));
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (30300 + i));
startupMembers.add(new RemoteGossipMember(cluster, uri, i + ""));
}
log.info("Adding clients");
final List<GossipService> clients = new ArrayList<>();
final List<GossipService> clients = Collections.synchronizedList(new ArrayList<GossipService>());
final int clusterMembers = 5;
for (int i = 1; i < clusterMembers + 1; ++i) {
final int j = i;
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (50000 + i));
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (30300 + i));
GossipService gossipService = new GossipService(cluster, uri, i + "", startupMembers,
settings, new GossipListener() {
@Override
public void gossipEvent(GossipMember member, GossipState state) {
System.out.println(System.currentTimeMillis() + " Member " + j + " reports "
+ member + " " + state);
}
});
settings, (a,b) -> {});
clients.add(gossipService);
gossipService.start();
}
@ -100,7 +88,7 @@ public class ShutdownDeadtimeTest {
}
return total;
}
}).afterWaitingAtMost(20, TimeUnit.SECONDS).isEqualTo(16);
}).afterWaitingAtMost(40, TimeUnit.SECONDS).isEqualTo(16);
clients.remove(randomClientId);
TUnit.assertThat(new Callable<Integer>() {
@ -111,17 +99,12 @@ public class ShutdownDeadtimeTest {
}
return total;
}
}).afterWaitingAtMost(10, TimeUnit.SECONDS).isEqualTo(4);
}).afterWaitingAtMost(30, TimeUnit.SECONDS).isEqualTo(4);
URI uri = new URI("udp://" + "127.0.0.1" + ":" + shutdownPort);
// start client again
GossipService gossipService = new GossipService(cluster, uri, shutdownId + "", startupMembers,
settings, new GossipListener() {
@Override
public void gossipEvent(GossipMember member, GossipState state) {
// System.out.println("revived " + member+" "+ state);
}
});
settings, (a,b) -> {});
clients.add(gossipService);
gossipService.start();
@ -134,7 +117,7 @@ public class ShutdownDeadtimeTest {
}
return total;
}
}).afterWaitingAtMost(20, TimeUnit.SECONDS).isEqualTo(20);
}).afterWaitingAtMost(60, TimeUnit.SECONDS).isEqualTo(20);
for (int i = 0; i < clusterMembers; ++i) {
clients.get(i).shutdown();

View File

@ -48,28 +48,16 @@ public class StartupSettingsTest {
@Test
public void testUsingSettingsFile() throws IOException, InterruptedException, URISyntaxException {
File settingsFile = File.createTempFile("gossipTest",".json");
log.debug( "Using settings file: " + settingsFile.getAbsolutePath() );
settingsFile.deleteOnExit();
writeSettingsFile(settingsFile);
URI uri = new URI("udp://" + "127.0.0.1" + ":" + 50000);
final GossipService firstService = new GossipService(
CLUSTER, uri, UUID.randomUUID().toString(),
CLUSTER, uri, "1",
new ArrayList<GossipMember>(), new GossipSettings(), null);
firstService.start();
TUnit.assertThat(new Callable<Integer> (){
public Integer call() throws Exception {
return firstService.getGossipManager().getLiveMembers().size();
}}).afterWaitingAtMost(30, TimeUnit.SECONDS).isEqualTo(0);
final GossipService serviceUnderTest = new GossipService(
StartupSettings.fromJSONFile( settingsFile )
);
StartupSettings.fromJSONFile(settingsFile));
serviceUnderTest.start();
TUnit.assertThat(new Callable<Integer> (){
public Integer call() throws Exception {
return serviceUnderTest.getGossipManager().getLiveMembers().size();
}}).afterWaitingAtMost(10, TimeUnit.SECONDS).isEqualTo(1);
firstService.shutdown();
serviceUnderTest.shutdown();
}
@ -78,10 +66,13 @@ public class StartupSettingsTest {
String settings =
"[{\n" + // It is odd that this is meant to be in an array, but oh well.
" \"cluster\":\"" + CLUSTER + "\",\n" +
" \"id\":\"" + UUID.randomUUID() + "\",\n" +
" \"id\":\"" + "2" + "\",\n" +
" \"uri\":\"udp://127.0.0.1:50001\",\n" +
" \"gossip_interval\":1000,\n" +
" \"window_size\":1000,\n" +
" \"minimum_samples\":5,\n" +
" \"cleanup_interval\":10000,\n" +
" \"convict_threshold\":2.6,\n" +
" \"members\":[\n" +
" {\"cluster\": \"" + CLUSTER + "\",\"uri\":\"udp://127.0.0.1:5000\"}\n" +
" ]\n" +

View File

@ -29,54 +29,39 @@ import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
import org.apache.log4j.Logger;
import org.apache.gossip.event.GossipListener;
import org.apache.gossip.event.GossipState;
import org.junit.jupiter.api.Test;
@RunWith(JUnitPlatform.class)
public class TenNodeThreeSeedTest {
private static final Logger log = Logger.getLogger( TenNodeThreeSeedTest.class );
@Test
public void test() throws UnknownHostException, InterruptedException, URISyntaxException{
abc();
public void test() throws UnknownHostException, InterruptedException, URISyntaxException {
abc(30150);
}
@Test
public void testAgain() throws UnknownHostException, InterruptedException, URISyntaxException{
abc();
abc(30100);
}
public void abc() throws InterruptedException, UnknownHostException, URISyntaxException{
public void abc(int base) throws InterruptedException, UnknownHostException, URISyntaxException{
GossipSettings settings = new GossipSettings();
String cluster = UUID.randomUUID().toString();
log.info( "Adding seed nodes" );
int seedNodes = 3;
List<GossipMember> startupMembers = new ArrayList<>();
for (int i = 1; i < seedNodes+1; ++i) {
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (50000 + i));
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (base + i));
startupMembers.add(new RemoteGossipMember(cluster, uri, i + ""));
}
log.info( "Adding clients" );
final List<GossipService> clients = new ArrayList<>();
final int clusterMembers = 5;
for (int i = 1; i < clusterMembers+1; ++i) {
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (50000 + i));
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (base + i));
GossipService gossipService = new GossipService(cluster, uri, i + "",
startupMembers, settings,
new GossipListener(){
@Override
public void gossipEvent(GossipMember member, GossipState state) {
log.info(member+" "+ state);
}
});
startupMembers, settings, (a,b) -> {});
clients.add(gossipService);
gossipService.start();
}
}
TUnit.assertThat(new Callable<Integer> (){
public Integer call() throws Exception {
int total = 0;
@ -84,8 +69,8 @@ public class TenNodeThreeSeedTest {
total += clients.get(i).getGossipManager().getLiveMembers().size();
}
return total;
}}).afterWaitingAtMost(20, TimeUnit.SECONDS).isEqualTo(20);
}}).afterWaitingAtMost(40, TimeUnit.SECONDS).isEqualTo(20);
for (int i = 0; i < clusterMembers; ++i) {
clients.get(i).shutdown();
}

View File

@ -0,0 +1,62 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.gossip.accrual;
import java.net.URI;
import org.apache.gossip.LocalGossipMember;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.jupiter.api.Test;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
@RunWith(JUnitPlatform.class)
public class FailureDetectorTest {
@Test
public void aTest(){
int samples = 1;
int windowSize = 1000;
LocalGossipMember member = new LocalGossipMember("", URI.create("udp://127.0.0.1:1000"), "", 0L, windowSize, samples);
member.recordHeartbeat(5);
member.recordHeartbeat(10);
Assert.assertEquals(new Double(0.4342944819032518), member.detect(10));
Assert.assertEquals(new Double(0.5211533782839021), member.detect(11));
Assert.assertEquals(new Double(1.3028834457097553), member.detect(20));
Assert.assertEquals(new Double(3.9), member.detect(50), .01);
Assert.assertEquals(new Double(8.25), member.detect(100), .01);
Assert.assertEquals(new Double(12.6), member.detect(150), .01);
Assert.assertEquals(new Double(14.77), member.detect(175), .01);
Assert.assertEquals(new Double(Double.POSITIVE_INFINITY), member.detect(500), .01);
member.recordHeartbeat(4);
Assert.assertEquals(new Double(12.6), member.detect(150), .01);
}
@Ignore
public void sameHeartbeatTest(){
int samples = 1;
int windowSize = 1000;
LocalGossipMember member = new LocalGossipMember("", URI.create("udp://127.0.0.1:1000"), "", 0L, windowSize, samples);
member.recordHeartbeat(5);
member.recordHeartbeat(5);
member.recordHeartbeat(5);
Assert.assertEquals(new Double(0.4342944819032518), member.detect(10));
}
}

View File

@ -37,7 +37,8 @@ public class DataReaperTest {
String value = "a";
GossipSettings settings = new GossipSettings();
GossipManager gm = RandomGossipManager.newBuilder().cluster("abc").settings(settings)
.withId(myId).uri(URI.create("udp://localhost:5000")).build();
.withId(myId).uri(URI.create("udp://localhost:6000")).build();
gm.init();
gm.gossipPerNodeData(perNodeDatum(key, value));
gm.gossipSharedData(sharedDatum(key, value));
Assert.assertEquals(value, gm.findPerNodeGossipData(myId, key).getPayload());
@ -46,6 +47,7 @@ public class DataReaperTest {
gm.getDataReaper().runSharedOnce();
TUnit.assertThat(() -> gm.findPerNodeGossipData(myId, key)).equals(null);
TUnit.assertThat(() -> gm.findSharedGossipData(key)).equals(null);
gm.shutdown();
}
private GossipDataMessage perNodeDatum(String key, String value) {
@ -74,7 +76,8 @@ public class DataReaperTest {
String value = "a";
GossipSettings settings = new GossipSettings();
GossipManager gm = RandomGossipManager.newBuilder().cluster("abc").settings(settings)
.withId(myId).uri(URI.create("udp://localhost:5000")).build();
.withId(myId).uri(URI.create("udp://localhost:7000")).build();
gm.init();
GossipDataMessage before = perNodeDatum(key, value);
GossipDataMessage after = perNodeDatum(key, "b");
after.setTimestamp(after.getTimestamp() - 1);
@ -82,6 +85,7 @@ public class DataReaperTest {
Assert.assertEquals(value, gm.findPerNodeGossipData(myId, key).getPayload());
gm.gossipPerNodeData(after);
Assert.assertEquals(value, gm.findPerNodeGossipData(myId, key).getPayload());
gm.shutdown();
}
}

View File

@ -83,14 +83,14 @@ public class RandomGossipManagerBuilderTest {
.uri(new URI("udp://localhost:2000"))
.settings(new GossipSettings())
.gossipMembers(null).build();
assertNotNull(gossipManager.getLiveMembers());
}
@Test
public void useMemberListIfProvided() throws URISyntaxException {
LocalGossipMember member = new LocalGossipMember("aCluster", new URI("udp://localhost:2000"), "aGossipMember",
System.currentTimeMillis(), new TestNotificationListener(), 60000);
LocalGossipMember member = new LocalGossipMember(
"aCluster", new URI("udp://localhost:2000"), "aGossipMember",
System.nanoTime(), 1000, 1);
List<GossipMember> memberList = new ArrayList<>();
memberList.add(member);
RandomGossipManager gossipManager = RandomGossipManager.newBuilder()
@ -99,8 +99,8 @@ public class RandomGossipManagerBuilderTest {
.settings(new GossipSettings())
.uri(new URI("udp://localhost:8000"))
.gossipMembers(memberList).build();
assertEquals(1, gossipManager.getLiveMembers().size());
assertEquals(member.getId(), gossipManager.getLiveMembers().get(0).getId());
assertEquals(1, gossipManager.getDeadMembers().size());
assertEquals(member.getId(), gossipManager.getDeadMembers().get(0).getId());
}
}