Vert.x
Node for the JVM
WHOAMI
Ryan Applegate
@rappleg
https://github.com/rappleg
Developer @ SmartThings
Grails Developer - 4+ years
Java Background - 7 years
What is Node?
Server Side Javascript
Event Driven Non-Blocking I/O
Single thread/single event loopApplication registers handlersEvents trigger handlersEverything runs on the event loop
Node is Not Web Scale
Why Vert.x?
Same event-driven non-blocking IO programming model as Node
Polyglot (Groovy, Ruby, Java, Javascript, Python, Scala and Clojure coming soon)Mature concurrency framework (JVM)Hazelcast for Clustering
Interprocess Communication via Event Bus
Asynchronous & Effortlessly Scalable
Vert.x Caveat
Benchmark #1
Benchmark #2
Verticle
Vert.x Instance
-instances 4
Running Vert.x Server
vertx.createHttpServer().requestHandler { req ->
def file = req.uri == "/" ? "index.html" : req.uri
req.response.sendFile "webroot/$file"
}.listen(8080)
vertx run Server.groovy
vertx run Server.groovy -instances 32
Running Vert.x Server (runmod)
vertx runmod server-mod -instances 32
Concurrency
Event Bus Addressing
Handler Registration
Handler Registration
def eb = vertx.eventBus()
eb.registerHandler("test.address") { message ->
println "I received a message ${message.body}"
}
Pub/Sub
Pub/Sub
Deliver single message to all handlers registered at an address
eb.publish("test.address", "hello world")
P2P
P2P
Deliver message to only one handler registered at an address
eb.send("test.address", "hello world")
P2P Messaging Options
Implement replyHandler for messages
Sender
eb.send("test.address", "Some message") { message ->
println "I received a reply ${message.body}"
}
Receiver
eb.registerHandler("test.address") { message ->
println "I received a message ${message.body}"
// Do some work here
message.reply("Some reply")
}
Message Types
- String
- Primitives
- Boxed Primitives
- Boolean
- java.util.map - representing JSON
- org.vertx.java.core.JsonObject
- org.vertx.java.core.Buffer
Vert.x in the Browser
SockJS Server
def server = vertx.createHttpServer()
server.requestHandler { req ->
if (req.uri == "/")
req.response.sendFile("index.html")
if (req.uri.endsWith("vertxbus.js"))
req.response.sendFile("vertxbus.js")
}.listen(8080)
def sockJSServer = vertx.createSockJSServer(server)
sockJSServer.bridge( { prefix: "/eventBus"} )
server.listen(8080)
SockJS Client
<script src="http://cdn.sockjs.org/sockjs-0.2.1.min.js"></script>
<script src="vertxbus.js"></script>
<script>
var eb = new vertx.EventBus('http://localhost:8080/eventBus')
eb.onopen = function() {
eb.registerHandler('msgs.echo', function(message) {
alert('Echoing msg: ' + JSON.stringify(message))
});
}
WebSockets on the Server
def server = vertx.createHttpServer()
server.websocketHandler{ ws ->
println "A websocket has connected!"
}.listen(8080, "localhost")
Rejecting WebSockets
def server = vertx.createHttpServer()
server.websocketHandler{ ws ->
if (ws.path == "/services/echo") {
Pump.createPump(ws, ws).start()
} else {
ws.reject()
}
}.listen(8080, "localhost")
WebSockets on the HTTP Client
def client = vertx.createHttpClient()
client.connectWebsocket("http://localhost:8080/some-uri") { ws ->
// Connected!
}
WebSockets in the browser
<script>
var socket = new WebSocket("ws://localhost:8080/services/echo");
socket.onmessage = function(event) {
alert("Received data from websocket: " + event.data);
}
socket.onopen = function(event) {
alert("Web Socket opened");
socket.send("Hello World");
};
socket.onclose = function(event) {
alert("Web Socket closed");
};
</script>
Vert.x Shared State
Allowed Values
- Strings
- Boxed Primitives
- byte[]
- org.vertx.java.core.buffer.Buffer
-
org.vertx.java.core.shareddata.Shareable
Shared Map
Verticle 1
def map = vertx.sharedData.getMap('demo.mymap')
map["some-key"] = 123
Verticle 2
def map = vertx.sharedData.getMap('demo.mymap')
// Retrieve value 123 from the map
def value = map."some-key"
Shared Set
Verticle 1
def set = vertx.sharedData.getSet('demo.myset')
set << "some-value"
Verticle 2
def set = vertx.sharedData.getSet('demo.myset')
// Set will now contain some-value
set.contains("some-value")
Reactor Pattern Issues
- MUST not block the event loop
-
Some work is natually blocking
- Intensive data crunching
- 3rd-party blocking API's (e.g. JDBC, etc...)
-
Node.js is not good for this type of work
Worker Verticle Example
public class FibWorker extends Verticle {
@Override
public void start() {
def eb = vertx.eventBus()
eb.registerHandler("fib.request") { message ->
def result = fib(message.body.intValue())
def resultMessage = { nbr: message.body,
result: result }
eb.send("fib.response", resultMessage)
}
}
def fib(n) { n < 2 ? 1 : fib(n-1) + fib(n-2) }
}
Verticle (Running on Event Loop)
public class WorkerExample extends Verticle {
@Override
public void start() {
def eb = vertx.eventBus()
eb.registerHandler("fib.response") { msg ->
println "Fib:${msg.body.nbr}=${msg.body.result}"
}
container.deployWorkerVerticle("worker.FibWorker")
{ msg ->
eb.send("fib.request", 20)
}
}
}
More stuff with Vert.x Core APIs
- TCP/SSL servers and clients
- HTTP/HTTPS servers and clients
- WebSockets servers and clients
- Accessing the distributed event bus
- Periodic and one-off timers
- Buffers
- Flow control
- Accessing files on the file system
- Shared map and sets
- Logging
- Accessing configuration
- Writing SockJS servers
-
Deploying and undeploying verticles
How do I contribute to Vert.x?
How does SmartThings use Vert.x?
SmartThings Vert.x Throughput
~6 million events/day from hubs to Vert.x
Vert.x Common Mistake
vertx.createHttpServer(someHttpServerConfig).requestHandler { request ->
def responseString = "ERROR" try { // Do some stuff with the request responseString = "OK" } catch (Exception e) {
responseString = "ERROR (${e.getClass().name})"
} finally {
request.response.end("${responseString}") } }.listen(someHttpServerConfig.port)
Resources
VERT.X
By rappleg
VERT.X
- 7,541