43
Scala {Culture}

アドテク×Scala @Dynalyst

Embed Size (px)

DESCRIPTION

How to build Spray How to build Akka How to Monitor them

Citation preview

Page 1: アドテク×Scala @Dynalyst

Scala {Culture}

Page 2: アドテク×Scala @Dynalyst

Who Am I• Now: Dynalyst • Lang: Korean(30+ years) Japanese(8+ years) JAVA(8.2+ years) Scala(a year)

• AdTech: AMoAd DSP CAA Reward

Page 3: アドテク×Scala @Dynalyst

What Dynalyst• Dynamic Retargeting + Analyst

•ユーザーの趣味嗜好に適した広告配信を行う国内初のスマートフォンに特化したダイナミックリターゲティング広告

Page 4: アドテク×Scala @Dynalyst

Scala USAGE

Page 5: アドテク×Scala @Dynalyst

Today’s Talk

•How to build Spray

•How to build Akka

•How to Monitor them

Page 6: アドテク×Scala @Dynalyst

mark ad bid imp click cv

redshift

storedimportingloggingrequest tracking

Dcontinuous importing

Page 7: アドテク×Scala @Dynalyst

redshift

reporting & bidding optimizationsummaringstored

date imp click cv

2014/09 10,000 500 10

2014/08 15,000 700 25

continuous reporting D

Page 8: アドテク×Scala @Dynalyst

Benchmark

Page 9: アドテク×Scala @Dynalyst

What is Spray?

http://spray.io

Page 10: アドテク×Scala @Dynalyst

What is Spray?

spray is an open-source toolkit for building REST/HTTP-based integration layers on top of Scala and Akka. Being asynchronous, actor-based, fast, lightweight, modular and testable it's a great way to connect your Scala applications to the world.

Page 11: アドテク×Scala @Dynalyst

Concurrency

Page 12: アドテク×Scala @Dynalyst

Future[T]

implicit val ec: ExecutionContext

val f = Future { “hello world” }

// Future[String]

Page 13: アドテク×Scala @Dynalyst

Future[T]

implicit val ec: ExecutionContext

for { greeting ← Future(“hello world”) name ← Future(“Han”)} yield s”$greeting, $name”// Future[String]

Page 14: アドテク×Scala @Dynalyst

FutureDirectives

• spray-routing directives

• non-blocking actor thread

Page 15: アドテク×Scala @Dynalyst

FutureDirectives

def onComplete[T] (future: ⇒ Future[T]) (implicit ec: ExecutionContext) :Directive1[Try[T]]

Page 16: アドテク×Scala @Dynalyst

implicit val ec: ExecutionContext

def respondWithBidding = { onComplete(bidding) { case Success(bid: Bid) ⇒ … case Success(noBid: NoBid) ⇒ … case Failure(e) ⇒ … }}

FutureDirectives

Page 17: アドテク×Scala @Dynalyst

Type of bidding

def bidding:Future[A<:BidResponse]

Page 18: アドテク×Scala @Dynalyst

Implementation

def bidding:Future[A<:BidResponse]

!

• simple but bad implementation

Future { // All bidding computations :(}

Page 19: アドテク×Scala @Dynalyst

Application Layers

Spray Router Handle raw level http request & response

Bidding Business Logic

External Resources"Fetch bidding candidates from data stores

Page 20: アドテク×Scala @Dynalyst

Global Dispatcher

Application Layers

Spray Router Handle raw level http request & response

Bidding Business Logic

External Resources"Fetch bidding candidates from data stores

Page 21: アドテク×Scala @Dynalyst

Application Layers

Spray Router Handle raw level http request & response

Bidding Business Logic

External Resources"Fetch bidding candidates from data stores

Router Dispatcher

Service Dispatcher

Repository Dispatcher

Page 22: アドテク×Scala @Dynalyst

Implementationtrait Router { implicit val ec = RouterDispatcher def handle: Future[BidResponse]}

trait Service { implicit val ec = ServiceDispatcher def bidding: Future[Bidder]}

trait Repository { implicit val ec = RepositoryDispatcher def candidates: Future[List[Candidate]]}

Page 23: アドテク×Scala @Dynalyst

How to test those Future[T] things

• Specs2 - Matcher[Future[T]]

bidding must beEqual(expected).await

bidding must beEqual(expected).await( retries = 2, timeout = 100.millis)

Page 24: アドテク×Scala @Dynalyst

Abstract Future

http://logji.blogspot.jp/2014/02/the-abstract-future.html

Page 25: アドテク×Scala @Dynalyst

Abstract Futuretrait Router[M[_]] { implicit val M: Monad[M] def handle: M[BidResponse]} trait Service[M[_]] { implicit val M: Monad[M] def bidding: M[Bidder] = M.point(bidder) def bidder = …} trait Repository[M[_]] { implicit val M: Monad[M] def candidates: M[List[Candidate]]}

Page 26: アドテク×Scala @Dynalyst

Type class & Implicit

object Service { implicit def fs = new Service[Future] { implicit val ec = ServiceDispatcher val M = Monad[Future] } implicit def ids = new Service[Id] { val M = Monad[Id] }} // type Id[+A] = A

Page 27: アドテク×Scala @Dynalyst

Test Again

val s = Service.ids

s.bidding must beEqual(expected)

Page 28: アドテク×Scala @Dynalyst

M[_] for Monad

• Monad is a structure that represents computations defined as sequences of steps

• Don’t dive into “Monad” here!

Page 29: アドテク×Scala @Dynalyst

What about Akka?

http://akka.io

Page 30: アドテク×Scala @Dynalyst

redshift

storedimportingloggingrequest tracking

Dcontinuous importing

mark ad bid imp click cv

Page 31: アドテク×Scala @Dynalyst

redshift

reporting & bidding optimizationsummaringstored

date imp click cv

2014/09 10,000 500 10

2014/08 15,000 700 25

continuous reporting D

Page 32: アドテク×Scala @Dynalyst

Master/Worker

http://letitcrash.com/post/29044669086/balancing-workload-across-nodes-with-akka-2

Page 33: アドテク×Scala @Dynalyst

Overview

Page 34: アドテク×Scala @Dynalyst

Overview

Page 35: アドテク×Scala @Dynalyst

How to Monitor Akka

• Typesafe Console

http://resources.typesafe.com/docs/console/manual/overview.html

• Kamon

http://kamon.io/

Page 36: アドテク×Scala @Dynalyst

Typesafe console• Great user interface

• Support by Typesafe

• Expensive

Page 37: アドテク×Scala @Dynalyst

Kamon• Open Source - Free

• Metrics: Akka, Spray, Play(over 50 categories)

• StatsD, New Relic, Datadog

• Migration could be hard

Page 38: アドテク×Scala @Dynalyst

Kamon meets Zabbix

Page 39: アドテク×Scala @Dynalyst

Running Thread Count

Page 40: アドテク×Scala @Dynalyst

Summary

• Future Directive on Spray

• Abstract Future(Type class & Implicit)

• Akka master/worker pattern

• Monitoring Akka with Kamon

Page 41: アドテク×Scala @Dynalyst

Best Practices?

• https://github.com/alexandru/scala-best-practices

• So many “MUST NOT, SHOULD NOT”

• In my opinion, Trial and Error to find right patterns

Page 42: アドテク×Scala @Dynalyst

We are Hiring!• 一緒に働く仲間を募集しています!Scalaに興味のある方はぜひ!

[email protected]