Created
June 10, 2015 07:01
-
-
Save spinscale/74a3f2f8fa4c99539998 to your computer and use it in GitHub Desktop.
Undertow + jgroups-raft example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<config xmlns="urn:org:jgroups" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="urn:org:jgroups http://www.jgroups.org/schema/jgroups.xsd"> | |
<UDP | |
mcast_addr="224.5.5.5" | |
mcast_port="${jgroups.udp.mcast_port:45588}" | |
bind_interface="en0" | |
diagnostics_bind_interfaces="en0" | |
receive_interfaces="en0"/> | |
<PING /> | |
<MERGE3 /> | |
<FD_SOCK/> | |
<FD_ALL/> | |
<VERIFY_SUSPECT timeout="1500" /> | |
<pbcast.NAKACK2 xmit_interval="500" | |
discard_delivered_msgs="true"/> | |
<UNICAST3 xmit_interval="500" | |
max_msg_batch_size="500"/> | |
<pbcast.STABLE desired_avg_gossip="50000" | |
max_bytes="4M"/> | |
<raft.NO_DUPES/> 1 | |
<pbcast.GMS print_local_addr="true" join_timeout="2000" | |
view_bundling="true"/> | |
<UFC max_credits="2M" min_threshold="0.4"/> | |
<MFC max_credits="2M" min_threshold="0.4"/> | |
<FRAG2 frag_size="60K" /> | |
<raft.ELECTION election_min_interval="100" election_max_interval="500"/> 2 | |
<raft.RAFT members="A,B,C" raft_id="${raft_id:undefined}"/> | |
<raft.REDIRECT/> 4 | |
<raft.CLIENT bind_addr="0.0.0.0" /> 5 | |
</config> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
echo ; echo ; echo "Setting /foo/bar" | |
curl -v -X PUT 127.0.0.1:8080/cluster/foo/bar | |
# wait for consensus | |
sleep 2 | |
echo ; echo ; echo "Getting /foo/bar" | |
curl -X GET 127.0.0.1:8081/cluster/foo | |
echo ; echo ; echo "Deleting /foo/bar" | |
curl -v -X DELETE 127.0.0.1:8082/cluster/foo | |
echo ; echo ; echo "Getting /foo/bar" | |
curl -v -X GET 127.0.0.1:8080/cluster/foo | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package de.spinscale.cluster; | |
import io.undertow.Undertow; | |
import io.undertow.server.handlers.PathTemplateHandler; | |
import io.undertow.util.HttpString; | |
import io.undertow.util.PathTemplateMatch; | |
import org.jgroups.JChannel; | |
import org.jgroups.raft.RaftHandle; | |
import org.jgroups.raft.blocks.ReplicatedStateMachine; | |
public class Webserver { | |
public static class RaftNode { | |
ReplicatedStateMachine<String, String> rsm; | |
public RaftNode(String id) throws Exception { | |
JChannel ch = new JChannel("src/main/resources/raft.xml"); | |
rsm = new ReplicatedStateMachine<>(ch); | |
RaftHandle handle = new RaftHandle(ch, rsm); | |
handle.raftId(id); | |
ch.connect("raft-cluster"); | |
} | |
public String get(String key) { | |
return rsm.get(key); | |
} | |
public void put(String key, String value) throws Exception { | |
rsm.put(key, value); | |
} | |
public void remove(String key) throws Exception { | |
rsm.remove(key); | |
} | |
public boolean exists(String key) { | |
return get(key) != null; | |
} | |
} | |
public static class UndertowServer { | |
private final Undertow server; | |
public UndertowServer(int port, final RaftNode raftNode) { | |
PathTemplateHandler handler = new PathTemplateHandler(); | |
handler.add("/cluster/{key}/{value}", exchange -> { | |
PathTemplateMatch attachment = exchange.getAttachment(PathTemplateMatch.ATTACHMENT_KEY); | |
String key = attachment.getParameters().get("key"); | |
String value = attachment.getParameters().get("value"); | |
if (exchange.getRequestMethod().equals(HttpString.tryFromString("PUT"))) { | |
raftNode.put(key, value); | |
exchange.setResponseCode(200); | |
} | |
}); | |
handler.add("/cluster/{key}", exchange -> { | |
PathTemplateMatch attachment = exchange.getAttachment(PathTemplateMatch.ATTACHMENT_KEY); | |
String key = attachment.getParameters().get("key"); | |
if (!raftNode.exists(key)) { | |
exchange.setResponseCode(404); | |
} else { | |
exchange.setResponseCode(200); | |
if (exchange.getRequestMethod().equals(HttpString.tryFromString("GET"))) { | |
exchange.getResponseSender().send(raftNode.get(key)); | |
} else if (exchange.getRequestMethod().equals(HttpString.tryFromString("DELETE"))) { | |
raftNode.remove(key); | |
} | |
} | |
}); | |
server = Undertow.builder() | |
.addHttpListener(port, "localhost") | |
.setHandler(handler) | |
.build(); | |
} | |
public UndertowServer start() { | |
server.start(); | |
return this; | |
} | |
} | |
public static void main(String[] args) { | |
System.setProperty("java.net.preferIPv4Stack", "true"); // osx prefers ipv6 | |
try { | |
new UndertowServer(8080, new RaftNode("A")).start(); | |
new UndertowServer(8081, new RaftNode("B")).start(); | |
new UndertowServer(8082, new RaftNode("C")).start(); | |
} catch (Exception e) { | |
throw new RuntimeException(e); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment