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

Server Side Kotlin Meetup vol.16: 内部動作を理解して ハイパ...

Avatar for ternbusty ternbusty
October 10, 2025

Server Side Kotlin Meetup vol.16: 内部動作を理解して ハイパフォーマンスなサーバサイド Kotlin アプリケーションを書こう

Avatar for ternbusty

ternbusty

October 10, 2025
Tweet

Other Decks in Programming

Transcript

  1. ˜-:$PSQPSBUJPO  "ZBLP)BZBTBLB -*/&Ϡϑʔגࣜձࣾ 4PGUXBSF&OHJOFFS ೥౓ೖࣾ 48"5ͱͯ͠ 8FCόοΫΤϯυྖҬͰશࣾԣஅతͳ ٕज़ࢧԉΛ࣮ࢪ ϝΠϯ͸

    4QSJOH#PPU +BWB  ,PUMJO • 3"(ٕज़Λར༻ͨ͠ۀ຿ޮ཰Խπʔϧ 4FFL"* ։ൃ • :BIPP஌ܙାͷ "*ճ౴ػೳʮΈΜͳͷ஌ܙାʯ։ൃ • ੜ੒"*Λར༻ͨ͠ 2"ྖҬͷੜ࢈ੑ޲্πʔϧ։ൃ • :BIPP͖ͬͣϑΟϧλϦϯάػೳ "*ಋೖ ˜-:$PSQPSBUJPO
  2. ˜-:$PSQPSBUJPO 4QSJOH.7$Ͱͷγϯϓϧͳ࣮૷  ·ͣ͸ΫϥγΧϧͳ࣮૷͔Β 1. Get request on thread#44 2.

    Start simulation on thread#44 3. End simulation on thread#44 4. Return response on thread#44 @GetMapping("/io-heavy") fun ioHeavy(): String { val result = classicService.ioHeavyTask() return result } fun ioHeavyTask(): String { Thread.sleep(1000) return "Simulating I/O finished" } ΫϥγΧϧͳ.7$Ͱ͸SFRVFTU͸ऴ࢝UISFBEͰॲཧ͞ΕΔ
  3. ˜-:$PSQPSBUJPO ผεϨουϓʔϧʹ *0ॲཧΛҠৡͯ͠ΈΔ  "TZOD $PNQMFUBCMF'VUVSF Λಋೖ 1. Get request

    on thread#44 2. Start simulation on thread IoTask-1 3. End simulation on thread IoTask-1 @GetMapping("/io-heavy") fun ioHeavy() { val task1 = asyncService.ioHeavyTask() task1.thenApply { "Simulating I/O finished" } } @Async("ioTaskExecutor") fun ioHeavyTask(): CompletableFuture<String> { Thread.sleep(1000) return CompletableFuture.completedFuture<String?>("Sim ulating I/O finished") } 4. Return response on thread IoTask-1
  4. ˜-:$PSQPSBUJPO • ࣮૷্ͷ՝୊ • ϦΫΤετ్தͰεϨου͕มΘΔͨΊɺ5ISFBE-PDBM ͕࢖͑ͳ͍ • ద੾ʹεϨουϓʔϧΛઃఆ͠ͳ͍ͱɺແݶʹεϨουΛ্ཱͪ͛ଓ͚Δ • ΋ͬͱࠜຊతͳ໰୊

    • 5PNDBUεϨουͷރׇ͸๷͛Δ͕ɺ݁ہผͷεϨουϓʔϧΛCMPDL͍ͯ͠ΔͷͰϦ ιʔεͷແବʹͳΔ ˠ 04ͷεϨουΛCMPDL͢ΔͷΛ΍Ί͍ͨʂ  "TZOD $PNQMFUBCMF'VUVSF Ͱͷ՝୊ ผεϨουϓʔϧʹ *0ॲཧΛҠৡͯ͠ΈΔ
  5. ˜-:$PSQPSBUJPO • ιέοτΛϊϯϒϩοΩϯάϞʔυͰར༻ • SFBE TZTDBMM ͷ݁Ռ͕ଈ࠲ʹฦΔΑ͏ʹͳΓɺσʔλͷ౸ணޙ͸FQPMM ʹΑΔ௨஌Λड͚ͯ݁ ՌΛॲཧ͢Δ •

    ͜ΕΒͷॲཧ͸&WFOU-PPQ εϨου͕ߦ͏  ϊϯϒϩοΩϯάͳ *0ͱ͸ &WFOU-PPQ SFBE  SFBE  FQPMM ड͚औͬͨ SFBE ݁Ռͷॲཧ SFBE 
  6. ˜-:$PSQPSBUJPO • SFBE ΛDBMM͢ΔΠϕϯτϧʔϓεϨουͱɺͦͷ݁ՌΛड͚औͬͯॲཧ͢ΔΠϕϯτϧʔϓεϨου ͸ผʹͳΓ͏Δ  4QSJOH8FC'MVY Ͱͷ࣮૷ྫ 1. Get

    request on thread#43 2. Start simulation on thread#43 3. End simulation on thread#72 fun ioHeavyTask(): Mono<String> = mono { delay(1000) "Simulating I/O finished" } @GetMapping("/io-heavy") fun ioHeavy(): Mono<String> = mono { reactiveService.ioHeavyTask().awaitSingle() "Simulating I/O finished" }
  7. ˜-:$PSQPSBUJPO ϊϯϒϩοΩϯά*0ʹΑΓඇৗʹߴ͍ੑೳ ΛތΔ • ॻ͖ํ͕ಛघ  • 5ISFBE-PDBM ͕࢖͑ͳ͍ •

    ͏͔ͬΓϒϩοΩϯάॲཧΛ͢ΔͱΠϕϯ τϧʔϓ͕ࢭ·ͬͯେม·͍ͣ • ϊϯϒϩοΩϯάͳϥΠϒϥϦ 3%#$ͳͲ Λ࢖͓͏ • Ͳ͏ͯ͠΋ϒϩοΩϯά͍ͨ͠৔߹ ͸ผεϨουϓʔϧʹ੾Γग़ͦ͏ ϝϦοτ σϝϦοτ  4QSJOH8FC'MVY Λར༻͢ΔϝϦοτɾσϝϦοτ  ,PUMJO$PSPVUJOFͱ૊Έ߹ΘͤΕ͹গ͠Θ͔Γ΍͘͢͸ͳΓ·͢
  8. ˜-:$PSQPSBUJPO • ΫϥγΧϧͳ࣮૷ͱιʔείʔυ͸શ͘Ұॹ  7JSUVBM5ISFBE 75 Λ༻͍࣮ͨ૷ྫ @GetMapping("/io-heavy") suspend fun

    ioHeavy(): String { val result = virtualService.ioHeavyTask() return result } fun ioHeavyTask(): String { Thread.sleep(1000) return "Simulated I/O finished" } 1. Get request on VirtualThread#63 2. Start simulation on VirtualThread#63 3. End simulation on VirtualThread#63 4. Return response on VirtualThread#63 SFRVFTU͸ऴ࢝ಉ͡ WJSUVBMUISFBEͰॲཧ͞ΕΔ
  9. ˜-:$PSQPSBUJPO • #MPDLJOHͳTZTDBMM ΛݺΜͰ͍Δ͕ɺ࣮ ࡍͷ*0଴ͪͷؒ͸ΞϯϚ΢ϯτ͞ΕΔͷ Ͱ04εϨου͸ϒϩοΫ͞Εͳ͍ඇ ৗʹੑೳ͕Α͍ • Կ΋ߟ͑ͣʹϒϩοΩϯά*0ͳϥΠϒϥ ϦΛݺΜͰ΋໰୊ͳ͍

    • 8FC'MVY ͷಠಛͳه๏Λֶश͢Δ͜ͱͳ ͘ɺ.7$νοΫͳॻ͖ํ͕Մೳ • ΞϓϦέʔγϣϯ͔ΒݟΔͱಉҰͷεϨο υͳͷͰ5ISFBE-PDBM ͕࢖͑Δ • +%,͔Βొ৔ͨͨ͠Ί࣮૷ྫ͕গͳ͍ • ར༻͍ͯ͠ΔϥΠϒϥϦʹTZODISPOJ[FE ϒϩοΫ͕ଘࡏ͢Δͱɺ$5͕ղ์͞Εͳ ͘ͳΔ QJOOJOH໰୊ • +%,Ͱमਖ਼ࡁΈ • ͳͷͰɺ͍ͭઌ೔ ೥݄  ϦϦʔε͞Εͨ +BWB -54൛  Ͱ΋मਖ਼൛͕ར༻ՄೳͰ͢ʂ ϝϦοτ σϝϦοτ  7JSUVBM5ISFBEΛ࢖͏ϝϦοτɾσϝϦοτ
  10. ˜-:$PSQPSBUJPO • ؀ڥ • ࣾ಺ LTج൫ʹ্ཱͪ͛ͨΞϓϦέʔγϣϯʹରͯ͠ɺࣾ಺ج൫্ͷ 7.͔Βෛՙࢼݧπʔϧ WFHFUB Λ༻͍ͯେྔϦΫΤετ •

    SQTɺEVSBUJPOT • 3QT Λ ্͍ͣͭ͛ͯͬͯɺϨεϙϯεʹ TҎ্͔͔ͬͨ࣌఺ͰࣦഊͱΈͳ͢ • ϚγϯεϖοΫ • $16Nɺ.FNPSZ.ɺSFQMJDB • ΞϓϦέʔγϣϯ • ֤ϑϨʔϜϫʔΫʹ͍ͭͯɺTTMFFQͯ͠ϨεϙϯεΛฦ͢ FOEQPJOUΛ࣮૷ • 4QSJOH#PPU +%, ,PUMJO  ੑೳࢼݧ֓ཁ
  11. ˜-:$PSQPSBUJPO • 8FC'MVY 7JSUVBM5ISFBE͸ϊϯϒϩοΩϯά*0ͳͷͰΫϥγΧϧͳ࣮૷ΑΓੑೳ͕Α͍ͩΖ͏ • 7JSUVBM5ISFBE͸8FC'MVY ͱൺֱͯ͠ੑೳతʹྼΓͦ͏ • 5ISFBE-PDBM ͳͲΛอ࣋͢Δඞཁ͕͋Γɺ8FC'MVY

    ܥ΄ͲͷܰྔͳλεΫ੾Γସ͑͸Ͱ͖ͳ͍ͩΖ͏ • 8FC'MVY Ͱ͏͔ͬΓϒϩοΩϯάͳॲཧΛॻ͘ͱ͔ͳΓੑೳ͕མͪͦ͏ • ΠϕϯτϧʔϓΛࢭΊΔͱେมͳ͜ͱʹͳΔͨΊ  ੑೳࢼݧԾઆ
  12. ˜-:$PSQPSBUJPO  ੑೳࢼݧ8FC'MVY ͰϒϩοΩϯάॲཧΛͯ͠͸μϝ suspend fun ioHeavyTask(): String { Thread.sleep(1000)

    return "Simulated I/O finished" } • ݁ՌSQT΋ड͚෇͚ΒΕͳ͘ͳͬͨ • ڭ܇FWFOUMPPQ ΛࢭΊͯ͸͍͚ͳ͍ɻͲ͏ͯ͠΋ඞཁʹͳͬͨΒ ผͷεϨουϓʔϧʹ੾Γग़ͦ͏
  13. ˜-:$PSQPSBUJPO  "TZOD $PNQMFUBCMF'VUVSF Ͱͷඇಉظॲཧ @GetMapping("/io-heavy") fun ioHeavyParallel(): CompletableFuture<String?> {

    val task1 = asyncService.ioHeavyTask() val task2 = asyncService.ioHeavyTask() return CompletableFuture.allOf(task1, task2) .thenApply<String?>(Function { "Simulated I/O results: " + task1.join() + ", " + task2.join() }) } @Async("ioTaskExecutor") fun ioHeavyTask(): CompletableFuture<String> { Thread.sleep(1000) return CompletableFuture.completedFuture<String>("Simula ted I/O finished") } 1. Start simulation on thread IoTask-4 1. Start simulation on thread IoTask-5 2. Start simulation on thread IoTask-4 2. Start simulation on thread IoTask-5 ඵޙ
  14. ˜-:$PSQPSBUJPO • *0଴ͪʹೖͬͨ࣌ʹɺͦΕΛ ࣮ߦ͍ͯͨ͠ίϧʔνϯΛ͍ͬ ͨΜதஅ TVTQFOE ͠ɺͦͷ ؒಉ͡εϨουͷ্Ͱଞͷί ϧʔνϯΛ࣮ߦͰ͖Δ •

    %JTQBUDIFSΛࢦఆͯ͠ɺλε ΫΛ࣮ߦ͢ΔεϨουϓʔϧͷ ࢦఆ΋Ͱ͖Δ • ඇಉظॲཧ͕؆ܿʹॻ͚Δ  ,PUMJO$PSPVUJOF @GetMapping("/io-heavy") suspend fun ioHeavy(): String = coroutineScope { val job1 = async { coroutineService.ioHeavyTask() } val job2 = async { coroutineService.ioHeavyTask() } job1.await() job2.await() "Simulating I/O finished" } suspend fun ioHeavyTask(): String = withContext(Dispatchers.IO) { delay(1000) "Simulating I/O finished" }
  15. ˜-:$PSQPSBUJPO • ϦΫΤετͷड͚औΓ • 5PNDBUͷεϨουϓʔϧ಺ͷεϨου σϑΥϧταΠζ  • Կࣄ΋ͳ͚Ε͹ͦͷ··Ϩεϙϯεฦ٫·ͰಉҰεϨουͰ໘౗ΛݟΔ͜ͱʹͳΔ •

    Ͱ͸εϨου͕੾ΓସΘΔͷ͸Ͳ͏͍͏ͱ͖ʁ • $PSPVUJOFͷ TVTQFOEޙʹ෮ؼ͢Δͱ͖ • XJUI$POUFYU %JTQBUDIFST*0 ౳Ͱ໌ࣔతͳεϨουϓʔϧ੾Γସ͑Λߦͬͨͱ͖ • ͜͜Ͱੜ͡Δٙ໰ • εϨου͕੾ΓସΘͬͨࡍɺϦΫΤετΛड͚औͬͨݩͷεϨου͸Ͳ͏ͳΔʁ • ղ์͞ΕͯଞͷϦΫΤετΛड͚෇͚ΒΕΔΑ͏ʹͳΔ PS߆ଋ͞Εͨ··ʁ • 4VTQFOEޙʹ෮ؼ͢Δ࣌͸ɺͲ͜ͷεϨουʹ໭ͬͯ͘Δʁ  4QSJOH.7$ ,PUMJO$PSPVUJOFͷλεΫ͸ ͲͷεϨουͰͲ͏࣮ߦ͞ΕΔʁ ˠ౴͑ύϑΥʔϚϯεʹ΋ؔ܎͢ΔͷͰ࣍εϥΠυҎ߱Ͱਂ۷Γ
  16. ˜-:$PSQPSBUJPO  ϦΫΤετΛड͚औͬͨݩͷεϨου͸Ͳ͏ͳΔʁ ॻ͖ํʹΑͬͯڍಈ͕ҟͳΔ @GetMapping("/io-heavy") fun ioHeavySerial(): String = runBlocking

    { coroutineService.ioHeavyTask() "Simulating I/O finished" } @GetMapping("/io-heavy") suspend fun ioHeavy(): String { coroutineService.ioHeavyTask() return "Simulating I/O finished" } SVO#MPDLJOH Λར༻͢Δ৔߹ ϦΫΤετΛड͚෇͚ͨεϨου͸ ଞͷεϨο υʹॲཧΛҠৡͨ͠ͱͯ͠΋ɺͦͷॲཧ͕ऴΘΔ ·Ͱ ϒϩοΫ͞Εଓ͚Δ 3FTQPOTF΋࠷ऴతʹ͸ݺͼग़͠ݩεϨου͔Β ฦ٫͞ΕΔ $POUSPMMFSΛ TVTQFOEؔ਺ʹ͢Δ৔߹ 4QSJOHҎ߱͸ɺ.7$ͷ $POUSPMMFSͰ΋ TVTQFOEؔ਺͕ѻ͑ΔΑ͏ʹͳͬͨ  %JTQBUDIPS TVTQFOE Λͨ͠ॠؒʹݺͼग़͠ݩͷ εϨουͷख͔Β཭Εɺ׬ྃ·ͰϒϩοΫ͞Εͳ͍  PSHKFUCSBJOTLPUMJOYLPUMJOYDPSPVUJOFTSFBDUPS Λґଘʹ௥Ճ͢Δඞཁ͋Γ
  17. ˜-:$PSQPSBUJPO  ϦΫΤετΛड͚औͬͨݩͷεϨου͸Ͳ͏ͳΔʁ ෛՙࢼݧͰͷݕূ݁Ռ  ϦΫΤετ εϨουͱ͍͏ 4QSJOH.7$Ͱͷݪଇ͔Β֎ΕɺҰ౓ TVTQFOE͢ΔͱϦΫΤετΛड͚෇͚ͨεϨουʹ໭ͬͯ͜ͳ͍͜ͱʹͳΓ·͢ɻ .%$ͳͲ΋ਧ͖ඈΜͰ໭͖ͬͯ·ͤΜɻඞཁʹԠͯ͡

    .%$$POUFYU ͳͲͰҾ͖ܧ͙Α͏ʹ͍ͯͩ͘͠͞ɻ • ෛՙࢼݧͷ৚݅ઌड़ͷ௨Γ • ݁Ռ SQT SVO#MPDLJOH $POUSPMMFSΛ 4VTQFOEؔ਺ʹ • 314Λ૿΍͢ʹͭΕɺSVO#MPDLJOH Λ ར༻͍ͯ͠ΔํͰ͸SFTQPOTFUJNF͕ ѱԽ͍ͯͬͨ͠ • $POUSPMMFSΛTVTQFOEؔ਺ʹ͢ Δ͚ͩͰεϨουͷϒϩοΫ͕๷ࢭ ͞Εɺੑೳ͕޲্͢ΔՄೳੑ͕͋Δ 
  18. ˜-:$PSQPSBUJPO  4VTQFOEޙʹͲ͜ͷεϨουʹ෮ؼ͢Δʁ ύϑΥʔϚϯε͕ग़Δͷ͸Ͳͬͪʁ suspend fun ioHeavyAfterDelayTask(): String { delay(1000)

    Thread.sleep(1000) return "Simulated I/O finished" } suspend fun delayAfterIoHeavyTask(): String { Thread.sleep(1000) delay(1000) return "Simulated I/O finished" } @GetMapping("/test") suspend fun test(): String = coroutineScope { // ͜͜Ͱؔ਺ݺͼग़͠ } PS
  19. ˜-:$PSQPSBUJPO  4VTQFOEޙʹͲ͜ͷεϨουʹ෮ؼ͢Δʁ ύϑΥʔϚϯε͕ग़Δͷ͸Ͳͬͪʁ suspend fun ioHeavyAfterDelayTask(): String { delay(1000)

    Thread.sleep(1000) return "Simulated I/O finished" } suspend fun delayAfterIoHeavyTask(): String { Thread.sleep(1000) delay(1000) return "Simulated I/O finished" } @GetMapping("/test") suspend fun test(): String = coroutineScope { // ͜͜Ͱؔ਺ݺͼग़͠ } ࣮࣭తʹ SQT͔͠ड͚෇͚ΒΕͳ͍ ΫϥγΧϧͳ࣮૷ͱಉఔ౓ͷύϑΥʔϚϯε͸ग़Δ
  20. ˜-:$PSQPSBUJPO  %JTQBUDIFST6ODPOGJOFE ͷڍಈʹ஫ҙ Started task on thread: Thread[#45,http-nio- 8080-exec-1,5,main]

    Finished task on thread: Thread[#74,kotlinx.coroutines.DefaultExecutor, 5,main] %FMBZͰ TVTQFOE 4VTQFOE͔Β DPSPVUJOFΛ෮ؼ ͤ͞Δͷ͸λΠϚʔ༻ͷΠϕϯτ ϧʔϓ %FGBVMU&YFDVUPS 4QSJOHͷ TVTQFOEϋϯυϥ͸ɺ %JTQBUDIFST6ODPOGJOFE Ͱىಈ ͍ͯ͠Δ ϙΠϯτʂ %JTQBUDIFST6ODPOGJOFE ͸෮ؼޙͷ UISFBEQPPMΛ໌ࣔతʹࢦఆ͠ͳ͍ͨΊɺ෮ ؼͷͨΊʹར༻͞ΕͨεϨουͰ෮ؼޙͷ ॲཧ͕࣮ߦ͞ΕΔ ˣ ຊ͔͠ͳ͍%FGBVMU&YFDVUPS Ͱͦͷޙͷ ॲཧ͕࣮ߦ͞Εͯ͠·͏ͷͰɺ εϧʔϓοτ͕ஶ͘͠௿Լ͢Δ https://github.com/spring-projects/spring-framework/issues/33788 suspend fun ioHeavyAfterDelayTask(): String { logger.info("Started task on thread: ${Thread.currentThread()}") delay(1000) Thread.sleep(1000) logger.info("finished task on thread: ${Thread.currentThread()}") return "Simulating I/O finished" } ࢥΘ͵εϨουͰॲཧ͕࣮ߦ͞Ε͏Δ
  21. ˜-:$PSQPSBUJPO  %JTQBUDIFST6ODPOGJOFE ͷڍಈʹ஫ҙ ͜ΕͳΒ 5ISFBETMFFQ ͸ UPNDBUεϨουͰ࣮ߦ͞ΕΔ ͚ͩͳͷͰେ͖ͳ໰୊ʹ͸ͳΒͳ͍ Ͱ͸Ͳ͏ͨ͠Β͍͍ʁ

    suspend fun delayAfterIoHeavyTask(): String { Thread.sleep(1000) delay(1000) return "Simulating I/O finished" } suspend fun ioHeavyAfterDelayWithDispatcherTask() = withContext(Dispatchers.IO) { delay(1000) Thread.sleep(1000) "Simulating I/O finished" } %JTQBUDIFSΛ໌ࣔతʹࢦఆ͢Ε͹ ෮ؼޙ͸ͦͷεϨουϓʔϧ಺ͷ εϨουʹ໭ͬͯ͘ΔͷͰ໰୊ͳ͍
  22. ˜-:$PSQPSBUJPO • ඇಉظॲཧΛγϯϓϧʹॻ͚Δ • 8FC'MVY ͱͷซ༻΋Ͱ͖Δɻͦͷ৔߹ɺ 8FC'MVY ಠಛͷॻ͖ํΛආ͚ͯಉظతͳ ॻ͖ํ͕Ͱ͖Δɻ •

    7JSUVBM5ISFBEͱҧͬͯϢʔβϨϕϧͷ λεΫ؅ཧʹ͗͢ͳ͍ͷͰɺϒϩοΩϯά *0Λݺͼͩ͢ͱ04εϨου͸ϒϩοΫ ͞ΕΔ • 4QSJOH.7$ͱซ༻͢Δࡍͷ஫ҙ • SVO#MPDLJOH Λར༻͢ΔͱϦΫΤε τΛड͚औͬͨ UPNDBUεϨουΛ ߆ଋ͠ɺύϑΥʔϚϯεʹӨڹ͢Δ • %JTQBUDIFST6ODPOGJOFE ͷڍಈʹ ཁ஫ҙɻඞཁʹԠͯ͡ %JTQBUDIFS Λར༻͢ΔͳͲͷ޻෉Λ ϝϦοτ σϝϦοτ  ,PUMJO$PSPVUJOFΛ࢖͏৔߹ͷ ϝϦοτɾσϝϦοτ
  23. ˜-:$PSQPSBUJPO  ·ͱΊ • ֤ϑϨʔϜϫʔΫ͕ͲͷΑ͏ʹ *0ό΢ϯυͳॲཧΛ࣮ߦ͍ͯ͠Δͷ͔Λཧղ͠Α͏ • 4QSJOH8FC'MVY ΍7JSUVBM5ISFBEΛར༻͢Ε͹ύϑΥʔϚϯε͸্͕Δ͕ɺͦͷ࢓૊Έ΍ɺ ࠾༻ʹΑΔϝϦοτɾσϝϦοτΛ೺Ѳ͓ͯ͘͜͠ͱ͕ॏཁ

    • ʮϒϩοΩϯά PSϊϯϒϩοΩϯάʯͱʮಉظ PSඇಉظʯ͸ผͷϨΠϠͷ࿩ • 4QSJOH.7$ͱ ,PUMJO$PSPVUJOFΛซ༻͢Δ৔߹͸ɺ֤λεΫ͕ͲͷεϨουͰ࣮ߦ͞Ε͍ͯΔ͔ʹ ஫ҙ͠Α͏