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

Kotlin Coroutines と Ktor HTTP Client で作るスケールするタスク実行

Kotlin Coroutines と Ktor HTTP Client で作るスケールするタスク実行

Kotlin Tech Talk 〜Kotlin開発で経験した失敗事例や課題解決の知見共有会〜
https://mercari.connpass.com/event/206751/
で発表した資料です。

主にKotlinのコルーチンを並行タスク処理で使う時のサンプルです。

Hideyuki Takeuchi

April 05, 2021
Tweet

More Decks by Hideyuki Takeuchi

Other Decks in Programming

Transcript

  1. SaaS 連携サーバの課題 SaaS 連携サーバからのHTTP レスポンスが、 2 秒〜20 分 SaaS 連携サーバは各SaaS

    からアカウントの状態を取り込む SaaS 連携サーバは無限に⽔平スケールする想定(GKE) もちろんDDoS っぽくならないようにスロットリングはする
  2. そこから派⽣する課題 「全てのお客さんが使っている、全てのSaaS のアカウント」 100 企業 × 100 SaaS = 10,000

    リクエスト 1,000 企業 × 100 SaaS = 100,000 リクエスト Kotlin/Java でHTTP のブロッキングAPI を利⽤して作ると、 スレッド数の限界を超える
  3. スレッドを利⽤したダメな例 fun main() { val pool = Executors.newFixedThreadPool(4) repeat(10000) {

    // 10,000 タスク pool.submit { // 10 秒レスポンスを待つだけのタスク Thread.sleep(10000L) println("DONE: " + Thread.currentThread().name) } } pool.shutdown() } → 実質4 並列でしか動かず、10 秒に4 つタスクが終わる。 全て終わるまで約7 時間。
  4. 並⾏プログラミング観点から プロセス プリエンプティブマルチタスク メモリ空間: 独⽴ タスク切り替え: OS レイヤー スレッド プリエンプティブマルチタスク

    メモリ空間: 共有 タスク切り替え: OS レイヤー コルーチン ノンプリエンプティブマルチタスク メモリ空間: 共有 タスク切り替え: アプリレイヤー
  5. スレッド vs コルーチン スレッド コルーチン タスク辺りのメモリ使⽤量 多くなる 少ない コンテキストスイッチのオーバーヘッド ある

    少ない プログラムのしやすさ 簡単 難しい (?) プログラムのしやすさは諸説ある コルーチンは、プログラマが他のタスクに、 いつCPU を明け渡すか制御しなければならない。
  6. Coroutines を複数スレッドで⾛らせる正しい例 fun main() { val pool = Executors.newFixedThreadPool(4) runBlocking(pool.asCoroutineDispatcher())

    { repeat(10000) { // 10,000 タスク async { // 10 秒レスポンスを待つだけのタスク delay(10000L) println("DONE: " + Thread.currentThread().name) } } } pool.shutdown() } → 10 秒(10000L) で10000 タスク全部終わる
  7. Coroutines を使ってるけどダメな例 fun main() { val pool = Executors.newFixedThreadPool(4) runBlocking(pool.asCoroutineDispatcher())

    { repeat(10000) { // 10,000 タスク async { // 10 秒レスポンスを待つだけのタスク Thread.sleep(10000L) // delay(10000L) println("DONE: " + Thread.currentThread().name) } } } pool.shutdown() } → 10 秒(10000L) に⼀回4 つタスクが流れるだけ
  8. Ktor HTTP Client https://ktor.io/docs/client.html JetBrains 謹製のフレームワーク「Ktor 」の HTTP Client API

    群 Kotlin coroutines を利⽤した、awesome な HTTP Client ( 意訳) もちろんすべてノンブロッキングAPI
  9. Ktor HTTP Client で HTTP リクエストを投げる fun main() { val

    client = HttpClient() val pool = Executors.newFixedThreadPool(4) runBlocking(pool.asCoroutineDispatcher()) { repeat(10000) { async { val response = client.get<String>("http://localhost:4000/healthcheck") println("DONE [${Thread.currentThread().name}]: $response") } } } pool.shutdown() } → HTTP サーバからレスポンスが待たされたとしても、 他のリクエストが並⾏で実⾏される
  10. Ktor TIPS デフォルトのHTTP 待ち受けスレッドプールの数が Runtime.getRuntime().availableProcessors() (CPU 論理コア数) に 設定される。 クラスタのノードがしょぼいインスタンスだとこれが1

    になって、 本番環境だとなんか動かないと焦る時がある ktor { deployment { connectionGroupSize = < 適切な値> workerGroupSize = < 適切な値> callGroupSize = < 適切な値> } }