Project Reactor

4ccf6c02807d06f043a71435c48ce86a?s=47 Kengo TODA
September 19, 2018

Project Reactor

A simple explanation about how we can apply project reactor to app.
It also explains about a required paradigm shift to code.

4ccf6c02807d06f043a71435c48ce86a?s=128

Kengo TODA

September 19, 2018
Tweet

Transcript

  1. PROJECT REACTOR 2018-09-12 Kengo TODA 1

  2. OBJECTIVE • Understand the best practices for multi-thread app •

    Understand a paradigm shift in daily coding • Learn how Spring Framework is going to apply these solutions 2
  3. WHOAMI • Kengo TODA • FOSS developer for 17+ years

    • https://github.com/KengoTODA/ • A core member of SpotBugs 3
  4. AGENDA • Best practice to code multi-thread app, and in

    reality • You are not coding a procedure! • Project Reactor the latest approach • Can we use Project Reactor in production? 4
  5. BEST PRACTICE TO CODE MULTI-THREAD APP, AND IN REALITY 5

  6. WHY MULTI-THREAD APP IS NECESSARY • Current architecture of computer:

    bottleneck exists in CPU and I/O • One machine has many CPU cores • Network is enough fast • Compute & store in parallel for better throughput 6
  7. WHY MULTI-THREAD APP IS DIFFICULT • Race condition • Hard

    to reproduce & debug • Amdahl’s law 7
  8. BEST PRACTICES • Stateless service, Immutable data (e.g. @Value in

    lombok, Immutables) • Ownership (e.g. Rust) • Non-blocking I/O (e.g. Netty) • Idempotence, Stateless, Actor model (e.g. Akka), Reentrant, Thread- safe, lock-free, CAS, etc. 8
  9. IN REALITY… • We need state! • We everyday persist

    some onto database • Cache is necessary but it’s also a kind of state • Ownership needs support from system 9
  10. IN REALITY… • Immutable data is hard to handle •

    Do we need Builder & copy constructor everywhere? • Java’s clone() is almost broken (see EffectiveJava) • Java has no Object.assign() in JavaScript • Some framework expects that data is not immutable (!!??) 10
  11. IN REALITY… • Non-blocking I/O makes callback hell • Callable<T>

    makes deep nest, lambda is not solution for it • CompletableFuture<T> is better solution, have a try with it • similar with Promise<T> in JavaScript • It works with @Async in Spring Framework 11
  12. CONCLUSION • We need to consider how to handle necessary

    state and mutability, with considering better async method handling.
 • To consider them simply, we need a paradigm shift in your mind. 12
  13. YOU ARE NOT CODING A PROCEDURE! 13

  14. WHAT YOUR PROGRAM IS? • We learned that program runs

    from top to bottom in your editor • in context of structured programming just has sequence, selection, and repetition 14
  15. SEQUENCIAL PROCEDURE example: A traditional web app that displays post

    and widget 15 load user load post combine data persist combined data load widget render
  16. SEQUENCIAL PROCEDURE example: A traditional web app that displays post

    and widget 16 load user load post combine data persist combined data load widget render Why we don’t start loading before persisting combined data? why don’t we load user and post in parallel?
  17. HOW ABOUT MULTI-THREAD APP? • You pass value/message to another

    thread, • You wait until other threads finish their task, and • You zip (combine) them to start a task in another thread.
 • You may need to care which thread we run each task (e.g. UI thread) 17
  18. DIRECTED ACYCLIC GRAPH Each task has dependency on others, waits

    until dependee gives data. 18
  19. DIRECTED ACYCLIC GRAPH Each task has dependency on others, waits

    until dependee gives data. 19 Thread 1 Thread 2 Thread 3 similar with MapReduce?
  20. HOW TO CODE A GRAPH? • Wire relation between tasks

    (lambda or method) • Keep tasks stateless, idempotence and thread safe • Prefer CompletableFuture<T> than Callable<T> • Encapsulate state/mutability in each task • disclose immutable data to others 20
  21. ROUGH SAMPLE CODE 21 with JDK8 API

  22. NOT SO PRODUCTIVE… • How to specify the thread to

    run tasks? • How to handle the exception in tasks? • How to make implementation testable? • How to cache, concat, filter, group, retry and throttle data? 22
  23. CONCLUSION • Multi-thread app is not a procedure but a

    graph • Wire tasks that encapsulate mutability in it • JDK8 provides CompletableFuture<T> and it fulfills a part of requirements 23
  24. PROJECT REACTOR THE LATEST APPROACH 24

  25. EXISTING APPROACH • We have many approaches like… • Rx.NET,

    Akka-streams, RxJava and Project Reactor (ref for diff) • JDK9 Flow could be standard in future • Project Reactor is most flesh and well-integrated with Spring 25
  26. BEFORE DIVING REACTOR… • Summarize existing problems: • How to

    specify the thread to run tasks? • How to handle the exception in tasks? • How to make implementation testable? • How to cache, concat, filter, group, retry and throttle data? 26
  27. THREAD HANDLING • Scheduler helps you to decide which thread

    to run tasks • Schedulers.parallel() for non-blocking tasks, to use fixed size thread pool. • Schedulers.elastic() for blocking tasks (JDBC etc.), to launch new thread if necessary. 27
  28. THREAD HANDLING • Set scheduler by Flux#publishOn() and Flux#subscribeOn() 28

  29. THREAD HANDLING • Set scheduler by Flux#publishOn() and Flux#subscribeOn() 29

    published on parallel-1 published on parallel-1 published on parallel-1 published on parallel-1 published on parallel-1 : :
  30. THREAD HANDLING • To run task in multiple thread, use

    Flux#parallel() 30
  31. THREAD HANDLING • To run task in multiple thread, use

    Flux#parallel() 31 run on parallel-1 run on parallel-2 run on parallel-3 run on parallel-3 run on parallel-4 : :
  32. BEFORE DIVING REACTOR… • Summarize existing problems: • How to

    specify the thread to run tasks? • How to handle the exception in tasks? • How to make implementation testable? • How to cache, concat, filter, group, retry and throttle data? 32
  33. EXCEPTION HANDLING • Each task (e.g. map, reduce, filter) can

    throw exception 33
  34. EXCEPTION HANDLING • Or return Flux.error() in Flux#flatMap() 34

  35. BEFORE DIVING REACTOR… • Summarize existing problems: • How to

    specify the thread to run tasks? • How to handle the exception in tasks? • How to make implementation testable? • How to cache, concat, filter, group, retry and throttle data? 35
  36. TASK IS ENOUGH TESTABLE • It’s just a lambda or

    method • Key is how to test the scenario realized by graph, the connected tasks 36
  37. USE REACTOR-TEST • StepVerifier in reactor-test helps you 37

  38. BEFORE DIVING REACTOR… • Summarize existing problems: • How to

    specify the thread to run tasks? • How to handle the exception in tasks? • How to make implementation testable? • How to cache, concat, filter, group, retry and throttle data? 38
  39. PUBLISHERS PROVIDES CONVENIENCE WAY • cache() to reuse emitted signals

    for further Subscribers • concat() Subscribers to make single subscriber • filter() source value before emit it (same with Stream API) • groupBy() some key, to make multiple publishers (similar with groupingBy collector) • retry() subscribe when subscribers throw error • for throttling, sampleTimeout() could be help 39
  40. PUBLISHERS PROVIDES CONVENIENCE WAY • We cannot use try-with-resources to

    close resource • because finally block will be executed before resource is used at timing to subscribe • use Flux.using() instead 40
  41. CAN WE USE PROJECT REACTOR IN PRODUCTION? 41

  42. THREE USE CASES • Web application • CLI application •

    GUI application 42
  43. WEB APPLICATION • Use spring-webflux with spring-boot • New web

    application framework based on Project Reactor • My sandbox project: javadocky 43
  44. KNOWN LIMITATION OF WEBFLUX • Community still needs time to

    support webflux • Actuator (monitoring) : done • Springfox (Swagger): not yet • We have sample project depending on snapshot • Validation: not yet for functional endpoint (or apply hack like this) 44
  45. CLI APPLICATION • Simply use Project Reactor on spring-boot •

    My sandbox project: DependJ • CommandLineRunner helps you to touch raw command line parameter • ApplicationRunner helps you to handle command line parameter • You can simplify code to run tasks in parallel 45
  46. GUI APPLICATION • Use project-reactor with reactor-extra on spring-boot •

    reactor-extra provides schedulers for event dispatch thread • like RxJava for Android app, we can use project reactor to separate backend computation and frontend operation 46
  47. WRAP-UP 47

  48. CHANGE MIND TO CODE A GRAPH • To code multi-thread

    app, • Encapsulate mutability into task, • Wire tasks by Project Reactor, then • Your app will be high-performance, non-blocking and testable! 48
  49. Q&A 49

  50. APPENDIX 50

  51. WHAT REACTIVE PROGRAMMING IS? • Reactive Programming is a paradigm

    focuses on dataflow, and what I explained partially in this slide • Spread sheet like Excel provides reactive feature (Wikipedia) • “=B1+C1” will be updated when B1 and/or C1 is changed 51
  52. THIS PARADIGM IS NOT ONLY FOR MULTI-THREAD APP • We

    can apply it to MSA & distributed service • Project Reactor provides backpressure • Reactive Systems (that can be achieved by Reactive Streams) can make distributed system responsive, elastic, resilient and message driven. 52
  53. RELATED KEY WORDS • Reactive Streams, Reactive Systems and Reactive

    Programming • Idempotence, Stateless, Reentrant, Hysteresis 53