Slide 1

Slide 1 text

/ by Igor Lozynskyi Deep Dive into Reactive Relational Database Access

Slide 2

Slide 2 text

Реактивный Хардкор / Oleh Dokuka 2 2 Igor Lozynskyi

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Agenda / Why reactive DB access? / Look at R2DBC / Build a toy R2DBC driver / I assume, you know what Reactive is

Slide 5

Slide 5 text

Part 1: Why Reactive DB access?

Slide 6

Slide 6 text

Reactive Programming / Nonblocking / Usually asynchronous / Declarative / Processing streams / Resilient / Back pressure / Reactive Streams Standart / High-efficiency

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

Spring (5.0+) is reactive now

Slide 9

Slide 9 text

Spring Netty WebFlux WebClient Cloud Messaging …

Slide 10

Slide 10 text

Reactive Spring Data MongoDB Cassandra Couchbase ElasticSearch Redis Neo4j* *1.0.0-beta01

Slide 11

Slide 11 text

What about SQL?

Slide 12

Slide 12 text

JDBC / Nonblocking / Usually asynchronous / Declarative / Processing streams / Resilient / Back pressure / Reactive Streams Standart / Blocks Threads JDK 1.1 1997 year

Slide 13

Slide 13 text

Reactive Relational DataBase Connectivity

Slide 14

Slide 14 text

Part 2: R2DBC https://r2dbc.io

Slide 15

Slide 15 text

R2DBC by Pivotal NDBC Jasync Vert.x async DB clients ADBA

Slide 16

Slide 16 text

R2DBC Design principles / Based on Reactive Streams Types and Patterns / Completely non-blocking, up to the DB / Utilize wire-protocol for non-blocking implementations / Divide Client API and Driver SPI / Shrink Driver SPI

Slide 17

Slide 17 text

Dependencies / Reactive Streams (1KB jar) / Java 8

Slide 18

Slide 18 text

image credits: Pivotal Other Databases H2

Slide 19

Slide 19 text

image credits: Pivotal Other Databases H2

Slide 20

Slide 20 text

R2DBC SPI - Specification

Slide 21

Slide 21 text

JDBC API vs R2DBC SPI for drivers for drivers for clients

Slide 22

Slide 22 text

R2DBC SPI / ConnectionFactory / Connection / Statement / Result / RowMetadata / Row image credits: Jonathan Bregler

Slide 23

Slide 23 text

R2DBC SPI - Connection / Batch createBatch() / Statement createStatement(String sql) / Publisher beginTransaction() / Publisher commitTransaction() / Publisher rollbackTransaction() / Publisher rollbackTransactionToSavepoint(String name) / Publisher setTransactionIsolationLevel(IsolationLevel level) / Publisher createSavepoint(String name) / Publisher releaseSavepoint(String name) / Publisher close()

Slide 24

Slide 24 text

R2DBC SPI - Statement / Statement add() / Statement bind(Object identifier, Object value) / Statement bindNull(Object identifier, Class type) / Publisher execute() / Statement returnGeneratedValues(String... columns)

Slide 25

Slide 25 text

R2DBC SPI - Result / Publisher getRowsUpdated() / Publisher map(BiFunction f)

Slide 26

Slide 26 text

R2DBC SPI - Row / T get(Object identifier, Class type)

Slide 27

Slide 27 text

SPI: Connection factory H2ConnectionConfiguration conf = H2ConnectionConfiguration.builder() .url("mem:db") .build(); ConnectionFactory connectionFactory = new H2ConnectionFactory(conf);

Slide 28

Slide 28 text

SPI: Simple select connectionFactory .create() .flatMapMany(conn -> conn.createStatement("SELECT currency, price FROM trades") .execute() .flatMap(result -> result .map((row, metadata) -> row.get("currency"))))

Slide 29

Slide 29 text

SPI: Batch insert connectionFactory .create() .flatMapMany(conn -> conn.createStatement( “INSERT INTO trades (currency, market, price) “ + "VALUES (?, ?, ?)") .bind(0, "EUR").bind(1, "TD").bind(2, 7.0).add() .bind(0, "UAH").bind(1, "TX").bind(2, 6.0).add() .execute())

Slide 30

Slide 30 text

SPI: Transactions connectionFactory .create() .flatMapMany(conn -> conn.beginTransaction() .thenMany(conn.createStatement( "INSERT INTO trades (currency, market, price) " + "VALUES (?, ?, ?)") .bind(0, "UAH").bind(1, "TX").bind(2, "B") .execute()) .delayUntil(p -> conn.commitTransaction()) .onErrorResume(t -> conn .rollbackTransaction() .then(Mono.error(t)))) try-with-resources

Slide 31

Slide 31 text

image credits: Pivotal Other Databases H2

Slide 32

Slide 32 text

R2DBC Client R2dbc r2dbcClient = new R2dbc(connectionFactory); r2dbcClient .withHandle(handle -> handle.createUpdate( "INSERT INTO trades (currency, market, price) " + "VALUES ($1, $2, $3)") .bind("$1", "UAH").bind("$2", "TX").bind("$3", 3.4) .execute())

Slide 33

Slide 33 text

R2DBC Client: Transactions r2dbcClient .inTransaction(handle -> handle.createUpdate( "INSERT INTO trades (currency, market, price) " + "VALUES ($1, $2, $3)") .bind("$1", "UAH").bind("$2", "TX").bind("$3", 3.4) .execute())

Slide 34

Slide 34 text

Stream Processing

