Slide 1

Slide 1 text

R2DBCでAPIの高速化をしようとし てやめた話 2022/09/02 Uzabase. Inc, Product Team yy_yank

Slide 2

Slide 2 text

自己紹介 やんく(@yy_yank) 株式会社ユーザベースのプログラマ。 Product Team 所属。 最近はNewsPicks Stage.の開発に関わっています。 Java, Kotlin, Goが好き。最近はRustを書いています。 過去にKotlin in Actionという本の共同翻訳をしたりしまし た。 2

Slide 3

Slide 3 text

3 はじめに ・サーバーサイドでのKotlinに興味がある人に何か知見を共有できればと 思っています ・Kotlin関係なく、Spring BootとR2DBCに興味がある方にとっても何かの 情報になるかなと思っています (Auto Translated Broken English is bellow) I talk about Spring Boot, R2DBC and Coroutines. I would be happy if that becomes the chance to start using Kotlin at Server Side.

Slide 4

Slide 4 text

4 前提 ・サーバーサイドでKotlinを使うことは別にフツウ。何も難しくない ・多くの人にとって使うことが難しくない状況になっている ・サーバーサイドKotlin全般についての自分の所感は以前発表しました https://speakerdeck.com/yyyank/sabasaidokotlintoiuxuan-ze-zhi-toyu zabesu Using Kotlin on the server side is not unusual. That’s easy.

Slide 5

Slide 5 text

5 前提 ・Java 17で良いんじゃない? ・まぁそれもあり。良い選択肢だと思います ・でもどっちか選べと言われたら自分はKotlinかな ・Java17 vs Kotlinに関しては@yusukeさんのこちらが分かりやすい https://youtu.be/gcu7ZaF-Bls?t=791 Java17 is a good choice, but I use Kotlin

Slide 6

Slide 6 text

6 前提 ということで、それ以外の話で思いついたのが今回の話でした FORCASというプロダクトの開発でR2DBCをやろうとしていた 話 What's(Why) Server Side Kotlin ... already discussed Java17 vs Kotlin ... already discussed So this time I decided to talk about this topic.

Slide 7

Slide 7 text

7 ・R2DBCの面白さ、ハマりどころ ・Kotlin Coroutinesの実用性、ハマりどころ advantages and difficulties of R2DBC advantages and difficulties of Coroutines 伝えたいこと

Slide 8

Slide 8 text

R2DBCとSpring BootとKotlin Coroutines 導入でハマったところ まとめ 01 02 03 8 目次

Slide 9

Slide 9 text

01 | R2DBCとSpring BootとKotlin Coroutines

Slide 10

Slide 10 text

10 ・R2DBC(Reactive Relational Database Connectivity)とは Based on the Reactive Streams specification. R2DBC is founded on the Reactive Streams specification, which provides a fully-reactive non-blocking API. Works with relational databases. In contrast to the blocking nature of JDBC, R2DBC allows you to work with SQL databases using a reactive API. Supports scalable solutions. With Reactive Streams, R2DBC enables you to move from the classic “one thread per connection” model to a more powerful and scalable approach. Provides an open specification. R2DBC is an open specification and establishes a Service Provider Interface (SPI) for driver vendors to implement and clients to consume. https://r2dbc.io/ R2DBCとSpring BootとKotlin Coroutines

Slide 11

Slide 11 text

11 Reactive Streams??? ・Reactive Streamsについては過去にJJUGの勉強会で特集があり、参加 したことがありました ・気になる方はご覧ください。今日は割愛 JJUG ナイトセミナー 「Reactive Streams特集」に行ってきました #jjug https://yyyank.blogspot.com/2015/06/jjug-reactive-streams-jjug.html R2DBCとSpring BootとKotlin Coroutines

Slide 12

Slide 12 text

12 ・R2DBCは非同期、速い、最高 asynchronous, fast, best R2DBCとSpring BootとKotlin Coroutines

Slide 13

Slide 13 text

