30
Blocking & Hyper Context Switching Pattern ScalaMatsuri 2017 ブロッキング&ハイパーコンテキストスイッチパターン

Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Embed Size (px)

Citation preview

Page 1: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Blocking & Hyper Context Switching Pattern

ScalaMatsuri 2017

ブロッキング&ハイパーコンテキストスイッチパターン

Page 2: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Agenda

● Introduction

● How did it happen?

● Importance

● Conclusions

アジェンダ

Page 3: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

About Me

● Takako Shimamoto (@chibochibo03)

● BizReach, Inc. CTO office

● Scala Warrior: Planning / Illustration

自己紹介

Page 4: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Introduction

はじめに

Page 5: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Notes

● In this session, I don't mention the following:

○ Specifications

○ Selection of libraries

● Instead, we'll use a snippet that demonstrates a

failure pattern

仕様や使用ライブラリの議論はしません

コードは再現したものです

Page 6: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

What is it?def delete(id: Long): Future[Unit] = {

val action = for {

_ <- repository.deleteCategory(id)

...

} yield ()

Try { Await.result(db.run(action.transactionally), Duration.Inf) } match { case Success(_) => repository.writeLog()

case Failure(e) => Future.failed(e)

}

}

quite a lot generators

returns DBIO[Unit]

returns Future[Unit]

本日のお題

Page 7: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

What is it?

● This method is called multiple times per request

● Inject the default Play execution context

このメソッドは1リクエストで複数回呼ばれる

Page 8: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Oh boy!

● The number of users was small

● But response speed worsened gradually

利用者が少ないにも関わらず徐々にレスポンス速度が悪化

Page 9: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Dangers

● Resources were not under stress

○ database connections

○ slow queries

○ access log

● Infrastructure monitoring showed well

外からの監視で異常を検知できない

Page 10: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

How did it happen?

何が起きたのか?

Page 11: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

The one problem is ...def delete(id: Long): Future[Unit] = {

val action = for {

_ <- repository.deleteCategory(id)

...

} yield () Try { Await.result(db.run(action.transactionally), Duration.Inf) } match { case Success(_) => repository.writeLog()

case Failure(e) => Future.failed(e)

}

}

quite a lot generators

1つ目の問題は無駄なスイッチング

Page 12: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

The precise meaning

The precise meaning of generators and guards is defined by translation to invocations of four methods: map, withFilter, flatMap, and foreach.

"6.19 For Comprehensions and For Loops". Scala Language Specification. https://www.scala-lang.org/files/archive/spec/2.12/, (参照 2017-01-03)

for式は4つのメソッド呼び出しに変換

Page 13: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Implicit ExecutionContexts

● Provide an execution context to execute the given

functions

○ When calling map or flatMap on an action

● In short, an ExecutionContext is a ThreadPool

mapやflatMapは引数に暗黙のスレッドプールが必要

渡した関数はそこで実行

Page 14: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Using a metaphor

CASHIER

ファーストフード店で例える

1品ずつ注文

One Hamburger.

A small Coffee.

One French Fry.Shop attendant

Page 15: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

What the hell !?

CASHIER

いやいや、まとめて頼めば1回ですむじゃん!

Shop attendant

Gather orders!!

Page 16: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Sequential Execution

● DBIO.seq

● DBIO.sequence

○ takes a number of DBIOActions

まとめて渡せるメソッドを使う

Page 17: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

The other is ...def delete(id: Long): Future[Unit] = {

val action = for {

_ <- repository.deleteCategory(id)

...

} yield ()

Try { Await.result(db.run(action.transactionally), Duration.Inf) }

match { case Success(_) => repository.writeLog()

case Failure(e) => Future.failed(e)

}

}

もう1つの問題はブロッキング

Page 18: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

According to Scaladoc

Await.resultはブロッキング

Although this method is blocking, the internal use of blocking ensures that the underlying ExecutionContext to properly detect blocking and ensure that there are no deadlocks.

"scala.concurrent.Await". SCALA API DOCS. http://www.scala-lang.org/api/2.12.1/scala/concurrent/index.html, (参照 2017-01-03)

Page 19: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Cool names

● More ominous names

○ Oni.blocking(..., Oni.forever)

○ Gachi.blocking(..., Gachi.forever)

● Just kidding! Haha!

名前がカッコよすぎ

鬼ブロック!ガチブロック!(冗談です)

Page 20: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Blocking is evil

● Play is not a traditional web framework

● Play’s thread pools are tuned to use fewer threads

○ IO never blocks

Playは少ないスレッドをブロックせず使い回すスタイル

Page 21: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

The C10K problem

● The number of threads multiplies too much

● Lack of resources such as memory

● CPU not busy

クライアント1万台問題

Page 22: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Transformations

変換やコールバックを使う

● Future's methods:

○ map, flatMap, and so on

● Callbacks

○ onComplete, foreach, and so on

Page 23: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Importance

重要なこと

Page 24: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

JDBC is synchronous

● A typical example of blocking is database access

● An asynchronous framework doesn't like JDBC

JDBCドライバは同期

Page 25: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Slick’s solution

● Wrap blocking code

○ Blocking happens in a different thread

● Slick has its own thread pool

○ All database actions are executed in this pool

Slickは独自でスレッドプールを持つデータベースアクションはそのプールのスレッドで実行

Page 26: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Play default thread pool

● It is an Akka dispatcher

● This execution context is backed by a ForkJoinPool

○ Keeping CPU busy

○ Fewer threads are always awake is desirable

AkkaはForkJoinPoolを採用

Page 27: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Blocking in a ForkJoinPool

ForkJoinPoolでブロッキングするとどうなる?

Await.resultをおさらい

● Let's review

Although this method is blocking, the internal use of blocking ensures that the underlying ExecutionContext to properly detect blocking and ensure that there are no deadlocks. "scala.concurrent.Await". SCALA API DOCS.

http://www.scala-lang.org/api/2.12.1/scala/concurrent/index.html, (参照 2017-01-03)

Page 28: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Blocking in a ForkJoinPool

● Inform one is about to block

● It compensates by starting an additional thread

○ Keep available threads for non-blocking operations

○ No upper limit for threads number!!

1つをブロックする代わりに追加のスレッドを生成上限なし!!

Page 29: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Conclusions

まとめ

Page 30: Deadly Code! (seriously) Blocking & Hyper Context Switching Pattern

Summary

● Await.result + Duration.Inf

● Quite a lot generators

Await.result + Duration.Inf = おやすみたくさんのジェネレータ = 東奔西走

Goodnight

zzz

Busy oneself