Ленок Антон_Реактивное программирование на Vertx.key

153
Реактивное программирование на Vert.x

Transcript of Ленок Антон_Реактивное программирование на Vertx.key

Реактивное программирование на Vert.x

Диалоги в Сбербанк Онлайн

Ленок АнтонСерверная разработка

Проект: Диалоги в Сбербанк Онлайн

[email protected]

Задача

Прием и отправка сообщений

Скорость отправки > приёма сообщения <1 секунды

В начале 10 человек онлайн

Целевое 100 000 человек онлайн

Быстрое добавление функций

Решение

WebSocket

Общая шина на сервере

Vert.x описание

Создатель Тим Фокс

Встроенная общая шина

Абстракция над Java Concurrency

Реактивный

Полиглот для языков JVM

Java

JavaScript

Ruby

Groovy

Scala

Kotlin

На чем фокусируемся

Принципы реактивного программирования

Vert.x

Kubernetes

Mongo DB

Подробно: Не концентрируемся:

Handler

Реактивное программирование

Event Queue

Event loop

while (true) { getNewEvent(); findHandler(); callHandler(); }

Handler

Handler

Handler

Multi-Reactor

Event Queue

Event loop

while (true) { getNewEvent(); findHandler(); callHandler(); }

Handler

Handler

Первое приложение

import io.vertx.core.AbstractVerticle; import io.vertx.core.eventbus.Message;

public class HelloVerticle extends AbstractVerticle {

@Override public void start() {

vertx.eventBus().consumer("greetings", this::hello);

vertx.eventBus().publish("greetings", "My first message"); }

private void hello(Message<String> data) { String message = data.body(); System.out.println(message); } }

1 / 9

Первое приложение

import io.vertx.core.AbstractVerticle; import io.vertx.core.eventbus.Message;

public class HelloVerticle extends AbstractVerticle {

@Override public void start() {

vertx.eventBus().consumer("greetings", this::hello);

vertx.eventBus().publish("greetings", "My first message"); }

private void hello(Message<String> data) { String message = data.body(); System.out.println(message); } }

2 / 9

Первое приложение

import io.vertx.core.AbstractVerticle; import io.vertx.core.eventbus.Message;

public class HelloVerticle extends AbstractVerticle {

@Override public void start() {

vertx.eventBus().consumer("greetings", this::hello);

vertx.eventBus().publish("greetings", "My first message"); }

private void hello(Message<String> data) { String message = data.body(); System.out.println(message); } }

3 / 9

Первое приложение

import io.vertx.core.AbstractVerticle; import io.vertx.core.eventbus.Message;

public class HelloVerticle extends AbstractVerticle {

@Override public void start() {

vertx.eventBus().consumer("greetings", this::hello);

vertx.eventBus().publish("greetings", "My first message"); }

private void hello(Message<String> data) { String message = data.body(); System.out.println(message); } }

4 / 9

import io.vertx.core.AbstractVerticle; import io.vertx.core.eventbus.Message;

public class HelloVerticle extends AbstractVerticle {

@Override public void start() {

vertx.eventBus().consumer("greetings", this::hello);

vertx.eventBus().publish("greetings", "My first message"); }

private void hello(Message<String> data) { String message = data.body(); System.out.println(message); } }

Первое приложение

5 / 9

import io.vertx.core.AbstractVerticle; import io.vertx.core.eventbus.Message;

public class HelloVerticle extends AbstractVerticle {

@Override public void start() {

vertx.eventBus().consumer("greetings", this::hello);

vertx.eventBus().publish("greetings", "My first message"); }

private void hello(Message<String> data) { String message = data.body(); System.out.println(message); } }

Первое приложение

6 / 9

import io.vertx.core.AbstractVerticle; import io.vertx.core.eventbus.Message;

public class HelloVerticle extends AbstractVerticle {

@Override public void start() {

vertx.eventBus().consumer("greetings", this::hello);

vertx.eventBus().publish("greetings", "My first message"); }

private void hello(Message<String> data) { String message = data.body(); System.out.println(message); } }

Первое приложение

7 / 9

import io.vertx.core.Vertx; import org.example.verticle.HelloVerticle;

public class Starter {

public static void main(String[] args) { Vertx.vertx().deployVerticle(new HelloVerticle()); } }

Первое приложение

8 / 9

import io.vertx.core.Vertx; import org.example.verticle.HelloVerticle;

public class Starter {

public static void main(String[] args) { Vertx.vertx().deployVerticle(new HelloVerticle()); } }

Первое приложение

9 / 9

Научились

Первое приложение

1 / 8

Блокирующие операции

Event Queue

