What is Node?
Server Side Javascript
Event Driven Non-Blocking I/O
Single thread/single event loop
Application registers handlers
Events trigger handlers
Everything runs on the event loop
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
Built on Netty and NIO2 for Network I/O
MUST be running Java 7
Benchmark #1
Verticle
The unit of deployment in vert.x is called a verticle (think of a particle, for vert.x). Verticles can currently be written in JavaScript, Ruby, Java, or Groovy
A verticle is defined by having a main which is just the script (or class in the case of Java) to run to start the verticle.
Vert.x Instance
Event Loops
Verticle
Verticle
Verticle
Verticle
vertx run HelloWorld
-instances 4
Running Vert.x Server
Server.groovy
vertx.createHttpServer().requestHandler { req ->
def file = req.uri == "/" ? "index.html" : req.uri
req.response.sendFile "webroot/$file"
}.listen(8080)
Start the server
Utilize more cores, up your instances...
vertx run Server.groovy -instances 32
Running Vert.x Server (runmod)
No need to specify your classpath everytime to use additional classes in your verticle implementations
Package your application as a module
vertx runmod server-mod -instances 32
Concurrency
Verticle instance ALWAYS executes on assigned thread/event loop.
Verticles have isolated classloaders and cannot share global state.
Write all your code as single threaded.
No more synchronized and volatile!
Verticle
Verticle
Verticle
Verticle
Event Bus Addressing
Address simply a String
Dot-style namespacing recommended
"messages.inbound.foo"
Handler Registration
Handler 1
Handler 2
Handler 3
messages.inbound.foo
Handler Registration
def eb = vertx.eventBus()
eb.registerHandler("test.address") { message ->
println "I received a message ${message.body}"
}
Pub/Sub
Deliver single message to all handlers registered at an address
Handler 1
Handler 2
Handler 3
Sender
messages.inbound.foo
Pub/Sub
Deliver single message to all handlers registered at an address
eb.publish("test.address", "hello world")
P2P
Deliver message to only one handler registered at an address
Handler 1
Handler 2
Handler 3
Sender
messages.inbound.foo
P2P
Deliver message to only one handler registered at an address
eb.send("test.address", "hello world")
P2P Messaging Options
Send (Fire and Forget)
Request/Reply Model
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
Clustered along with Vert.x instances using HazelCast
SockJS - Older browsers/Corp Proxy
Talk to event bus through SockJS Bridge
WebSockets - HTML 5 feature that allows a full duplex between HTTP servers
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
Shared Data Object (vertx.sharedData())
ConcurrentMap or Set
Elements MUST be immutable values
Currently only available within a Vertx instance, not across the cluster
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
Verticle
Verticle
Verticle
Verticle
Worker Verticle
Worker Verticle
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?
IRC: irc://freenode.net/vertx
No support for the language you want to use?
Write a language handler for it and submit a pull request
Add more examples, modules, or update documentation
How does SmartThings use Vert.x?
Hubs/Clients need to maintain always open socket
amqp bus mode to push/pull events to/from Rabbit MQ
Event Bus to get messages to the right socket
SmartThings Vert.x Throughput
~6 million events/day from hubs to Vert.x
~70 events/second
Cluster of 3 Vert.x instances
Primary reason is stability, not throughput
Mirrored on ios and android clients
Vert.x Common Mistake
Once you have finished with the HTTP response you must call the end() method on it.
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
web scale picture reference (watch video here)
Questions?
Slides Available