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

Reactive или не reactive, вот в чем вопрос

Kirill Tolkachev
April 05, 2019
1k

Reactive или не reactive, вот в чем вопрос

Доклад Reactive or Not Reactive c JPoint 2019 – https://jpoint.ru/talks/b9ib3swihayyhnnpjghc2/

Все вы слышали фразу: «Человек, научившийся пользоваться молотком, во всем начинает видеть гвоздь». В мире программирования это очень часто происходит с новыми и модными технологиями, которые далеко не всегда применяются по назначению. В результате мы имеем более сложный API, который могут поддерживать только прошедшие медные трубы программисты, кучу багов и прочих проблем.

Как нам избежать сломанных пальцев и разбитых молотком вещей при попытке внедрить React?

Мы рассмотрим пример системы, в которой есть проблемы, и, конечно же, попробуем отрефакторить её в реактивном стиле. Рассмотрим преимущества и недостатки не только подхода, но и API конкретных реализаций. Оценим сложность, которая была до рефакторинга, и ту сложность, которую мы привнесли после. Постараемся разобраться, что игрушки, а что нет.

Код с демо — https://github.com/lavcraft/spring-react-or-not-react-jpoint2019
Json streaming — https://en.wikipedia.org/wiki/JSON_streaming
Jackson Smile — https://github.com/FasterXML/jackson-dataformats-binary/tree/master/smile

WebClient Java 11 HttpClient Support — https://github.com/spring-projects/spring-framework/issues/21014
Webflux and RSocket backpressure — https://stackoverflow.com/questions/52244808/backpressure-mechanism-in-spring-web-flux/52245213#52245213

Kirill Tolkachev

April 05, 2019
Tweet