Handler

Event loop

while (true) { getNewEvent(); findHandler(); callHandler(); }

Handler

vertx.eventBus().consumer("block", this::blockingCode);

void blockingCode(Message<String> m) { for (long i = 0; i < Long.MAX_VALUE; i++) ; }

Блокирующие операции

1 / 3

vertx.eventBus().consumer("block", this::blockingCode);

void blockingCode(Message<String> m) { vertx.executeBlocking(future -> { for (long i = 0; i < Long.MAX_VALUE; i++) ; future.complete("ok"); }, res -> System.out.println(res.result())); }

Блокирующие операции

2 / 3

vertx.eventBus().consumer("block", this::blockingCode);

void blockingCode(Message<String> m) { vertx.executeBlocking(future -> { for (long i = 0; i < Long.MAX_VALUE; i++) ; future.complete("ok"); }, res -> System.out.println(res.result())); }

Блокирующие операции

3 / 3

Научились

Первое приложение

Блокирующие операции

2 / 8

{ "text" : "Hello", "address": "nickname" }

Протокол

Клиент

var socket = new WebSocket( 'ws://HOST/token/ADDRESS' )

Клиент

socket.send( '{"text" :"Hello", "address":"receiver"}' )

Общая шина v1.0

Event Bus

WebSocket Push message

WebSocket Get message

public class WsServerVerticle extends AbstractVerticle { @Override public void start() { vertx.createHttpServer() .websocketHandler(this::createWebSocketServer) .listen(8080); } }

1 / 20

Отправкасообщений

@Override public void start() { vertx.createHttpServer() .websocketHandler(this::createWebSocketServer) .listen(8080); }

2 / 20

Отправкасообщений

@Override public void start() { vertx.createHttpServer() .websocketHandler(this::createWebSocketServer) .listen(8080); }

3 / 20

Отправкасообщений

@Override public void start() { vertx.createHttpServer() .websocketHandler(this::createWebSocketServer) .listen(8080); }

4 / 20

Отправкасообщений

@Override public void start() { vertx.createHttpServer() .websocketHandler(this::createWebSocketServer) .listen(8080); }void createWebSocketServer (ServerWebSocket wsServer) { }

5 / 20

Отправкасообщений

void createWebSocketServer(ServerWebSocket wsServer) { vertx.eventBus().<String>consumer(wsServer.path(), data -> { wsServer.writeFinalTextFrame(data.body()); data.reply("ok"); }); }

6 / 20

Отправкасообщений

void createWebSocketServer(ServerWebSocket wsServer) { vertx.eventBus().<String>consumer(wsServer.path(), data -> { wsServer.writeFinalTextFrame(data.body()); data.reply("ok"); }); }

7 / 20

Отправкасообщений

var socket = new WebSocket( 'ws://HOST/token/ADDRESS' )

8 / 20

Отправкасообщений

9 / 20

void createWebSocketServer(ServerWebSocket wsServer) { vertx.eventBus().<String>consumer(wsServer.path(), data -> { wsServer.writeFinalTextFrame(data.body()); data.reply("ok"); }); }

Отправкасообщений

10 / 20

void createWebSocketServer(ServerWebSocket wsServer) { vertx.eventBus().<String>consumer(wsServer.path(), data -> { wsServer.writeFinalTextFrame(data.body()); data.reply("ok"); }); }

Отправкасообщений

11 / 20

void createWebSocketServer(ServerWebSocket wsServer) { vertx.eventBus().<String>consumer(wsServer.path(), data -> { wsServer.writeFinalTextFrame(data.body()); data.reply("ok"); }); }

Отправкасообщений

@Override public void start() { vertx.createHttpServer() .websocketHandler(this::createWebSocketServer) .listen(8080); }

void createWebSocketServer (ServerWebSocket wsServer) { }

12 / 20

Приемсообщений

Приемсообщений

13 / 20

void createWebSocketServer(ServerWebSocket wsServer) { wsServer.frameHandler(wsFrame -> { Data data = Json.decodeValue(wsFrame.textData(), Data.class); String token = "/token/" + data.getAddress(); vertx.eventBus().publish( token, wsFrame.textData()); }); }

14 / 20

Приемсообщений

void createWebSocketServer(ServerWebSocket wsServer) { wsServer.frameHandler(wsFrame -> { Data data = Json.decodeValue(wsFrame.textData(), Data.class); String token = "/token/" + data.getAddress(); vertx.eventBus().publish( token, wsFrame.textData()); }); }

15 / 20

Приемсообщений

