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

  2. 自己紹介 やんく(@yy_yank) 株式会社ユーザベースのプログラマ。 Product Team 所属。 最近はNewsPicks Stage.の開発に関わっています。 Java, Kotlin,

    Goが好き。最近はRustを書いています。 過去にKotlin in Actionという本の共同翻訳をしたりしまし た。 2
  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.
  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.
  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
  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.
  7. 7 ・R2DBCの面白さ、ハマりどころ ・Kotlin Coroutinesの実用性、ハマりどころ advantages and difficulties of R2DBC advantages

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

  9. 01 | R2DBCとSpring BootとKotlin Coroutines

  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
  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
  12. 12 ・R2DBCは非同期、速い、最高 asynchronous, fast, best R2DBCとSpring BootとKotlin Coroutines

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

    increasing data volumes from slowing down in the future R2DBCとSpring BootとKotlin Coroutines
  14. 14 ・チームメンバーに提案してもらい、チームと してチャレンジしてみることになりました We decided to trying to this solution

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

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

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

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

    callback { callback { 🥋👐💨 callback {} } } } }
  19. 19 R2DBCとSpring BootとKotlin Coroutines R2DBCを使うには? dependencies { implementation ("org.springframework.boot:spring-boot-starter-data-r2dbc" )

    } ・Spring Data R2DBCを使えばok
  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
  21. 21 R2DBCとSpring BootとKotlin Coroutines R2DBCを呼び出すためにコルーチンの依存を足す dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core' implementation

    'org.jetbrains.kotlinx:kotlinx-coroutines-reactor' }
  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"
  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"
  24. 24 R2DBCとSpring BootとKotlin Coroutines R2DBCはorg.springframework.r2dbc.core.DatabaseClientを使う @Repository class HogeRepository( private val

    dbClient: DatabaseClient ) { fun select(ids: List<String>): Flux<HogeEntity> { 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() } }
  25. 25 R2DBCとSpring BootとKotlin Coroutines R2DBCはコルーチン内で呼び出す @Service class HogeService( private val

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

    repository: hoge.infra.HogeRepository ) { fun fetchHoge(ids: List<String>): List<Hoge> = runBlocking { val hogeFlux = repository.select(ids) val hogeList = hogeFlux.collectList() .awaitSingle() ids.map { id -> async(context = Dispatchers.Default) { // 非同期でデカい処理 Hoge() } }.map{ it.await() } } }
  27. 27 ・runBlockingは org.jetbrains.kotlnx.coroutines-coreの関数で ContextとeventLoopを隠蔽して BlockingCoroutineを生成して引数の関数を実 行してくれる R2DBCとSpring BootとKotlin Coroutines

  28. 28 R2DBCとSpring BootとKotlin Coroutines R2DBCはコルーチン内で呼び出す @Service class HogeService( private val

    repository: hoge.infra.HogeRepository ) { fun fetchHoge(ids: List<String>): List<Hoge> = runBlocking { val hogeFlux = repository.select(ids) val hogeList = hogeFlux.collectList() .awaitSingle() ids.map { id -> async(context = Dispatchers.Default) { // 非同期でデカい処理 Hoge() } }.map{ it.await() } } }
  29. 29 ・reactor.core.publisher.Fluxと reactor.core.publisher.Monoは org.reactivestreams.Publisherの具象実装 R2DBCとSpring BootとKotlin Coroutines

  30. 30 R2DBCとSpring BootとKotlin Coroutines R2DBCはコルーチン内で呼び出す @Service class HogeService( private val

    repository: hoge.infra.HogeRepository ) { fun fetchHoge(ids: List<String>): List<Hoge> = runBlocking { val hogeFlux = repository.select(ids) val hogeList = hogeFlux.collectList() .awaitSingle() ids.map { id -> async(context = Dispatchers.Default) { // 非同期でデカい処理 Hoge() } }.map{ it.await() } } }
  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
  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
  33. 02 | 導入でハマったところ

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

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

    unstable (at the time) 導入でハマったところ
  36. 03 | まとめ

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

  38. 38 まとめ

  39. 39 まとめ

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