Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JUGNsk Meetup#10. Олег Докука: "Multiplayer Pac-Man with RSocket"

jugnsk
August 27, 2019

JUGNsk Meetup#10. Олег Докука: "Multiplayer Pac-Man with RSocket"

Работаете с микросервисами? Раздражает медленный REST? Надоел ненадежный gRPC? Нужно быстрое клиент-серверное взаимодействие, но не хочется изобретать свой WS-протокол? Решение есть, и это RSocket. RSocket — новый протокол уровня приложений с поддержкой Reactive Streams, способный сделать вашу систему быстрой, масштабируемой и отказоустойчивой. Приходите узнать, почему RSocket — это будущее межсервисных взаимодействий.

Из этого доклада вы узнаете, почему RSocket — новаторское решение для межсервисных взаимодействий. Увидите, как создать современный мультиплеерный Pac-Man с помощью этой замечательной технологии. Доклад покажет, как улучшить gRPC с помощью RSocket и почему стоит начать использовать RSocket уже сегодня.

jugnsk

August 27, 2019
Tweet

More Decks by jugnsk

Other Decks in Programming

Transcript

  1. Oleh Dokuka • WORK FOR NETIFI • REACTIVE GEEK •

    REACTOR 3 CONTRIBUTOR • BOOKS AUTHOR • LOCAL COMMUNITY BUILDER @OlehDokuka
  2. Step 3: Updates 100. Player 1 88. Player 3 80.

    Player 5 75. Player 2 68. Player 6 30. Player 4 7. Player 7 Scoreboard +1 +1 +1 +25 +1
  3. 100. Player 1 88. Player 3 80. Player 5 75.

    Player 2 68. Player 6 30. Player 4 7. Player 7 Scoreboard +1 +1 +1 +100 +1 Real Enterprise
  4. 100. Player 1 88. Player 3 80. Player 5 75.

    Player 2 68. Player 6 30. Player 4 7. Player 7 Scoreboard + + + +10 + Real Enterprise
  5. 100. Player 1 88. Player 3 80. Player 5 75.

    Player 2 68. Player 6 30. Player 4 7. Player 7 Scoreboard + + + +10 + Real Enterprise ← Elastic Storage Ы
  6. 100. Player 1 88. Player 3 80. Player 5 75.

    Player 2 68. Player 6 30. Player 4 7. Player 7 Scoreboard + + + +10 + Real Enterprise Ы
  7. To Summarize • MACHINE LEARNING PIPE • WHERE SUBSCRIBER CAN

    WORK SLOW OR FAST • THIS SHOULD WORK STABLY
  8. @RestController @RequestMapping("/http") public class HttpGameController { ... @PostMapping("/start") public Mono<Config>

    start( @RequestBody Nickname nickname, @CookieValue("uuid") String uuid ) { return gameService.start(nickname) .subscriberContext(Context.of("uuid", UUID.fromString(uuid))); } } @RestController @RequestMapping("/http") public class HttpGameController { ... @PostMapping("/start") public Mono<Config> start( @RequestBody Nickname nickname, @CookieValue("uuid") String uuid ) { return gameService.start(nickname) .subscriberContext(Context.of("uuid", UUID.fromString(uuid))); } }
  9. • TEXT MESSAGE OVERHEAD • INEFFICIENT RESOURCE USAGE • SLOW

    PERFORMANCE • COMMUNICATION RIGIDITY • LACK OF PROPER FLOW CONTROL Why NOT HTTP?
  10. • MOST POPULAR IN JS WORLD • TOPIC BASED BINARY/TEXT

    MESSAGING • JAVA SERVER BUILT ON TOP OF NETTY Why Socket.IO?
  11. • NO INTEGRATION WITH SPRING • JS (CALLBACKS) CODE STYLE

    • NO ACCESS TO BYTEBUF final SocketIOServer server = new SocketIOServer(configuration); context.addApplicationListener(event -> { if (event instanceof ContextClosedEvent || event instanceof ContextStoppedEvent || event instanceof ApplicationFailedEvent) { server.stop(); } }); final SocketIOServer server = new SocketIOServer(configuration); context.addApplicationListener(event -> { if (event instanceof ContextClosedEvent || event instanceof ContextStoppedEvent || event instanceof ApplicationFailedEvent) { server.stop(); } }); final SocketIOServer server = new SocketIOServer(configuration); context.addApplicationListener(event -> { if (event instanceof ContextClosedEvent || event instanceof ContextStoppedEvent || event instanceof ApplicationFailedEvent) { server.stop(); } }); Why Not Socket.IO server.addConnectListener(client -> {}); server.addDisconnectListener(client -> {}); server.addEventListener("start", byte[].class, (client, data, ackSender) -> {}); server.addEventListener("locate", byte[].class, (client, data, ackRequest) -> {}); server.addEventListener("streamMetricsSnapshots", byte[].class, (client, data, ackSender) -> {}); server.addConnectListener(client -> {}); server.addDisconnectListener(client -> {}); server.addEventListener("start", byte[].class, (client, data, ackSender) -> {}); server.addEventListener("locate", byte[].class, (client, data, ackRequest) -> {}); server.addEventListener("streamMetricsSnapshots", byte[].class, (client, data, ackSender) -> {});
  12. Why gRPC? • BUILT ON TOP OF HTTP/2 • EASY

    TO BUILD API WITH PROTOBUF • GOOD DEVELOPMENT EXPERIENCE • SEAMLESS INTEGRATION WITH SPRING service GameService { rpc start (Nickname) returns (Config) {} } service PlayerService { rpc locate(stream Location) returns (google.protobuf.Empty) {} rpc players(google.protobuf.Empty) returns (stream Player) {} } service GameService { rpc start (Nickname) returns (Config) {} } service PlayerService { rpc locate(stream Location) returns (google.protobuf.Empty) {} rpc players(google.protobuf.Empty) returns (stream Player) {} } service GameService { rpc start (Nickname) returns (Config) {} } service PlayerService { rpc locate(stream Location) returns (google.protobuf.Empty) {} rpc players(google.protobuf.Empty) returns (stream Player) {} } service GameService { rpc start (Nickname) returns (Config) {} } service PlayerService { rpc locate(stream Location) returns (google.protobuf.Empty) {} rpc players(google.protobuf.Empty) returns (stream Player) {} } protobuf { protoc { artifact = 'com.google.protobuf:protoc' } plugins { grpc { artifact = "io.grpc:protoc-gen-grpc-java" } } generateProtoTasks { ofSourceSet('main')*.plugins { grpc {} } } } @GRpcService public class GrpcPlayerController extends ReactorPlayerServiceGrpc.PlayerServiceImplBase { @Override public Flux<Player> players(Mono<Empty> message) { return playerService .players() .onBackpressureBuffer() .subscriberContext(Context.of("uuid", CONTEXT_UUID_KEY.get())); } } @GRpcService public class GrpcPlayerController extends ReactorPlayerServiceGrpc.PlayerServiceImplBase { @Override public Flux<Player> players(Mono<Empty> message) { return playerService .players() .onBackpressureBuffer() .subscriberContext(Context.of("uuid", CONTEXT_UUID_KEY.get())); } }
  13. GRPC SUBSCRIBER new CallStreamObserver<>() { @Override public void onNext(Object value)

    { this.request(5); } } new CallStreamObserver<>() { @Override public void onNext(Object value) { this.request(5); } }
  14. Summary • Everything is either SLOW, HARD to implement or

    LACKS browser support • Flow control is far from needed • Do you want to waste your time in searching how to solve the problems???
  15. Netflix case study on gRPC • Reactive Streaming Service Networking

    with Ryland Degnan 
 (ex Netflix Edge Platform)
 
 https://bit.ly/2FUvHG3
  16. 85 Notable Features • LEASING - GIVE CAPACITY TO CLIENTS,

    AVOID CIRCUIT BREAKERS • RESUMABILITY - RESUME STREAMS IF CONNECTION LOST • FRAGMENTATION - SPLIT LARGE PAYLOAD ONTO SMALLER CHUNKS
  17. RPC API protobuf { generatedFilesBaseDir = "${projectDir}/src/generated" protoc { artifact

    = 'com.google.protobuf:protoc' } plugins { rsocketRpc { artifact = "io.rsocket.rpc:rsocket-rpc-protobuf" } } generateProtoTasks { ofSourceSet('main')*.plugins { rsocketRpc {} } } } protobuf { generatedFilesBaseDir = "${projectDir}/src/generated" protoc { artifact = 'com.google.protobuf:protoc' } plugins { rsocketRpc { artifact = "io.rsocket.rpc:rsocket-rpc-protobuf" } } generateProtoTasks { ofSourceSet('main')*.plugins { rsocketRpc {} } } }
  18. RSocketRpcService public class ExtrasController implements org.coinen.pacman.ExtrasService { … @Override public

    Flux<Extra> extras(Empty message, ByteBuf metadata) { return extrasService.extras(); } } public class ExtrasController implements org.coinen.pacman.ExtrasService { … @Override public Flux<Extra> extras(Empty message, ByteBuf metadata) { return extrasService.extras(); } } public class ExtrasController implements org.coinen.pacman.ExtrasService { … @Override public Flux<Extra> extras(Empty message, ByteBuf metadata) { return extrasService.extras(); } }
  19. SPRING-MESSAGING @Controller @MessageMapping(“my.route.name”) public class ExtrasController { … @MessageMapping(“handle.extras”) public

    Flux<Extra> extras() { return extrasService.extras(); } } @Controller @MessageMapping(“my.route.name”) public class ExtrasController { … @MessageMapping(“handle.extras”) public Flux<Extra> extras() { return extrasService.extras(); } } @Controller @MessageMapping(“my.route.name”) public class ExtrasController { … @MessageMapping(“handle.extras”) public Flux<Extra> extras() { return extrasService.extras(); } }
  20. Scenario 10 3 3 3 3 10 3 3 3

    3 10 3 3 3 3 4 1 1 1 1 4 1 1 1 1 Ы
  21. Advantages • SIMPLICITY IN DEVELOPMENT • EFFICIENT RESOURCE USAGE •

    HIGH PERFORMANCE • HIGH FLEXIBILITY • EFFECTIVE RELIABILITY
  22. Summary • EACH PROTOCOL HAS IT`S BENEFITS • SOCKET.IO IS

    THE BEST IN JS WORLD • gRPC PERFORMS REALLY WELL FOR SERVER • BUT REACTIVE IS ABOUT RESILIENCY • WHERE RSOCKET FULLY COVERS OUR USE-CASE
  23. Resources • COMMUNITY -> https://community.netifi.com • VIDEO CHANNEL -> https://bit.ly/2Fku9VC

    • RSOCKET IN SPRING -> https://bit.ly/2OiUmrD • CLOUD NATIVE RSOCKET -> https://bit.ly/2JvDFdJ @OlehDokuka @netifi_inc