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

R2DBCでAPIの高速化をしようとしてやめた話

yy_yank
September 02, 2022

 R2DBCでAPIの高速化をしようとしてやめた話

FORCASというプロダクトの開発でR2DBCをやろうとしていた話です
R2DBC(MySQL) + Spring Boot + Kotlin + Kotlin Coroutines

参考リンク集
https://gist.github.com/yyYank/cbcf8074b3b3bfa0fd68d9fc00cb6e73

yy_yank

September 02, 2022
Tweet

More Decks by yy_yank

Other Decks in Programming

Transcript

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

    View Slide

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

    View Slide

  3. 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.

    View Slide

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

    View Slide

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

    View Slide

  6. 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.

    View Slide

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

    View Slide

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

    View Slide

  9. 01 |
    R2DBCとSpring BootとKotlin
    Coroutines

    View Slide

  10. 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

    View Slide

  11. 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

    View Slide

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

    View Slide

  13. 13
    ・データ量が増えてくるエンドポイントが将来
    的に鈍化するのを防ぐことが出来るかもしれな

    This Improvements might prevent endpoints with increasing data
    volumes from slowing down in the future
    R2DBCとSpring BootとKotlin Coroutines

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  20. 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

    View Slide

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

    View Slide

  22. 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"

    View Slide

  23. 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"

    View Slide

  24. 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()
    }
    }

    View Slide

  25. 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() }
    }
    }

    View Slide

  26. 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() }
    }
    }

    View Slide

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

    View Slide

  28. 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() }
    }
    }

    View Slide

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

    View Slide

  30. 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() }
    }
    }

    View Slide

  31. 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

    View Slide

  32. 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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  36. 03 |
    まとめ

    View Slide

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

    View Slide

  38. 38
    まとめ

    View Slide

  39. 39
    まとめ

    View Slide

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

    View Slide