Blocking & Hyper Context
Switching Pattern
ScalaMatsuri 2017
ブロッキング&ハイパーコンテキストスイッチパターン
Agenda
● Introduction
● How did it happen?
● Importance
● Conclusions
アジェンダ
About Me
● Takako Shimamoto (@chibochibo03)
● BizReach, Inc. CTO office
● Scala Warrior: Planning / Illustration
自己紹介
Introduction
はじめに
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
仕様や使用ライブラリの議論はしません
コードは再現したものです
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]
本日のお題
What is it?
● This method is called multiple times per request
● Inject the default Play execution context
このメソッドは1リクエストで複数回呼ばれる
Oh boy!
● The number of users was small
● But response speed worsened gradually
利用者が少ないにも関わらず徐々にレスポンス速度が悪化
Dangers
● Resources were not under stress
○ database connections
○ slow queries
○ access log
● Infrastructure monitoring showed well
外からの監視で異常を検知できない
How did it happen?
何が起きたのか?
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つ目の問題は無駄なスイッチング
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つのメソッド呼び出しに変換
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は引数に暗黙のスレッドプールが必要
渡した関数はそこで実行
Using a metaphor
C
A
S
H
I
E
R
ファーストフード店で例える
1品ずつ注文
One Hamburger.
A small Coffee.
One French Fry.
Shop
attendant
What the hell !?
C
A
S
H
I
E
R
いやいや、まとめて頼めば1回ですむじゃん!
Shop
attendant
Gather orders!!
Sequential Execution
● DBIO.seq
● DBIO.sequence
○ takes a number of DBIOActions
まとめて渡せるメソッドを使う
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つの問題はブロッキング
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)
Cool names
● More ominous names
○ Oni.blocking(..., Oni.forever)
○ Gachi.blocking(..., Gachi.forever)
● Just kidding! Haha!
名前がカッコよすぎ
鬼ブロック!ガチブロック!(冗談です)
Blocking is evil
● Play is not a traditional web framework
● Play’s thread pools are tuned to use fewer threads
○ IO never blocks
Playは少ないスレッドをブロックせず使い回すスタイル
The C10K problem
● The number of threads multiplies too much
● Lack of resources such as memory
● CPU not busy
クライアント1万台問題
Transformations
変換やコールバックを使う
● Future's methods:
○ map, flatMap, and so on
● Callbacks
○ onComplete, foreach, and so on
Importance
重要なこと
JDBC is synchronous
● A typical example of blocking is database access
● An asynchronous framework doesn't like JDBC
JDBCドライバは同期
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は独自でスレッドプールを持つ
データベースアクションはそのプールのスレッドで実行
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を採用
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)
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つをブロックする代わりに追加のスレッドを生成
上限なし!!
Conclusions
まとめ
Summary
● Await.result + Duration.Inf
● Quite a lot generators
Await.result + Duration.Inf = おやすみ
たくさんのジェネレータ = 東奔西走
Goodnight
zzz
Busy oneself

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

  • 1.
    Blocking & HyperContext Switching Pattern ScalaMatsuri 2017 ブロッキング&ハイパーコンテキストスイッチパターン
  • 2.
    Agenda ● Introduction ● Howdid it happen? ● Importance ● Conclusions アジェンダ
  • 3.
    About Me ● TakakoShimamoto (@chibochibo03) ● BizReach, Inc. CTO office ● Scala Warrior: Planning / Illustration 自己紹介
  • 4.
  • 5.
    Notes ● In thissession, I don't mention the following: ○ Specifications ○ Selection of libraries ● Instead, we'll use a snippet that demonstrates a failure pattern 仕様や使用ライブラリの議論はしません コードは再現したものです
  • 6.
    What is it? defdelete(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] 本日のお題
  • 7.
    What is it? ●This method is called multiple times per request ● Inject the default Play execution context このメソッドは1リクエストで複数回呼ばれる
  • 8.
    Oh boy! ● Thenumber of users was small ● But response speed worsened gradually 利用者が少ないにも関わらず徐々にレスポンス速度が悪化
  • 9.
    Dangers ● Resources werenot under stress ○ database connections ○ slow queries ○ access log ● Infrastructure monitoring showed well 外からの監視で異常を検知できない
  • 10.
    How did ithappen? 何が起きたのか?
  • 11.
    The one problemis ... 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つ目の問題は無駄なスイッチング
  • 12.
    The precise meaning Theprecise 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つのメソッド呼び出しに変換
  • 13.
    Implicit ExecutionContexts ● Providean execution context to execute the given functions ○ When calling map or flatMap on an action ● In short, an ExecutionContext is a ThreadPool mapやflatMapは引数に暗黙のスレッドプールが必要 渡した関数はそこで実行
  • 14.
  • 15.
    What the hell!? C A S H I E R いやいや、まとめて頼めば1回ですむじゃん! Shop attendant Gather orders!!
  • 16.
    Sequential Execution ● DBIO.seq ●DBIO.sequence ○ takes a number of DBIOActions まとめて渡せるメソッドを使う
  • 17.
    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つの問題はブロッキング
  • 18.
    According to Scaladoc Await.resultはブロッキング Althoughthis 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)
  • 19.
    Cool names ● Moreominous names ○ Oni.blocking(..., Oni.forever) ○ Gachi.blocking(..., Gachi.forever) ● Just kidding! Haha! 名前がカッコよすぎ 鬼ブロック!ガチブロック!(冗談です)
  • 20.
    Blocking is evil ●Play is not a traditional web framework ● Play’s thread pools are tuned to use fewer threads ○ IO never blocks Playは少ないスレッドをブロックせず使い回すスタイル
  • 21.
    The C10K problem ●The number of threads multiplies too much ● Lack of resources such as memory ● CPU not busy クライアント1万台問題
  • 22.
    Transformations 変換やコールバックを使う ● Future's methods: ○map, flatMap, and so on ● Callbacks ○ onComplete, foreach, and so on
  • 23.
  • 24.
    JDBC is synchronous ●A typical example of blocking is database access ● An asynchronous framework doesn't like JDBC JDBCドライバは同期
  • 25.
    Slick’s solution ● Wrapblocking code ○ Blocking happens in a different thread ● Slick has its own thread pool ○ All database actions are executed in this pool Slickは独自でスレッドプールを持つ データベースアクションはそのプールのスレッドで実行
  • 26.
    Play default threadpool ● 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を採用
  • 27.
    Blocking in aForkJoinPool 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)
  • 28.
    Blocking in aForkJoinPool ● 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つをブロックする代わりに追加のスレッドを生成 上限なし!!
  • 29.
  • 30.
    Summary ● Await.result +Duration.Inf ● Quite a lot generators Await.result + Duration.Inf = おやすみ たくさんのジェネレータ = 東奔西走 Goodnight zzz Busy oneself