void createWebSocketServer(ServerWebSocket wsServer) { wsServer.frameHandler(wsFrame -> { Data data = Json.decodeValue(wsFrame.textData(), Data.class); String token = "/token/" + data.getAddress(); vertx.eventBus().publish( token, wsFrame.textData()); }); }

16 / 20

Приемсообщений

{ "text" : "Hello", "address": "nickname" }

17 / 20

Приемсообщений

void createWebSocketServer(ServerWebSocket wsServer) { wsServer.frameHandler(wsFrame -> { Data data = Json.decodeValue(wsFrame.textData(), Data.class); String token = "/token/" + data.getAddress(); vertx.eventBus().publish( token, wsFrame.textData()); }); }

18 / 20

Приемсообщений

void createWebSocketServer(ServerWebSocket wsServer) { wsServer.frameHandler(wsFrame -> { Data data = Json.decodeValue(wsFrame.textData(), Data.class); String token = "/token/" + data.getAddress(); vertx.eventBus().publish( token, wsFrame.textData()); }); }

Приемсообщений

19 / 20

void createWebSocketServer(ServerWebSocket wsServer) { vertx.eventBus().<String>consumer(wsServer.path(), data -> { wsServer.writeFinalTextFrame(data.body()); data.reply("ok"); }); }

Demo

20 / 20Приемсообщений

Научились

Первое приложение

Блокирующие операции

WebSocket

3 / 8

Общая шина v2.0

Event Bus

WebSocket Push message

WebSocket Get message

Router

Маршрутизатор

void createWebSocketServer(ServerWebSocket wsServer) { wsServer.frameHandler(wsFrame -> { Data data = Json.decodeValue(wsFrame.textData(), Data.class); String token = "/token/" + data.getAddress(); vertx.eventBus().publish( token, wsFrame.textData()); }); }

1 / 9

2 / 9Маршрутизатор

void createWebSocketServer(ServerWebSocket wsServer) { wsServer.frameHandler(wsFrame -> {

vertx.eventBus().publish( "router", wsFrame.textData()); }); }

3 / 9Маршрутизатор

public class RouterVerticle extends AbstractVerticle { @Override public void start() { vertx.eventBus().consumer("router", this::router); }

void router(Message<String> message) { Data data = Json.decodeValue(message.body(), Data.class); vertx.eventBus().publish( "/token/" + data.getAddress(), message.body()); } }

4 / 9Маршрутизатор

public class RouterVerticle extends AbstractVerticle { @Override public void start() { vertx.eventBus().consumer("router", this::router); }

void router(Message<String> message) { Data data = Json.decodeValue(message.body(), Data.class); vertx.eventBus().publish( "/token/" + data.getAddress(), message.body()); } }

5 / 9Маршрутизатор

public class RouterVerticle extends AbstractVerticle { @Override public void start() { vertx.eventBus().consumer("router", this::router); }

void router(Message<String> message) { Data data = Json.decodeValue(message.body(), Data.class); vertx.eventBus().publish( "/token/" + data.getAddress(), message.body()); } }

6 / 9Маршрутизатор

void createWebSocketServer(ServerWebSocket wsServer) { wsServer.frameHandler(wsFrame -> {

vertx.eventBus().publish( "router", wsFrame.textData()); }); }

7 / 9Маршрутизатор

public class RouterVerticle extends AbstractVerticle { @Override public void start() { vertx.eventBus().consumer("router", this::router); }

void router(Message<String> message) { Data data = Json.decodeValue(message.body(), Data.class); vertx.eventBus().publish( "/token/" + data.getAddress(), message.body()); } }

8 / 9Маршрутизатор

public class RouterVerticle extends AbstractVerticle { @Override public void start() { vertx.eventBus().consumer("router", this::router); }

void router(Message<String> message) { Data data = Json.decodeValue(message.body(), Data.class); vertx.eventBus().publish( "/token/" + data.getAddress(), message.body()); } }

9 / 9Маршрутизатор

void createWebSocketServer(ServerWebSocket wsServer) { vertx.eventBus().<String>consumer(wsServer.path(), data -> { wsServer.writeFinalTextFrame(data.body()); data.reply("ok"); }); }

Продумывайтемаршруты

Научились

Первое приложение

Блокирующие операции

WebSocket

Путь сообщения

4 / 8

Общая шина v2.1

WebSocket Get message

Event Bus

WebSocket Push message

REST Push history

Router

Rest-клиент

curl \ -H "Content-Type: application/json" \ -X POST -d \ '{"text":"Message","address":"token"}' \ http://HOST/sendMessage

Отправкасообщений по REST

public class RestServerVerticle extends AbstractVerticle { @Override public void start() { } }

1 / 13

Отправкасообщений по REST