13 ・データ量が増えてくるエンドポイントが将来 的に鈍化するのを防ぐことが出来るかもしれな い This Improvements might prevent endpoints with increasing data volumes from slowing down in the future R2DBCとSpring BootとKotlin Coroutines

Slide 14

Slide 14 text

14 ・チームメンバーに提案してもらい、チームと してチャレンジしてみることになりました We decided to trying to this solution as a team. R2DBCとSpring BootとKotlin Coroutines

Slide 15

Slide 15 text

15 ・小さなマイクロサービスの少しのエンドポイ ントをR2DBCで動かしてみようとした We tried to run a few endpoints of small microservices with R2DBC R2DBCとSpring BootとKotlin Coroutines

Slide 16

Slide 16 text

16 ・1リクエストが600ms→200〜300msとかに なった!!!(当時) response time has improved 600ms → 200-300 ms (at that time)!!!! R2DBCとSpring BootとKotlin Coroutines

Slide 17

Slide 17 text

17 ・ReactorのFluxとMonoもいい感じに Corotuinesと繋ぎ込むことができた ・Reactive特有のメソッドチェインで変換に悩 むところもあまりなかった(かも) R2DBCとSpring BootとKotlin Coroutines

Slide 18

Slide 18 text

18 ちょっとだけコールバックヘルともサヨナラでき た気がした R2DBCとSpring BootとKotlin Coroutines callback { callback { callback { callback { 🥋👐💨 callback {} } } } }

Slide 19

Slide 19 text

19 R2DBCとSpring BootとKotlin Coroutines R2DBCを使うには? dependencies { implementation ("org.springframework.boot:spring-boot-starter-data-r2dbc" ) } ・Spring Data R2DBCを使えばok

Slide 20

Slide 20 text