Transcript

  1. Архитектура проекта «Big Brother» Перехватчик писем, отсылает все письма на

    распознание Правоохранительные органы, принимают решение об аресте Расшифровщик писем, Выясняет чьё письмо о отсылает в Правоохранительные органы
  2. Tomcat Push and Pull semantics related to consumer events Pusher

    Buffer #P0 Passive Consumer Buffer #C2 Buffer #T1 Wait
  3. Tomcat Push and Pull semantics related to consumer events Pusher

    Buffer #P0 Passive Consumer Buffer #C2 Buffer #T1 Wait
  4. Tomcat Push and Pull semantics related to consumer events Pusher

    Buffer #P0 Passive Consumer Buffer #C2 Buffer #T1 Reject
  5. ...

  6. Что должен делать producer когда consumer не справляется Продюсер читает

    данные с нужной скоростью Нет проблемы В продюсер текут данные Всё что не успеваем отослать, суем в очередь, когда нет места в очереди, дропаем, то что менее важно
  7. Push and Pull semantics related to consumer events Pusher Buffer

    #P0 Passive Consumer Or batch single Buffer #C2
  8. Push and Pull semantics related to consumer events Pusher Buffer

    #P0 Passive Consumer Or batch single Buffer #C2
  9. Tomcat Push and Pull semantics related to consumer events Pusher

    Buffer #P0 Passive Consumer Buffer #C2 Buffer #T1 Wait
  10. Tomcat Push and Pull semantics related to consumer events Pusher

    Buffer #P0 Passive Consumer Buffer #C2 Buffer #T1 Wait
  11. Tomcat Push and Pull semantics related to consumer events Pusher

    Buffer #P0 Passive Consumer Buffer #C2 Buffer #T1 Reject
  12. Push and Pull semantics related to consumer events Pusher Buffer

    #P0 Passive Consumer Buffer #C2 Black Hole
  13. Push and Pull semantics related to consumer events Pull &

    Push Service Passive Consumer Buffer #C2 Black Hole Buffer #P0
  14. Push and Pull semantics related to consumer events Pull &

    Push Service Passive Consumer Buffer #C2 Black Hole Buffer #P0
  15. Push and Pull semantics related to consumer events Pull &

    Push Service Passive Consumer Buffer #C2 Black Hole Buffer #P0
  16. WebClient is a new RestTemplate Было RestTemplateBuilder → RestTemplate RestTemplate

    — передаём статический текс в body Стало WebClient.Builder → WebClient WebClient — можем передать последовательность Flux в качестве body
  17. exchange WebClient reactor-netty jetty-client Java 11 http client Issue 19658

    subscribe Issue 21014 Flux closed open Controller http connection
  18. void processLetter(Flux<Letter> f) f.doOnNext() .doOnNext() .log() .subscribe() return Mono.empty() /

    nothing / anything LetterController Close connection 400 BAD_REQUEST "Request body is missing
  19. void processLetter(Flux<Letter> f) f.doOnNext() .doOnNext() .log() .subscribe() return Mono.empty() /

    nothing / anything LetterController Close connection 400 BAD_REQUEST "Request body is missing Для начала вычитывания
  20. Flux пайплайн жизненный цикл 1. Assembly Как new Builder().prop().build() Только

    Flux.create().subscribe(subscriber) 2. В subscriber.onSubscribe() передаётся подписка – subscription 3. Через subscription выполняется первый запрос на ивенты или отписка
  21. Mon<Void> processLetter(Flux<Letter> f) return f.doOnNext() .flatMap( letter -> Mono.fromCallable(() ->

    decode(letter)) .subscribeOn(fromExecutor(threadPool)), threadPool.getMaximumPoolSize()) .log() .then() LetterController reactor-netty
  22. А что с нашими DirectBuffer`ами? netty java.lang.OutOfMemoryError: Direct buffer memory

    at j.n.Bits.reserveMemory(Bits.java:175) at j.n.DirectByteBuffer.<init>(DirectByteBuffer.java:118)
  23. Почувствуйте разницу [letter-4] onNext [letter-4] onNext [letter-2] onNext [letter-1] onNext

    [letter-4] onNext [letter-3] onNext [reactor-http-nio-3] onNext [reactor-http-nio-3] onNext [reactor-http-nio-3] onNext [reactor-http-nio-3] onNext [reactor-http-nio-3] onNext [reactor-http-nio-3] onNext vs
  24. TCP BP Без flatMap #0 flux netty netty flux reactor-netty

    reactor-nio-1 Без flatMap Пулы DirectBuffer`ов netty socket
  25. TCP BP Без flatMap #1 flux netty netty flux reactor-netty

    reactor-nio-1 Пулы DirectBuffer`ов netty socket 1. Копирует данные из cистемного сокета в DirectBuffer
  26. TCP BP Без flatMap #2 flux netty netty flux reactor-netty

    reactor-nio-1 Пулы DirectBuffer`ов netty socket 1. Копирует данные из cистемного сокета в DirectBuffer 2. Вызывает наш медленный метод decoder.decode LetterController.java
  27. TCP BP Без flatMap #3 flux netty netty flux reactor-netty

    reactor-nio-1 Пулы DirectBuffer`ов netty socket 1. Копирует данные из cистемного сокета в DirectBuffer 2. Вызывает наш медленный метод decoder.decode LetterController.java 3. Копирует данные из cистемного сокета в DirectBuffer
  28. TCP BP Без flatMap #3 flux netty netty flux reactor-netty

    reactor-nio-1 Пулы DirectBuffer`ов netty socket 1. Копирует данные из cистемного сокета в DirectBuffer 2. Вызывает наш медленный метод decoder.decode LetterController.java 3. Копирует данные из cистемного сокета в DirectBuffer 4. ... и так повторяется
  29. TCP BP После добавления flatMap flux netty netty flux reactor-netty

    reactor-nio-1 letter-N Пулы DirectBuffer`ов netty socket 1. Копирует данные из cистемного сокета в [1ms] DirectBuffer
  30. TCP BP После добавления flatMap flux netty netty flux reactor-netty

    reactor-nio-1 letter-N Пулы DirectBuffer`ов netty socket 1. Вызывает наш медленный метод [1000ms] decoder.decode LetterController.java
  31. TCP BP После добавления flatMap flux netty netty flux reactor-netty

    reactor-nio-1 letter-N Пулы DirectBuffer`ов netty socket 1. Копирует данные из cистемного сокета в [1ms] DirectBuffer [1000ms]
  32. TCP BP После добавления flatMap flux netty netty flux reactor-netty

    reactor-nio-1 letter-N Пулы DirectBuffer`ов netty socket [1000ms] letter-N Копирует данные из cистемного сокета в DirectBuffer [1ms] Вызывает наш медленный метод decoder.decode LetterController.jav a [1000ms] работает независимо
  33. TCP BP После добавления flatMap flux netty netty flux reactor-netty

    reactor-nio-1 letter-N Пулы DirectBuffer`ов netty socket Копирует данные из cистемного сокета в DirectBuffer [1ms] [1000ms] Вызывает наш медленный метод decoder.decode LetterController.jav a [1000ms] работает независимо
  34. А что с нашими DirectBuffer`ами? netty java.lang.OutOfMemoryError: Direct buffer memory

    at j.n.Bits.reserveMemory(Bits.java:175) at j.n.DirectByteBuffer.<init>(DirectByteBuffer.java:118)
  35. RSocket идеальное решение? Можно было бы его продать так же

    как webflux :) Но 1. Версия у него 0.11 2. Пока делали доклад нашли 2 бага. Спасибо Олегу, смогли обойти их 3. Привычные вещи не всегда делаются просто 4. И это только только то что мы успели найти ...
  36. Сияющие технологии 1. В каких то задачах webflux будет хорош

    2. В каких то задачах RSocket будет плох 3. Но своё решение всегда как минимум заставляет задуматься
  37. Сияющие технологии 1. В каких то задачах webflux будет хорош

    2. В каких то задачах RSocket будет плох 3. Но своё решение всегда как минимум заставляет задуматься
  38. Выводы 1. Не всё то Reactive что с интегрировано с

    Project Reactor a. Поддержка Backpressure на основе TCP BP имеет сайд эффекты b. Control flow между сервисами для реактивного пайплайна так же важен 2. Webflux не подходит для балансировки скорости между сервисами 3. С RSocket честный backpressure, пока сырой, но перспективный 4.
  39. Настоящие выводы Не стоит внедрять технологии на основе авторитета: 1.

    спикера 2. компании 3. Тренда Webflux хорош когда нужно сэкономить коннекшены и отправить пачку данных RSocket хорош во всех наших кейсах Свой велосипед всегда поняитнее
  40. Выводы – кривая обучения reactive effort/time Holy moly I am

    god! Wow It’s works This doesnt work Why can’t i get it to work Learn about reactive mastery
  41. Ссылки Код с демо 1. https://github.com/lavcraft/spring-react-or-not-react-jpoint2019 Spring Webflux Streaming 1.

    Json streaming 2. Jackson Smile Spring WebClient 1. WebClient Java 11 HttpClient Support 2. Webflux and RSocket backpressure