public class RestServerVerticle extends AbstractVerticle { @Override public void start() { } }

2 / 13

Отправкасообщений по REST

@Override public void start() { HttpServer httpServer = vertx.createHttpServer(); Router httpRouter = Router.router(vertx); httpRouter.route().handler(BodyHandler.create()); httpRouter.post("/sendMessage") .handler(request -> { vertx.eventBus().publish("router", request.getBodyAsString()); request.response().end("ok"); }); httpServer.requestHandler(httpRouter::accept); httpServer.listen(8081); }

3 / 13

Отправкасообщений по REST

@Override public void start() { HttpServer httpServer = vertx.createHttpServer(); Router httpRouter = Router.router(vertx); httpRouter.route().handler(BodyHandler.create()); httpRouter.post("/sendMessage") .handler(request -> { vertx.eventBus().publish("router", request.getBodyAsString()); request.response().end("ok"); }); httpServer.requestHandler(httpRouter::accept); httpServer.listen(8081); }

4 / 13

Отправкасообщений по REST

@Override public void start() { HttpServer httpServer = vertx.createHttpServer(); Router httpRouter = Router.router(vertx); httpRouter.route().handler(BodyHandler.create()); httpRouter.post("/sendMessage") .handler(request -> { vertx.eventBus().publish("router", request.getBodyAsString()); request.response().end("ok"); }); httpServer.requestHandler(httpRouter::accept); httpServer.listen(8081); }

5 / 13

Отправкасообщений по REST

@Override public void start() { HttpServer httpServer = vertx.createHttpServer(); Router httpRouter = Router.router(vertx); httpRouter.route().handler(BodyHandler.create()); httpRouter.post("/sendMessage") .handler(request -> { vertx.eventBus().publish("router", request.getBodyAsString()); request.response().end("ok"); }); httpServer.requestHandler(httpRouter::accept); httpServer.listen(8081); }

6 / 13

Отправкасообщений по REST

@Override public void start() { HttpServer httpServer = vertx.createHttpServer(); Router httpRouter = Router.router(vertx); httpRouter.route().handler(BodyHandler.create()); httpRouter.post("/sendMessage") .handler(request -> { vertx.eventBus().publish("router", request.getBodyAsString()); request.response().end("ok"); }); httpServer.requestHandler(httpRouter::accept); httpServer.listen(8081); }

7 / 13

Отправкасообщений по REST

@Override public void start() { HttpServer httpServer = vertx.createHttpServer(); Router httpRouter = Router.router(vertx); httpRouter.route().handler(BodyHandler.create()); httpRouter.post("/sendMessage") .handler(request -> { vertx.eventBus().publish("router", request.getBodyAsString()); request.response().end("ok"); }); httpServer.requestHandler(httpRouter::accept); httpServer.listen(8081); }

8 / 13

Отправкасообщений по REST

@Override public void start() { HttpServer httpServer = vertx.createHttpServer(); Router httpRouter = Router.router(vertx); httpRouter.route().handler(BodyHandler.create()); httpRouter.post("/sendMessage") .handler(request -> { vertx.eventBus().publish("router", request.getBodyAsString()); request.response().end("ok"); }); httpServer.requestHandler(httpRouter::accept); httpServer.listen(8081); }

9 / 13

Отправкасообщений по REST

@Override public void start() { HttpServer httpServer = vertx.createHttpServer(); Router httpRouter = Router.router(vertx); httpRouter.route().handler(BodyHandler.create()); httpRouter.post("/sendMessage") .handler(request -> { vertx.eventBus().publish("router", request.getBodyAsString()); request.response().end("ok"); }); httpServer.requestHandler(httpRouter::accept); httpServer.listen(8081); }

10 / 13

Отправкасообщений по REST

@Override public void start() { HttpServer httpServer = vertx.createHttpServer(); Router httpRouter = Router.router(vertx); httpRouter.route().handler(BodyHandler.create()); httpRouter.post("/sendMessage") .handler(request -> { vertx.eventBus().publish("router", request.getBodyAsString()); request.response().end("ok"); }); httpServer.requestHandler(httpRouter::accept); httpServer.listen(8081); }

11 / 13

Отправкасообщений по REST

@Override public void start() { HttpServer httpServer = vertx.createHttpServer(); Router httpRouter = Router.router(vertx); httpRouter.route().handler(BodyHandler.create()); httpRouter.post("/sendMessage") .handler(request -> { vertx.eventBus().publish("router", request.getBodyAsString()); request.response().end("ok"); }); httpServer.requestHandler(httpRouter::accept); httpServer.listen(8081); }

12 / 13

