Skip to content

Title: Introduce Weighted Node Selection for Gradual Traffic Ramp-Up #64

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<groupId>io.appform.ranger</groupId>
<artifactId>ranger</artifactId>
<packaging>pom</packaging>
<version>1.1-RC5</version>
<version>1.2-RC5</version>
<name>Ranger</name>
<url>https://github.com/appform-io/ranger</url>
<description>Service Discovery for Java</description>
Expand Down
2 changes: 1 addition & 1 deletion ranger-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<artifactId>ranger</artifactId>
<groupId>io.appform.ranger</groupId>
<version>1.1-RC5</version>
<version>1.2-RC5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
2 changes: 1 addition & 1 deletion ranger-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<artifactId>ranger</artifactId>
<groupId>io.appform.ranger</groupId>
<version>1.1-RC5</version>
<version>1.2-RC5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import io.appform.ranger.core.finder.nodeselector.RandomServiceNodeSelector;
import io.appform.ranger.core.finder.nodeselector.WeightedRandomServiceNodeSelector;
import io.appform.ranger.core.finder.serviceregistry.ServiceRegistryUpdater;
import io.appform.ranger.core.finder.serviceregistry.signal.ScheduledRegistryUpdateSignal;
import io.appform.ranger.core.model.*;
import io.appform.ranger.core.model.Deserializer;
import io.appform.ranger.core.model.NodeDataSource;
import io.appform.ranger.core.model.Service;
import io.appform.ranger.core.model.ServiceNodeSelector;
import io.appform.ranger.core.model.ServiceRegistry;
import io.appform.ranger.core.model.ShardSelector;
import io.appform.ranger.core.signals.Signal;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
Expand All @@ -48,7 +53,7 @@ public abstract class BaseServiceFinderBuilder
protected boolean disablePushUpdaters;
protected D deserializer;
protected ShardSelector<T, R> shardSelector;
protected ServiceNodeSelector<T> nodeSelector = new RandomServiceNodeSelector<>();
protected ServiceNodeSelector<T> nodeSelector = new WeightedRandomServiceNodeSelector<>();
protected final List<Signal<T>> additionalRefreshSignals = new ArrayList<>();
protected final List<Consumer<Void>> startSignalHandlers = Lists.newArrayList();
protected final List<Consumer<Void>> stopSignalHandlers = Lists.newArrayList();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.appform.ranger.core.finder.nodeselector;

import io.appform.ranger.core.model.ServiceNode;
import io.appform.ranger.core.model.ServiceNodeSelector;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

