mirror of
https://github.com/robindhole/Low-Level-Design.git
synced 2025-09-13 12:22:31 +00:00
Added LLD projects
This commit is contained in:
3
service-orchestrator/.idea/.gitignore
generated
vendored
Normal file
3
service-orchestrator/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
13
service-orchestrator/.idea/compiler.xml
generated
Normal file
13
service-orchestrator/.idea/compiler.xml
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<annotationProcessing>
|
||||
<profile name="Maven default annotation processors profile" enabled="true">
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
<outputRelativeToContentRoot value="true" />
|
||||
<module name="service-orchestrator" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
</project>
|
20
service-orchestrator/.idea/jarRepositories.xml
generated
Normal file
20
service-orchestrator/.idea/jarRepositories.xml
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
14
service-orchestrator/.idea/misc.xml
generated
Normal file
14
service-orchestrator/.idea/misc.xml
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
124
service-orchestrator/.idea/uiDesigner.xml
generated
Normal file
124
service-orchestrator/.idea/uiDesigner.xml
generated
Normal file
@@ -0,0 +1,124 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Palette2">
|
||||
<group name="Swing">
|
||||
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||
</item>
|
||||
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||
<initial-values>
|
||||
<property name="text" value="Button" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="RadioButton" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="CheckBox" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="Label" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||
<preferred-size width="-1" height="20" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||
</item>
|
||||
</group>
|
||||
</component>
|
||||
</project>
|
6
service-orchestrator/.idea/vcs.xml
generated
Normal file
6
service-orchestrator/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
31
service-orchestrator/pom.xml
Normal file
31
service-orchestrator/pom.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.example</groupId>
|
||||
<artifactId>service-orchestrator</artifactId>
|
||||
<version>1.0</version>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>11</source>
|
||||
<target>11</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
2
service-orchestrator/service-orchestrator.iml
Normal file
2
service-orchestrator/service-orchestrator.iml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4" />
|
33
service-orchestrator/src/main/java/LoadBalancer.java
Normal file
33
service-orchestrator/src/main/java/LoadBalancer.java
Normal file
@@ -0,0 +1,33 @@
|
||||
import models.Node;
|
||||
import models.Request;
|
||||
import models.Service;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class LoadBalancer {
|
||||
private final Map<String, Service> services;
|
||||
private final Map<String, Node> nodes;
|
||||
|
||||
public LoadBalancer() {
|
||||
this.services = new ConcurrentHashMap<>();
|
||||
this.nodes = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
public void register(Service service) {
|
||||
services.put(service.getId(), service);
|
||||
}
|
||||
|
||||
public void addNode(String serviceId, Node node) {
|
||||
nodes.put(node.getId(), node);
|
||||
services.get(serviceId).getRouter().addNode(node);
|
||||
}
|
||||
|
||||
public void removeNode(String serviceId, String nodeId) {
|
||||
services.get(serviceId).getRouter().removeNode(nodes.remove(nodeId));
|
||||
}
|
||||
|
||||
public Node getHandler(Request request) {
|
||||
return services.get(request.getServiceId()).getRouter().getAssignedNode(request);
|
||||
}
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
package algorithms;
|
||||
|
||||
import models.Node;
|
||||
import models.Request;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ConsistentHashing implements Router {
|
||||
private final Map<Node, List<Long>> nodePositions;
|
||||
private final ConcurrentSkipListMap<Long, Node> nodeMappings;
|
||||
private final Function<String, Long> hashFunction;
|
||||
private final int pointMultiplier;
|
||||
|
||||
|
||||
public ConsistentHashing(final Function<String, Long> hashFunction,
|
||||
final int pointMultiplier) {
|
||||
if (pointMultiplier == 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.pointMultiplier = pointMultiplier;
|
||||
this.hashFunction = hashFunction;
|
||||
this.nodePositions = new ConcurrentHashMap<>();
|
||||
this.nodeMappings = new ConcurrentSkipListMap<>();
|
||||
}
|
||||
|
||||
public void addNode(Node node) {
|
||||
nodePositions.put(node, new CopyOnWriteArrayList<>());
|
||||
for (int i = 0; i < pointMultiplier; i++) {
|
||||
for (int j = 0; j < node.getWeight(); j++) {
|
||||
final var point = hashFunction.apply((i * pointMultiplier + j) + node.getId());
|
||||
nodePositions.get(node).add(point);
|
||||
nodeMappings.put(point, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeNode(Node node) {
|
||||
for (final Long point : nodePositions.remove(node)) {
|
||||
nodeMappings.remove(point);
|
||||
}
|
||||
}
|
||||
|
||||
public Node getAssignedNode(Request request) {
|
||||
final var key = hashFunction.apply(request.getId());
|
||||
final var entry = nodeMappings.higherEntry(key);
|
||||
if (entry == null) {
|
||||
return nodeMappings.firstEntry().getValue();
|
||||
} else {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
}
|
12
service-orchestrator/src/main/java/algorithms/Router.java
Normal file
12
service-orchestrator/src/main/java/algorithms/Router.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package algorithms;
|
||||
|
||||
import models.Node;
|
||||
import models.Request;
|
||||
|
||||
public interface Router {
|
||||
void addNode(Node node);
|
||||
|
||||
void removeNode(Node node);
|
||||
|
||||
Node getAssignedNode(Request request);
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
package algorithms;
|
||||
|
||||
import models.Node;
|
||||
import models.Request;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class WeightedRoundRobin implements Router {
|
||||
private final List<Node> nodes;
|
||||
private int assignTo;
|
||||
private int currentNodeAssignments;
|
||||
private final Object lock;
|
||||
|
||||
public WeightedRoundRobin() {
|
||||
this.nodes = new ArrayList<>();
|
||||
this.assignTo = 0;
|
||||
this.lock = new Object();
|
||||
}
|
||||
|
||||
public void addNode(Node node) {
|
||||
synchronized (this.lock) {
|
||||
nodes.add(node);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeNode(Node node) {
|
||||
synchronized (this.lock) {
|
||||
nodes.remove(node);
|
||||
assignTo--;
|
||||
currentNodeAssignments = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public Node getAssignedNode(Request request) {
|
||||
synchronized (this.lock) {
|
||||
assignTo = assignTo % nodes.size();
|
||||
final var currentNode = nodes.get(assignTo);
|
||||
currentNodeAssignments++;
|
||||
if (currentNodeAssignments == currentNode.getWeight()) {
|
||||
assignTo++;
|
||||
currentNodeAssignments = 0;
|
||||
}
|
||||
return currentNode;
|
||||
}
|
||||
}
|
||||
}
|
45
service-orchestrator/src/main/java/models/Node.java
Normal file
45
service-orchestrator/src/main/java/models/Node.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package models;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Node {
|
||||
private final String id;
|
||||
private final int weight;
|
||||
private final String ipAddress;
|
||||
|
||||
public Node(String id, String ipAddress) {
|
||||
this(id, ipAddress, 1);
|
||||
}
|
||||
|
||||
public Node(String id, String ipAddress, int weight) {
|
||||
this.id = id;
|
||||
this.weight = weight;
|
||||
this.ipAddress = ipAddress;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
public String getIpAddress() {
|
||||
return ipAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Node node = (Node) o;
|
||||
return id.equals(node.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
}
|
26
service-orchestrator/src/main/java/models/Request.java
Normal file
26
service-orchestrator/src/main/java/models/Request.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package models;
|
||||
|
||||
public class Request {
|
||||
private final String id;
|
||||
|
||||
private final String serviceId;
|
||||
private final String method;
|
||||
|
||||
public Request(String id, String serviceId, String method) {
|
||||
this.id = id;
|
||||
this.serviceId = serviceId;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getServiceId() {
|
||||
return serviceId;
|
||||
}
|
||||
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
}
|
27
service-orchestrator/src/main/java/models/Service.java
Normal file
27
service-orchestrator/src/main/java/models/Service.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package models;
|
||||
|
||||
import algorithms.Router;
|
||||
|
||||
public class Service {
|
||||
private final Router router;
|
||||
private final String id;
|
||||
private final String[] methods;
|
||||
|
||||
public Service(String id, Router router, String[] methods) {
|
||||
this.router = router;
|
||||
this.id = id;
|
||||
this.methods = methods;
|
||||
}
|
||||
|
||||
public Router getRouter() {
|
||||
return router;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String[] getMethods() {
|
||||
return methods;
|
||||
}
|
||||
}
|
70
service-orchestrator/src/test/java/LBTester.java
Normal file
70
service-orchestrator/src/test/java/LBTester.java
Normal file
@@ -0,0 +1,70 @@
|
||||
import algorithms.ConsistentHashing;
|
||||
import algorithms.WeightedRoundRobin;
|
||||
import models.Node;
|
||||
import models.Request;
|
||||
import models.Service;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class LBTester {
|
||||
@Test
|
||||
public void LBDefaultBehaviour() {
|
||||
LoadBalancer loadBalancer = new LoadBalancer();
|
||||
final var consistentHashing = new ConsistentHashing(point -> (long) Math.abs(point.hashCode()) % 100, 1);
|
||||
final String profileServiceId = "profile", smsServiceId = "sms", emailServiceId = "email";
|
||||
|
||||
loadBalancer.register(new Service(profileServiceId, consistentHashing, new String[]{"addProfile", "deleteProfile", "updateProfile"}));
|
||||
loadBalancer.register(new Service(smsServiceId, new WeightedRoundRobin(), new String[]{"sendSms", "addTemplate", "getSMSForUser"}));
|
||||
loadBalancer.register(new Service(emailServiceId, new WeightedRoundRobin(), new String[]{"sendEmail", "addTemplate", "getSMSForUser"}));
|
||||
|
||||
final Node pNode1 = new Node("51", "35.45.55.65", 2), pNode2 = new Node("22", "35.45.55.66", 3);
|
||||
loadBalancer.addNode(profileServiceId, pNode1);
|
||||
loadBalancer.addNode(profileServiceId, pNode2);
|
||||
|
||||
final Node sNode1 = new Node("13", "35.45.55.67"), sNode2 = new Node("64", "35.45.55.68");
|
||||
loadBalancer.addNode(smsServiceId, sNode1);
|
||||
loadBalancer.addNode(smsServiceId, sNode2);
|
||||
|
||||
final Node eNode1 = new Node("node-35", "35.45.55.69", 2), eNode2 = new Node("node-76", "35.45.55.70");
|
||||
loadBalancer.addNode(emailServiceId, eNode1);
|
||||
loadBalancer.addNode(emailServiceId, eNode2);
|
||||
|
||||
var profileNode1 = loadBalancer.getHandler(new Request("r-123", profileServiceId, "addProfile"));
|
||||
var profileNode2 = loadBalancer.getHandler(new Request("r-244", profileServiceId, "addProfile"));
|
||||
var profileNode3 = loadBalancer.getHandler(new Request("r-659", profileServiceId, "addProfile"));
|
||||
var profileNode4 = loadBalancer.getHandler(new Request("r-73", profileServiceId, "addProfile"));
|
||||
Assert.assertEquals(pNode1, profileNode1);
|
||||
Assert.assertEquals(pNode1, profileNode2);
|
||||
Assert.assertEquals(pNode2, profileNode3);
|
||||
Assert.assertEquals(pNode1, profileNode4);
|
||||
|
||||
loadBalancer.removeNode(profileServiceId, pNode1.getId());
|
||||
|
||||
profileNode1 = loadBalancer.getHandler(new Request("r-123", profileServiceId, "addProfile"));
|
||||
profileNode2 = loadBalancer.getHandler(new Request("r-244", profileServiceId, "addProfile"));
|
||||
profileNode3 = loadBalancer.getHandler(new Request("r-659", profileServiceId, "addProfile"));
|
||||
profileNode4 = loadBalancer.getHandler(new Request("r-73", profileServiceId, "addProfile"));
|
||||
Assert.assertEquals(pNode2, profileNode1);
|
||||
Assert.assertEquals(pNode2, profileNode2);
|
||||
Assert.assertEquals(pNode2, profileNode3);
|
||||
Assert.assertEquals(pNode2, profileNode4);
|
||||
|
||||
final var smsNode1 = loadBalancer.getHandler(new Request("r-124", smsServiceId, "addTemplate"));
|
||||
final var smsNode2 = loadBalancer.getHandler(new Request("r-1214", smsServiceId, "addTemplate"));
|
||||
final var smsNode3 = loadBalancer.getHandler(new Request("r-4", smsServiceId, "addTemplate"));
|
||||
|
||||
Assert.assertEquals(sNode1, smsNode1);
|
||||
Assert.assertEquals(sNode2, smsNode2);
|
||||
Assert.assertEquals(sNode1, smsNode3);
|
||||
|
||||
final var emailNode1 = loadBalancer.getHandler(new Request("r-1232", emailServiceId, "addTemplate"));
|
||||
final var emailNode2 = loadBalancer.getHandler(new Request("r-4134", emailServiceId, "addTemplate"));
|
||||
final var emailNode3 = loadBalancer.getHandler(new Request("r-23432", emailServiceId, "addTemplate"));
|
||||
final var emailNode4 = loadBalancer.getHandler(new Request("r-5345", emailServiceId, "addTemplate"));
|
||||
|
||||
Assert.assertEquals(eNode1, emailNode1);
|
||||
Assert.assertEquals(eNode1, emailNode2);
|
||||
Assert.assertEquals(eNode2, emailNode3);
|
||||
Assert.assertEquals(eNode1, emailNode4);
|
||||
}
|
||||
}
|
140
service-orchestrator/src/test/java/RouterTester.java
Normal file
140
service-orchestrator/src/test/java/RouterTester.java
Normal file
@@ -0,0 +1,140 @@
|
||||
import algorithms.ConsistentHashing;
|
||||
import algorithms.Router;
|
||||
import algorithms.WeightedRoundRobin;
|
||||
import models.Node;
|
||||
import models.Request;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class RouterTester {
|
||||
String ipAddress = "127.0.0.1", serviceId = "service", method = "method";
|
||||
|
||||
@Test
|
||||
public void defaultRoundRobin() {
|
||||
final Router router = new WeightedRoundRobin();
|
||||
final Node node1 = newNode("node-1"), node2 = newNode("node-2"), node3 = newNode("node-3");
|
||||
router.addNode(node1);
|
||||
router.addNode(node2);
|
||||
router.addNode(node3);
|
||||
|
||||
Assert.assertEquals(node1, router.getAssignedNode(newRequest("r-123")));
|
||||
Assert.assertEquals(node2, router.getAssignedNode(newRequest("r-124")));
|
||||
Assert.assertEquals(node3, router.getAssignedNode(newRequest("r-125")));
|
||||
|
||||
router.removeNode(node1);
|
||||
|
||||
Assert.assertEquals(node2, router.getAssignedNode(newRequest("r-125")));
|
||||
Assert.assertEquals(node3, router.getAssignedNode(newRequest("r-126")));
|
||||
Assert.assertEquals(node2, router.getAssignedNode(newRequest("r-127")));
|
||||
Assert.assertEquals(node3, router.getAssignedNode(newRequest("r-128")));
|
||||
|
||||
final Node node4 = new Node("node-4", ipAddress, 2);
|
||||
router.addNode(node4);
|
||||
|
||||
Assert.assertEquals(node4, router.getAssignedNode(newRequest("r-129")));
|
||||
Assert.assertEquals(node4, router.getAssignedNode(newRequest("r-130")));
|
||||
Assert.assertEquals(node2, router.getAssignedNode(newRequest("r-131")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultConsistentHashing() {
|
||||
final List<Long> hashes = new ArrayList<>();
|
||||
hashes.add(1L);
|
||||
hashes.add(11L);
|
||||
hashes.add(21L);
|
||||
hashes.add(31L);
|
||||
final Function<String, Long> hashFunction = id -> {
|
||||
if (id.contains("000000")) {
|
||||
return hashes.remove(0);
|
||||
} else {
|
||||
return Long.parseLong(id);
|
||||
}
|
||||
};
|
||||
final Router router = new ConsistentHashing(hashFunction, 1);
|
||||
final Node node1 = newNode("1000000"), node2 = newNode("2000000"), node3 = newNode("3000000");
|
||||
router.addNode(node1);
|
||||
router.addNode(node2);
|
||||
router.addNode(node3);
|
||||
|
||||
Assert.assertEquals(node1, router.getAssignedNode(newRequest("35")));
|
||||
Assert.assertEquals(node2, router.getAssignedNode(newRequest("5")));
|
||||
Assert.assertEquals(node3, router.getAssignedNode(newRequest("15")));
|
||||
|
||||
router.removeNode(node1);
|
||||
|
||||
Assert.assertEquals(node2, router.getAssignedNode(newRequest("22")));
|
||||
Assert.assertEquals(node3, router.getAssignedNode(newRequest("12")));
|
||||
Assert.assertEquals(node2, router.getAssignedNode(newRequest("23")));
|
||||
Assert.assertEquals(node3, router.getAssignedNode(newRequest("13")));
|
||||
|
||||
final Node node4 = newNode("4000000");
|
||||
router.addNode(node4);
|
||||
|
||||
Assert.assertEquals(node4, router.getAssignedNode(newRequest("25")));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void consistentHashingConstruction() {
|
||||
new ConsistentHashing(Long::valueOf, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void consistentHashingWithWeights() {
|
||||
final List<Long> hashes = new ArrayList<>();
|
||||
hashes.add(1L); // remaining is node 1
|
||||
hashes.add(21L); // 12 to 21 is for node 1
|
||||
hashes.add(11L); // 2 to 11 is for node 2
|
||||
hashes.add(41L); // 32 to 41 is for node 2
|
||||
hashes.add(31L); // 22 to 31 is for node 3
|
||||
hashes.add(51L); // 42 to 51 is for node 3 --> 10 points
|
||||
final Function<String, Long> hashFunction = id -> {
|
||||
//range should be (0, 60)
|
||||
if (id.contains("000000")) {
|
||||
return hashes.remove(0);
|
||||
} else {
|
||||
return Long.parseLong(id);
|
||||
}
|
||||
};
|
||||
final Router router = new ConsistentHashing(hashFunction, 2);
|
||||
final Node node1 = newNode("1000000"), node2 = newNode("2000000"), node3 = newNode("3000000");
|
||||
router.addNode(node1);
|
||||
router.addNode(node2);
|
||||
router.addNode(node3);
|
||||
|
||||
Assert.assertEquals(node1, router.getAssignedNode(newRequest("55")));
|
||||
Assert.assertEquals(node1, router.getAssignedNode(newRequest("15")));
|
||||
Assert.assertEquals(node2, router.getAssignedNode(newRequest("8")));
|
||||
Assert.assertEquals(node2, router.getAssignedNode(newRequest("33")));
|
||||
Assert.assertEquals(node3, router.getAssignedNode(newRequest("28")));
|
||||
Assert.assertEquals(node3, router.getAssignedNode(newRequest("47")));
|
||||
|
||||
router.removeNode(node1);
|
||||
// remaining is node 2
|
||||
// 12 to 21 is now for node 3
|
||||
Assert.assertEquals(node2, router.getAssignedNode(newRequest("58")));
|
||||
Assert.assertEquals(node3, router.getAssignedNode(newRequest("12")));
|
||||
Assert.assertEquals(node3, router.getAssignedNode(newRequest("23")));
|
||||
Assert.assertEquals(node2, router.getAssignedNode(newRequest("54")));
|
||||
|
||||
final Node node4 = newNode("4000000");
|
||||
hashes.add(6L); // 0 to 6 is for node 4, 52 to remaining is for node 4
|
||||
hashes.add(26L); // 12 to 26 is for node 4
|
||||
router.addNode(node4);
|
||||
|
||||
Assert.assertEquals(node4, router.getAssignedNode(newRequest("15")));
|
||||
Assert.assertEquals(node4, router.getAssignedNode(newRequest("59")));
|
||||
Assert.assertEquals(node4, router.getAssignedNode(newRequest("5")));
|
||||
}
|
||||
|
||||
private Request newRequest(String s) {
|
||||
return new Request(s, serviceId, method);
|
||||
}
|
||||
|
||||
private Node newNode(String s) {
|
||||
return new Node(s, ipAddress);
|
||||
}
|
||||
}
|
BIN
service-orchestrator/target/classes/LoadBalancer.class
Normal file
BIN
service-orchestrator/target/classes/LoadBalancer.class
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
service-orchestrator/target/classes/algorithms/Router.class
Normal file
BIN
service-orchestrator/target/classes/algorithms/Router.class
Normal file
Binary file not shown.
Binary file not shown.
BIN
service-orchestrator/target/classes/models/Node.class
Normal file
BIN
service-orchestrator/target/classes/models/Node.class
Normal file
Binary file not shown.
BIN
service-orchestrator/target/classes/models/Request.class
Normal file
BIN
service-orchestrator/target/classes/models/Request.class
Normal file
Binary file not shown.
BIN
service-orchestrator/target/classes/models/Service.class
Normal file
BIN
service-orchestrator/target/classes/models/Service.class
Normal file
Binary file not shown.
BIN
service-orchestrator/target/test-classes/LBTester.class
Normal file
BIN
service-orchestrator/target/test-classes/LBTester.class
Normal file
Binary file not shown.
Binary file not shown.
BIN
service-orchestrator/target/test-classes/RouterTester.class
Normal file
BIN
service-orchestrator/target/test-classes/RouterTester.class
Normal file
Binary file not shown.
Reference in New Issue
Block a user