Demo

13 / 13

Отправкасообщений по REST

Первое приложение

Блокирующие операции

WebSocket

Путь сообщения

REST

Научились 5 / 8

Общая шина v2.2

WebSocket Get message

Event Bus

Router

WebSocket Push message

Database

REST Push history

1 / 15MongoDB

public class MongoDbVerticle extends AbstractVerticle { private MongoClient client; @Override public void start() { client = MongoClient.createShared(vertx, new JsonObject() .put("db_name", "my_DB")); vertx.eventBus().consumer("router", this::saveDb); } }

2 / 15MongoDB

public class MongoDbVerticle extends AbstractVerticle { private MongoClient client; @Override public void start() { client = MongoClient.createShared(vertx, new JsonObject() .put("db_name", "my_DB")); vertx.eventBus().consumer("router", this::saveDb); } }

3 / 15MongoDB

public class MongoDbVerticle extends AbstractVerticle { private MongoClient client; @Override public void start() { client = MongoClient.createShared(vertx, new JsonObject() .put("db_name", "my_DB")); vertx.eventBus().consumer("router", this::saveDb); } }

4 / 15MongoDB

public class MongoDbVerticle extends AbstractVerticle { private MongoClient client; @Override public void start() { client = MongoClient.createShared(vertx, new JsonObject() .put("db_name", "my_DB")); vertx.eventBus().consumer("router", this::saveDb); } }

5 / 15MongoDB

public class MongoDbVerticle extends AbstractVerticle { private MongoClient client; @Override public void start() { client = MongoClient.createShared(vertx, new JsonObject() .put("db_name", "my_DB")); vertx.eventBus().consumer("router", this::saveDb); } }

6 / 15MongoDB

public class MongoDbVerticle extends AbstractVerticle { private MongoClient client; @Override public void start() { client = MongoClient.createShared(vertx, new JsonObject() .put("db_name", "my_DB")); vertx.eventBus().consumer("router", this::saveDb); } }

7 / 15MongoDB

public class MongoDbVerticle extends AbstractVerticle { private MongoClient client; @Override public void start() { client = MongoClient.createShared(vertx, new JsonObject() .put("db_name", "my_DB")); vertx.eventBus().consumer("router", this::saveDb); } }

8 / 15MongoDB

public class MongoDbVerticle extends AbstractVerticle { private MongoClient client; @Override public void start() { client = MongoClient.createShared(vertx, new JsonObject() .put("db_name", "my_DB")); vertx.eventBus().consumer("router", this::saveDb); } }

void saveDb(Message<String> message) { }

9 / 15MongoDB

void saveDb(Message<String> message) { client.insert("message", new JsonObject(message.body()), this::handlerSaved); }

void handlerSaved(AsyncResult<String> stringAsyncResult) { if (stringAsyncResult.succeeded()) { System.out.println("MongoDB save: " + stringAsyncResult.result()); } else { System.out.println("ERROR MongoDB: " + stringAsyncResult.cause()); } }

10 / 15MongoDB

void saveDb(Message<String> message) { client.insert("message", new JsonObject(message.body()), this::handlerSaved); }

void handlerSaved(AsyncResult<String> stringAsyncResult) { if (stringAsyncResult.succeeded()) { System.out.println("MongoDB save: " + stringAsyncResult.result()); } else { System.out.println("ERROR MongoDB: " + stringAsyncResult.cause()); } }

11 / 15MongoDB

void saveDb(Message<String> message) { client.insert("message", new JsonObject(message.body()), this::handlerSaved); }

void handlerSaved(AsyncResult<String> stringAsyncResult) { if (stringAsyncResult.succeeded()) { System.out.println("MongoDB save: " + stringAsyncResult.result()); } else { System.out.println("ERROR MongoDB: " + stringAsyncResult.cause()); } }

12 / 15

void createWebSocketServer(ServerWebSocket wsServer) { wsServer.frameHandler(wsFrame -> {

vertx.eventBus().publish( "router", wsFrame.textData()); }); }

MongoDB

13 / 15MongoDB

void saveDb(Message<String> message) { client.insert("message", new JsonObject(message.body()), this::handlerSaved); }

void handlerSaved(AsyncResult<String> stringAsyncResult) { if (stringAsyncResult.succeeded()) { System.out.println("MongoDB save: " + stringAsyncResult.result()); } else { System.out.println("ERROR MongoDB: " + stringAsyncResult.cause()); } }

14 / 15MongoDB

void saveDb(Message<String> message) { client.insert("message", new JsonObject(message.body()), this::handlerSaved); }