Slide 35

Slide 35 text

Stream processing pgConnection .createStatement("LISTEN user_login_notifications”) .execute() .flatMap(PostgresqlResult::getRowsUpdated) .subscribe(); pgConnection .getNotifications() .map(Notification::getParameter) .subscribe(event -> { // do something useful });

Slide 36

Slide 36 text

image credits: Pivotal Other Databases H2

Slide 37

Slide 37 text

Drivers: supported databases

Slide 38

Slide 38 text

2018 StackOverflow survey Reactive Spring Data R2DBC

Slide 39

Slide 39 text

Using R2DBC with Spring

Slide 40

Slide 40 text

Spring Boot Starter for R2DBC / Driver discovery by URL (r2dbc:mysql://…) / ConnectionFactory / TransactionManager / Actuator integration / Embedded H2 / schema.sql and data.sql / @DataR2dbcTest

Slide 41

Slide 41 text

public interface UsSalesR2dbcRepository extends R2dbcRepository { @Query("select * from us_sales_by_districts") Flux findAll(); @Query("select * from us_sales_by_districts, where code=:code") Mono findById(@Param("code") String code); } Spring Data R2DBC

Slide 42

Slide 42 text

Spring Data Repository & Transactions? @Component class TransactionalService { private CustomerRepository repository; @Transactional public Mono save(Customer customer) { return repository.save(customer).map(it -> { if (it.firstname.equals("Dave")) { throw new IllegalStateException(); } else { return it; } }); } }

Slide 43

Slide 43 text

Caveats / Requires Project Reactor (Context) / May not work with RxJava / Some Rx operators may cancel subscription / Flux.take(10) / Flux.next()

Slide 44

Slide 44 text

How R2DBC drivers work?

Slide 45

Slide 45 text

r2dbc-postgres PostgreSQL wire-protocol TCP

Slide 46

Slide 46 text

r2dbc-postgres PostgreSQL

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

Where is back pressure?

Slide 49

Slide 49 text

Portal - Pg protocol feature handles back pressure 2 4

Slide 50

Slide 50 text

Downsides of R2DBC

Slide 51

Slide 51 text

JPA? / No Hibernate / No EclipseLink / No JPA so far? / But: Hibernate Rx

Slide 52

Slide 52 text

Longer Queries / DBs rushing to deliver data / Back pressure may delay data delivery

Slide 53

Slide 53 text

Longer Transactions / Back pressure may cause more contention / JDBC may be faster than R2DBC / R2DBC may impact DB internals

Slide 54

Slide 54 text

Wire-protocol & DB design requirements / Should allow data streaming / Should allow back pressure / Support query cancellation / Conform to Reactive Streams semantics / Connection multiplexing? / RSocket?

Slide 55

Slide 55 text

R2DBC Goodies / r2dbc-proxy / r2dbc-pool (connection pooling)

Slide 56

Slide 56 text

R2DBC Roadmap / 0.8.0 GA in 2019 / 0.9.0: / Extended transaction API / EventProvider / Stored Procedures / More R2DBC support in DB-related libraries

Slide 57

Slide 57 text

Fun Part: Demo

Slide 58

Slide 58 text

App (WebFlux) PostgreSQL TCP Reactive Spring Data R2DBC Driver

Slide 59

Slide 59 text

Dirty Part: Writing code!

Slide 60

Slide 60 text

PrestoDB R2DBC Driver

Slide 61

Slide 61 text

source: https://stackshare.io/presto

Slide 62

Slide 62 text

PrestoDB vs PrestoSQL

Slide 63

Slide 63 text

source: http://starburstdata.com

Slide 64

Slide 64 text

source: http://starburstdata.com HTTP

Slide 65

Slide 65 text

image credits: Pivotal PrestoDB

Slide 66

Slide 66 text

r2dbc-presto Presto wire-protocol HTTP SQL

Slide 67

Slide 67 text

What we need? / Java / R2DBC SPI / Project Reactor / Java 11 HTTP client (or reactor-netty) / JSON parsing libs / Presto instance

Slide 68

Slide 68 text

Get hands dirty! coding session

Slide 69

Slide 69 text

r2dbc-presto

Slide 70

Slide 70 text

Last Part: Moral

Slide 71

Slide 71 text

R2DBC Pros / New and shiny / Brings reactive to DB access / Active community, huge momentum / Easy to implement drivers

Slide 72

Slide 72 text

R2DBC Cons / Still not GA (current: 0.8 RC2) / No JPA (Hibernate/EclipseLink) / Reactive approach may not fit SQL / Reactive programming is under a thread

Slide 73

Slide 73 text

Fibers & Coroutines attack

Slide 74

Slide 74 text

Fibers/Coroutines Cons / Light-weight threads / C#, JS has async/await / Go, Kotlin has green threads / Write blocking, synchronous code / Don’t use FP, write imperative code / Use JDBC/JPA

Slide 75

Slide 75 text

/ Nonblocking / Usually asynchronous / Declarative / Processing streams / Resilient / Back pressure / Reactive Streams Standart Reactive vs Fibers/Coroutines Kotlin Coroutine’s Flow Java / JS / C++ / C# … May be simulated with channels No external libraries

Slide 76

Slide 76 text

Summary / Will have reactive DB access, soon / Spring Data drives R2DBC / It is time to try R2DBC! / Reactive vs Fibers: friends or foes?

Slide 77

Slide 77 text

Q&A Thank you! /aigor /siromaha /ihor.lozinsky