20 R2DBCとSpring BootとKotlin Coroutines R2DBCを使うには? dependencies { implementation("dev.miku:r2dbc-mysql:0.8.2.RELEASE" ) // or implementation("com.github.jasync-sql:jasync-r2dbc-mysql:2.0.8" ) } ・R2DBCドライバ実装も必要 R2DBCのMySQLドライバ実装に関しては過去にブログに書きました https://yyyank.blogspot.com/2021/02/r2dbc2mysql.html

Slide 21

Slide 21 text

21 R2DBCとSpring BootとKotlin Coroutines R2DBCを呼び出すためにコルーチンの依存を足す dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-reactor' }

Slide 22

Slide 22 text

22 R2DBCとSpring BootとKotlin Coroutines application.yml spring: r2dbc: url: r2dbcs:pool:mysql://localhost:3306/hoge username: mysql-user password: mysql-password pool: initial-size: 10 max-size: 10 validation-query: "select 1"

Slide 23

Slide 23 text

23 R2DBCとSpring BootとKotlin Coroutines application.properties spring.r2dbc.url=r2dbcs:pool:mysql://localhost:3306/hoge spring.r2dbc.username=mysql-user spring.r2dbc.password=mysql-password spring.r2dbc.pool.initial-size=10 spring.r2dbc.pool.max-size=10 spring.r2dbc.pool.validation-query="select 1"

Slide 24

Slide 24 text

24 R2DBCとSpring BootとKotlin Coroutines R2DBCはorg.springframework.r2dbc.core.DatabaseClientを使う @Repository class HogeRepository( private val dbClient: DatabaseClient ) { fun select(ids: List): Flux { return dbClient.sql("select * from hoge where id in (:ids) " ) .bind("ids", ids) .map { row -> HogeEntity( id = checkNotNull(row.get("id", String::class.java)), hoge = checkNotNull(row.get("hoge", java.lang.Integer:: class.java)?.toInt()), fuga = checkNotNull(row.get("fuga", String::class.java)) ) } .all() } }

Slide 25

Slide 25 text

25 R2DBCとSpring BootとKotlin Coroutines R2DBCはコルーチン内で呼び出す @Service class HogeService( private val repository: hoge.infra.HogeRepository ) { fun fetchHoge(ids: List): List = runBlocking { val hogeFlux = repository.select(ids) val hogeList = hogeFlux.collectList() .awaitSingle() ids.map { id -> async(context = Dispatchers.Default) { // 非同期でデカい処理 Hoge() } }.map{ it.await() } } }

Slide 26

Slide 26 text

26 R2DBCとSpring BootとKotlin Coroutines R2DBCはコルーチン内で呼び出す @Service class HogeService( private val repository: hoge.infra.HogeRepository ) { fun fetchHoge(ids: List): List = runBlocking { val hogeFlux = repository.select(ids) val hogeList = hogeFlux.collectList() .awaitSingle() ids.map { id -> async(context = Dispatchers.Default) { // 非同期でデカい処理 Hoge() } }.map{ it.await() } } }

Slide 27

Slide 27 text

27 ・runBlockingは org.jetbrains.kotlnx.coroutines-coreの関数で ContextとeventLoopを隠蔽して BlockingCoroutineを生成して引数の関数を実 行してくれる R2DBCとSpring BootとKotlin Coroutines

Slide 28

Slide 28 text

28 R2DBCとSpring BootとKotlin Coroutines R2DBCはコルーチン内で呼び出す @Service class HogeService( private val repository: hoge.infra.HogeRepository ) { fun fetchHoge(ids: List): List = runBlocking { val hogeFlux = repository.select(ids) val hogeList = hogeFlux.collectList() .awaitSingle() ids.map { id -> async(context = Dispatchers.Default) { // 非同期でデカい処理 Hoge() } }.map{ it.await() } } }

Slide 29

Slide 29 text

29 ・reactor.core.publisher.Fluxと reactor.core.publisher.Monoは org.reactivestreams.Publisherの具象実装 R2DBCとSpring BootとKotlin Coroutines

Slide 30

Slide 30 text

30 R2DBCとSpring BootとKotlin Coroutines R2DBCはコルーチン内で呼び出す @Service class HogeService( private val repository: hoge.infra.HogeRepository ) { fun fetchHoge(ids: List): List = runBlocking { val hogeFlux = repository.select(ids) val hogeList = hogeFlux.collectList() .awaitSingle() ids.map { id -> async(context = Dispatchers.Default) { // 非同期でデカい処理 Hoge() } }.map{ it.await() } } }

Slide 31

Slide 31 text

31 ・org.jetbrains.kotlinx.coroutines.reactive のAwait.ktはPublisherの拡張関数 awaitSingle awaitLast awaitFirstOrElse awaitFirstOrNull awaitFirstOrDefault awaitFirst kotlinx.coroutines has extension for reactivestreams. R2DBCとSpring BootとKotlin Coroutines

Slide 32

Slide 32 text

32 ・org.jetbrains.kotlinx.coroutines.reactive のAwait.ktはPublisherの拡張関数 これによって MonoやFluxなどをawait出来るし Reactive StreamのSPIに準拠した別のリアク ティブ実装でも対応出来る(RxJavaとかVert.x とかAkka Streamsとか) R2DBCとSpring BootとKotlin Coroutines

Slide 33

Slide 33 text

02 | 導入でハマったところ

Slide 34

Slide 34 text

34 ・テストのやり方に試行錯誤 ・Coroutineのテスト、R2DBCのテスト test implementation was trial and error 導入でハマったところ

Slide 35

Slide 35 text

35 ・R2DBCのMySQLドライバが不安定(当時) ・connectionのハングが何度か発生、しかも再 現しない → 安心してリリースできなかった R2DBC's MySQL driver was unstable (at the time) 導入でハマったところ

Slide 36

Slide 36 text

03 | まとめ

Slide 37

Slide 37 text

37 ・導入をしなかったもののR2DBCに可能性を感 じた ・Stableな状態を待って再度チャレンジするの もアリかもしれない まとめ

Slide 38

Slide 38 text

38 まとめ

Slide 39

Slide 39 text

39 まとめ

Slide 40

Slide 40 text

40 サーバサイドでKotlin使っていきましょう Have a nice Kotlin! BTW we are hiring!