void handlerSaved(AsyncResult<String> stringAsyncResult) { if (stringAsyncResult.succeeded()) { System.out.println("MongoDB save: " + stringAsyncResult.result()); } else { System.out.println("ERROR MongoDB: " + stringAsyncResult.cause()); } }

15 / 15MongoDB

void saveDb(Message<String> message) { client.insert("message", new JsonObject(message.body()), this::handlerSaved); }

void handlerSaved(AsyncResult<String> stringAsyncResult) { if (stringAsyncResult.succeeded()) { System.out.println("MongoDB save: " + stringAsyncResult.result()); } else { System.out.println("ERROR MongoDB: " + stringAsyncResult.cause()); } }

Первое приложение

Блокирующие операции

WebSocket

Путь сообщения

REST

База данных

Научились 6 / 8

WebSocket Get message

Event Bus

Router

WebSocket Push message

Database

REST Get message

REST Push history

Общая шина v2.3

curl http://HOST/getHistory

Rest-клиент

Приемсообщений по REST

public class RestServerVerticle extends AbstractVerticle { @Override public void start() { } }

1 / 12

@Override public void start() { // . . . httpRouter.get("/getHistory") .handler(request -> vertx.eventBus().send( "getHistory", request.getBodyAsString(), result -> request.response().end( result.result().body().toString()))); // . . . }

2 / 12

Приемсообщений по REST

@Override public void start() { // . . . httpRouter.get("/getHistory") .handler(request -> vertx.eventBus().send( "getHistory", request.getBodyAsString(), result -> request.response().end( result.result().body().toString()))); // . . . }

3 / 12

Приемсообщений по REST

@Override public void start() { // . . . httpRouter.get("/getHistory") .handler(request -> vertx.eventBus().send( "getHistory", request.getBodyAsString(), result -> request.response().end( result.result().body().toString()))); // . . . }

4 / 12

Приемсообщений по REST

@Override public void start() { // . . . httpRouter.get("/getHistory") .handler(request -> vertx.eventBus().send( "getHistory", request.getBodyAsString(), result -> request.response().end( result.result().body().toString()))); // . . . }

5 / 12

Приемсообщений по REST

@Override public void start() { // . . . httpRouter.get("/getHistory") .handler(request -> vertx.eventBus().send( "getHistory", request.getBodyAsString(), result -> request.response().end( result.result().body().toString()))); // . . . }

6 / 12

Приемсообщений по REST

public class MongoDbVerticle extends AbstractVerticle { private MongoClient client; @Override public void start() { // . . . vertx.eventBus().consumer("getHistory", this::getHistory); } } void getHistory(Message<String> message) { client.find("message", new JsonObject(), result -> message.reply( Json.encode(result.result())) ); }

Приемсообщений по REST

7 / 12

public class MongoDbVerticle extends AbstractVerticle { private MongoClient client; @Override public void start() { // . . . vertx.eventBus().consumer("getHistory", this::getHistory); } } void getHistory(Message<String> message) { client.find("message", new JsonObject(), result -> message.reply( Json.encode(result.result())) ); }

Приемсообщений по REST

8 / 12

public class MongoDbVerticle extends AbstractVerticle { private MongoClient client; @Override public void start() { // . . . vertx.eventBus().consumer("getHistory", this::getHistory); } } void getHistory(Message<String> message) { client.find("message", new JsonObject(), result -> message.reply( Json.encode(result.result())) ); }

Приемсообщений по REST

9 / 12

public class MongoDbVerticle extends AbstractVerticle { private MongoClient client; @Override public void start() { // . . . vertx.eventBus().consumer("getHistory", this::getHistory); } } void getHistory(Message<String> message) { client.find("message", new JsonObject(), result -> message.reply( Json.encode(result.result())) ); }

Приемсообщений по REST

10 / 12

@Override public void start() { // . . . httpRouter.get("/getHistory") .handler(request -> vertx.eventBus().send( "getHistory", request.getBodyAsString(), result -> request.response().end( result.result().body().toString()))); // . . . }

11 / 12

Приемсообщений по REST

Demo

12 / 12

Приемсообщений по REST

С греческого — «Рулевой»

Первоначальный разработчик — Google

Управляет Docker контейнерами

Kubernetes описание

Kubernetes

Задача — автоматизировать работу с Docker контейнерами:

Установка

Обновление

Масштабирование

Возврат к старой версии

Мониторинг

Логирование

Что такое Deployment

NODE

NODE

NODE

POD

POD

POD

POD

POD

POD

V2

V1

REPLICA SET

DEPLOYMENT

REPLICA SET

REPLICA SET

V3

Deploy

public class Starter {

public static void main(String[] args) { Vertx.vertx().deployVerticle(new WsServerVerticle()); Vertx.vertx().deployVerticle(new RestServerVerticle()); Vertx.vertx().deployVerticle(new RouterVerticle()); Vertx.vertx().deployVerticle(new MongoDbVerticle());

} }

1 / 5

Deploy

--- apiVersion: apps/v1 kind: Deployment metadata: name: jbreak-chat spec: selector: matchLabels: run: jbreak-chat replicas: 1 template: metadata: labels: run: jbreak-chat spec: containers: - name: jbreak-chat image: dzx912/jbreak-chat:1 ports: - containerPort: 8080 - containerPort: 8081

2 / 5

Deploy

--- apiVersion: v1 kind: Service metadata: name: jbreak-chat labels: run: jbreak-chat spec: selector: run: jbreak-chat-server ports: - name: websocket port: 8080 nodePort: 30080 - name: http port: 8081 nodePort: 30081 type: LoadBalancer

3 / 5

Deploy

kubectl apply -f chat.yaml

4 / 5

Demo

5 / 5Deploy

Cluster Manager в Vert.x

Cluster в Vert.x

IgniteConfiguration getIgniteConfiguration() { TcpDiscoverySpi spi = new TcpDiscoverySpi(); TcpDiscoveryKubernetesIpFinder ipFinder = new TcpDiscoveryKubernetesIpFinder(); ipFinder.setServiceName("jbreak-chat"); spi.setIpFinder(ipFinder); IgniteConfiguration cfg = new IgniteConfiguration(); cfg.setDiscoverySpi(spi); return cfg; }

1 / 11

Cluster в Vert.x

--- apiVersion: v1 kind: Service metadata: name: jbreak-chat . . . .

2 / 11

Cluster в Vert.x

IgniteConfiguration getIgniteConfiguration() { TcpDiscoverySpi spi = new TcpDiscoverySpi(); TcpDiscoveryKubernetesIpFinder ipFinder = new TcpDiscoveryKubernetesIpFinder(); ipFinder.setServiceName("jbreak-chat"); spi.setIpFinder(ipFinder); IgniteConfiguration cfg = new IgniteConfiguration(); cfg.setDiscoverySpi(spi); return cfg; }

3 / 11

Cluster в Vert.x

void setupCluster() { ClusterManager clusterManager = new IgniteClusterManager(getIgniteConfiguration()); VertxOptions options = new VertxOptions() .setClustered(true) .setClusterManager(clusterManager) .setClusterHost(getMyIp()); Vertx.clusteredVertx(options, res -> { if (res.succeeded()) { Vertx vertx = res.result(); deploy(vertx); } }); }

4 / 11

Cluster в Vert.x

void setupCluster() { ClusterManager clusterManager = new IgniteClusterManager(getIgniteConfiguration()); VertxOptions options = new VertxOptions() .setClustered(true) .setClusterManager(clusterManager) .setClusterHost(getMyIp()); Vertx.clusteredVertx(options, res -> { if (res.succeeded()) { Vertx vertx = res.result(); deploy(vertx); } }); }

5 / 11

Cluster в Vert.x

void setupCluster() { ClusterManager clusterManager = new IgniteClusterManager(getIgniteConfiguration()); VertxOptions options = new VertxOptions() .setClustered(true) .setClusterManager(clusterManager) .setClusterHost(getMyIp()); Vertx.clusteredVertx(options, res -> { if (res.succeeded()) { Vertx vertx = res.result(); deploy(vertx); } }); }

6 / 11

Cluster в Vert.x

void setupCluster() { ClusterManager clusterManager = new IgniteClusterManager(getIgniteConfiguration()); VertxOptions options = new VertxOptions() .setClustered(true) .setClusterManager(clusterManager) .setClusterHost(getMyIp()); Vertx.clusteredVertx(options, res -> { if (res.succeeded()) { Vertx vertx = res.result(); deploy(vertx); } }); }

7 / 11

Cluster в Vert.x

void setupCluster() { ClusterManager clusterManager = new IgniteClusterManager(getIgniteConfiguration()); VertxOptions options = new VertxOptions() .setClustered(true) .setClusterManager(clusterManager) .setClusterHost(getMyIp()); Vertx.clusteredVertx(options, res -> { if (res.succeeded()) { Vertx vertx = res.result(); deploy(vertx); } }); }

8 / 11

Cluster в Vert.x

void setupCluster() { ClusterManager clusterManager = new IgniteClusterManager(getIgniteConfiguration()); VertxOptions options = new VertxOptions() .setClustered(true) .setClusterManager(clusterManager) .setClusterHost(getMyIp()); Vertx.clusteredVertx(options, res -> { if (res.succeeded()) { Vertx vertx = res.result(); deploy(vertx); } }); }

9 / 11

Cluster в Vert.x

void deploy(Vertx vertx) { vertx.deployVerticle(new WsServerVerticle()); vertx.deployVerticle(new RestServerVerticle()); vertx.deployVerticle(new RouterVerticle()); vertx.deployVerticle(new MongoDbVerticle()); }

10 / 11

Научились

Первое приложение

Блокирующие операции

WebSocket

Путь сообщения

REST

База данных

Кластеризация

7 / 8

Cluster в Vert.x

Demo

11 / 11

Продумывайтемаршруты

Научились 7 / 8

Первое приложение

Блокирующие операции

WebSocket

Путь сообщения

REST

База данных

Кластеризация

Cluster в Vert.x

1 / 15

Even

t B

us

Pod1 Pod2

Server

Router

Server

Router

Cluster в Vert.x

void deploy(Vertx vertx) { vertx.deployVerticle(new WsServerVerticle()); vertx.deployVerticle(new RestServerVerticle()); }

2 / 15

Cluster в Vert.x

apiVersion: apps/v1 kind: Deployment metadata: name: jbreak-chat-server . . . .

3 / 15

Cluster в Vert.x

void deploy(Vertx vertx) { vertx.deployVerticle(new RouterVerticle()); }

4 / 15

Cluster в Vert.x

apiVersion: apps/v1 kind: Deployment metadata: name: jbreak-chat-router . . . .

5 / 15

Cluster в Vert.x

void deploy(Vertx vertx) { vertx.deployVerticle(new MongoDbVerticle()); }

6 / 15

Cluster в Vert.x

apiVersion: apps/v1 kind: Deployment metadata: name: jbreak-chat-mongo . . . .

7 / 15

Cluster в Vert.x

8 / 15

void createWebSocketServer(ServerWebSocket wsServer) { wsServer.frameHandler(wsFrame -> {

vertx.eventBus().publish( "router", wsFrame.textData()); }); }

Cluster в Vert.x

9 / 15

void createWebSocketServer(ServerWebSocket wsServer) { wsServer.frameHandler(wsFrame -> {

vertx.eventBus().send( "router", wsFrame.textData()); }); }

Cluster в Vert.x

10 / 15

@Override public void start() { HttpServer httpServer = vertx.createHttpServer(); Router httpRouter = Router.router(vertx); httpRouter.route().handler(BodyHandler.create()); httpRouter.post("/sendMessage") .handler(request -> { vertx.eventBus().publish("router", request.getBodyAsString()); request.response().end("ok"); }); httpServer.requestHandler(httpRouter::accept); httpServer.listen(8081); }

Cluster в Vert.x

11 / 15

@Override public void start() { HttpServer httpServer = vertx.createHttpServer(); Router httpRouter = Router.router(vertx); httpRouter.route().handler(BodyHandler.create()); httpRouter.post("/sendMessage") .handler(request -> { vertx.eventBus().send("router", request.getBodyAsString()); request.response().end("ok"); }); httpServer.requestHandler(httpRouter::accept); httpServer.listen(8081); }

Cluster в Vert.x

12 / 15

public class MongoDbVerticle extends AbstractVerticle { private MongoClient client; @Override public void start() { client = MongoClient.createShared(vertx, new JsonObject() .put("db_name", "my_DB")); vertx.eventBus().consumer("router", this::saveDb); } }

Cluster в Vert.x

13 / 15

public class MongoDbVerticle extends AbstractVerticle { private MongoClient client; @Override public void start() { client = MongoClient.createShared(vertx, new JsonObject() .put("db_name", "my_DB")); vertx.eventBus().consumer("database.save", this::saveDb); } }

Cluster в Vert.x

14 / 15

public class RouterVerticle extends AbstractVerticle { void router(Message<String> message) { Data data = Json.decodeValue(message.body(), Data.class); vertx.eventBus().publish( "/token/" + data.getAddress(), message.body());

vertx.eventBus().send("database.save", message.body()); } }

Cluster в Vert.x

Demo

15 / 15

Научились 8 / 8

Первое приложение

Блокирующие операции

WebSocket

Путь сообщения

REST

База данных

Кластеризация

Пусть сообщения в кластере

Чистим за собой

kubectl delete -f chat.yaml

Не блокировать Event Bus

1 функция — 1 модуль

Продумываем маршруты

Выученные уроки

Вопросы?

Ленок АнтонСерверная разработка

Проект: Диалоги в Сбербанк Онлайн

[email protected]