public class WeightedRandomServiceNodeSelector<T> implements ServiceNodeSelector<T> {

@Override
public ServiceNode<T> select(List<ServiceNode<T>> serviceNodes) {
if (serviceNodes == null || serviceNodes.isEmpty()) {
throw new IllegalArgumentException("Service nodes list cannot be empty");
}

double totalWeight = 0.0;
double[] cumulativeWeights = new double[serviceNodes.size()];

for (int i = 0; i < serviceNodes.size(); i++) {
totalWeight += serviceNodes.get(i).getWeight();
cumulativeWeights[i] = totalWeight;
}

double randomValue = ThreadLocalRandom.current().nextDouble(totalWeight);


int index = Arrays.binarySearch(cumulativeWeights, randomValue);
if (index < 0) {
index = -index - 1;
}

return serviceNodes.get(index);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
public class ServiceNode<T> {
private String host;
private int port;
@Builder.Default
private double weight = 1.0;
private T nodeData;
@Builder.Default
private HealthcheckStatus healthcheckStatus = HealthcheckStatus.healthy;
Expand All @@ -37,6 +39,18 @@ public class ServiceNode<T> {
@Builder.Default
private String portScheme = PortSchemes.HTTP;

public ServiceNode(final String host, final int port, final T nodeData, final HealthcheckStatus healthcheckStatus,
final long lastUpdatedTimeStamp,
final String portScheme) {
this.host = host;
this.port = port;
this.weight = 1;
this.nodeData = nodeData;
this.healthcheckStatus = healthcheckStatus;
this.lastUpdatedTimeStamp = lastUpdatedTimeStamp;
this.portScheme = portScheme;
}

public String representation() {
return String.format("%s:%d", host, port);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.lang.management.ManagementFactory;
import java.util.Collections;
import java.util.List;

Expand Down Expand Up @@ -69,10 +70,23 @@ private void handleHealthUpdate(HealthcheckResult result) {
log.debug("No update to health state of node. Skipping data source update.");
return;
}

serviceNode.setWeight(computeWeight());// to be updated
serviceNode.setHealthcheckStatus(result.getStatus());
serviceNode.setLastUpdatedTimeStamp(result.getUpdatedTime());
dataSink.updateState(serializer, serviceNode);
log.debug("Updated node with health check result: {}", result);
}

private double computeWeight() {
double T = 60000; // Midpoint at 5 minutes
double S = 30000; // Scaling factor

return 1.0 / (1.0 + Math.exp(-( (getInstanceUptime() - T) / S )));
}

private long getInstanceUptime() {
return ManagementFactory.getRuntimeMXBean().getUptime();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,8 @@ private static class TestNodeDataSource implements NodeDataSource<TestNodeData,
@Override
public Optional<List<ServiceNode<TestNodeData>>> refresh(Deserializer<TestNodeData> deserializer) {
val list = new ArrayList<ServiceNode<TestNodeData>>();
list.add(new ServiceNode<>("HOST", 0, TestNodeData.builder().shardId(1).build(), HealthcheckStatus.healthy, Long.MAX_VALUE, "HTTP"));
list.add(new ServiceNode<>("HOST", 0, 1f, TestNodeData.builder().shardId(1).build(),
HealthcheckStatus.healthy, Long.MAX_VALUE, "HTTP"));
return Optional.of(list);
}

Expand Down
2 changes: 1 addition & 1 deletion ranger-discovery-bundle/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<artifactId>ranger</artifactId>
<groupId>io.appform.ranger</groupId>
<version>1.1-RC5</version>
<version>1.2-RC5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
2 changes: 1 addition & 1 deletion ranger-drove-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<artifactId>ranger</artifactId>
<groupId>io.appform.ranger</groupId>
<version>1.1-RC5</version>
<version>1.2-RC5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
package io.appform.ranger.client.drove;

import io.appform.ranger.client.AbstractRangerHubClient;
import io.appform.ranger.core.finder.nodeselector.RandomServiceNodeSelector;
import io.appform.ranger.core.finder.nodeselector.WeightedRandomServiceNodeSelector;
import io.appform.ranger.core.finderhub.ServiceDataSource;
import io.appform.ranger.core.finderhub.ServiceFinderHub;
import io.appform.ranger.core.model.ServiceNodeSelector;
Expand All @@ -42,7 +42,7 @@ public abstract class AbstractRangerDroveHubClient<T, R extends ServiceRegistry<
private final DroveCommunicator droveCommunicator;

@Builder.Default
private final ServiceNodeSelector<T> nodeSelector = new RandomServiceNodeSelector<>();
private final ServiceNodeSelector<T> nodeSelector = new WeightedRandomServiceNodeSelector<>();

@Override
protected ServiceDataSource getDefaultDataSource() {
Expand Down
2 changes: 1 addition & 1 deletion ranger-drove/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<artifactId>ranger</artifactId>
<groupId>io.appform.ranger</groupId>
<version>1.1-RC5</version>
<version>1.2-RC5</version>
</parent>
<properties>
<drove.version>1.30</drove.version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
import lombok.extern.slf4j.Slf4j;
import lombok.val;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
Expand All @@ -44,6 +46,7 @@ public final List<ServiceNode<T>> deserialize(List<ExposedAppInfo> appInfo) {
}
return new ServiceNode<>(endpoint.getHost(),
endpoint.getPort(),
1,
info,
HealthcheckStatus.healthy,
currTime,
Expand Down
2 changes: 1 addition & 1 deletion ranger-http-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<artifactId>ranger</artifactId>
<groupId>io.appform.ranger</groupId>
<version>1.1-RC5</version>
<version>1.2-RC5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
package io.appform.ranger.client.http;

import io.appform.ranger.client.AbstractRangerHubClient;
import io.appform.ranger.core.finder.nodeselector.RandomServiceNodeSelector;
import io.appform.ranger.core.finder.nodeselector.WeightedRandomServiceNodeSelector;
import io.appform.ranger.core.finderhub.ServiceDataSource;
import io.appform.ranger.core.finderhub.ServiceFinderHub;
import io.appform.ranger.core.model.ServiceNodeSelector;
Expand Down Expand Up @@ -46,7 +46,7 @@ public abstract class AbstractRangerHttpHubClient<T, R extends ServiceRegistry<T
private final HttpCommunicator<T> httpClient;

@Builder.Default
private final ServiceNodeSelector<T> nodeSelector = new RandomServiceNodeSelector<>();
private final ServiceNodeSelector<T> nodeSelector = new WeightedRandomServiceNodeSelector<>();

@Override
protected ServiceDataSource getDefaultDataSource() {
Expand Down
2 changes: 1 addition & 1 deletion ranger-http-model/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<artifactId>ranger</artifactId>
<groupId>io.appform.ranger</groupId>
<version>1.1-RC5</version>
<version>1.2-RC5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
2 changes: 1 addition & 1 deletion ranger-http/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<artifactId>ranger</artifactId>
<groupId>io.appform.ranger</groupId>
<version>1.1-RC5</version>
<version>1.2-RC5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
2 changes: 1 addition & 1 deletion ranger-hub-server-bundle/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<artifactId>ranger</artifactId>
<groupId>io.appform.ranger</groupId>
<version>1.1-RC5</version>
<version>1.2-RC5</version>
</parent>
<build>
<plugins>
Expand Down
2 changes: 1 addition & 1 deletion ranger-server-bundle/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<artifactId>ranger</artifactId>
<groupId>io.appform.ranger</groupId>
<version>1.1-RC5</version>
<version>1.2-RC5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
2 changes: 1 addition & 1 deletion ranger-server-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<artifactId>ranger</artifactId>
<groupId>io.appform.ranger</groupId>
<version>1.1-RC5</version>
<version>1.2-RC5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
2 changes: 1 addition & 1 deletion ranger-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<parent>
<groupId>io.appform.ranger</groupId>
<artifactId>ranger</artifactId>
<version>1.1-RC5</version>
<version>1.2-RC5</version>
</parent>

<artifactId>ranger-server</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion ranger-zk-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<artifactId>ranger</artifactId>
<groupId>io.appform.ranger</groupId>
<version>1.1-RC5</version>
<version>1.2-RC5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
package io.appform.ranger.client.zk;

import io.appform.ranger.core.finder.nodeselector.RandomServiceNodeSelector;
import io.appform.ranger.core.finder.nodeselector.WeightedRandomServiceNodeSelector;
import io.appform.ranger.core.finder.serviceregistry.MapBasedServiceRegistry;
import io.appform.ranger.core.finder.shardselector.MatchingShardSelector;
import io.appform.ranger.core.finderhub.ServiceFinderFactory;
Expand All @@ -36,7 +36,7 @@ public class ShardedRangerZKHubClient<T>
private final ShardSelector<T, MapBasedServiceRegistry<T>> shardSelector = new MatchingShardSelector<>();

@Builder.Default
private final ServiceNodeSelector<T> nodeSelector = new RandomServiceNodeSelector<>();
private final ServiceNodeSelector<T> nodeSelector = new WeightedRandomServiceNodeSelector<>();

@Override
protected ServiceFinderFactory<T, MapBasedServiceRegistry<T>> getFinderFactory() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
package io.appform.ranger.client.zk;

import io.appform.ranger.core.finder.nodeselector.RandomServiceNodeSelector;
import io.appform.ranger.core.finder.nodeselector.WeightedRandomServiceNodeSelector;
import io.appform.ranger.core.finder.serviceregistry.ListBasedServiceRegistry;
import io.appform.ranger.core.finder.shardselector.ListShardSelector;
import io.appform.ranger.core.finderhub.ServiceFinderFactory;
Expand All @@ -36,7 +36,7 @@ public class UnshardedRangerZKHubClient<T>
private final ShardSelector<T, ListBasedServiceRegistry<T>> shardSelector = new ListShardSelector<>();

@Builder.Default
private final ServiceNodeSelector<T> nodeSelector = new RandomServiceNodeSelector<>();
private final ServiceNodeSelector<T> nodeSelector = new WeightedRandomServiceNodeSelector<>();

@Override
protected ServiceFinderFactory<T, ListBasedServiceRegistry<T>> getFinderFactory() {
Expand Down
2 changes: 1 addition & 1 deletion ranger-zookeeper/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<artifactId>ranger</artifactId>
<groupId>io.appform.ranger</groupId>
<version>1.1-RC5</version>
<version>1.2-RC5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
Loading