Slide 1

Slide 1 text

Running Scala on AWS Lambda in a snappy way ScalaMatsuri 2019 @todokr BizReach, Inc. "84-BNCEBͰ4DBMBΛαΫαΫಈ͔͢ and fun!

Slide 2

Slide 2 text

The opinions expressed here do not represent
 those of any organization. ͜͜Ͱࣔ͞Ε͍ͯΔݟղ͸ɺ
 ॴଐ૊৫ͷݟղΛ൓ө͢Δ΋ͷͰ͸͋Γ·ͤΜ

Slide 3

Slide 3 text

Who? Shunsuke Tadokoro @todokr ‣A software engineer working at BizReach, Inc. ‣Love: Scala, Clojure, Emacs, etc. ‣Contributed: Play Framework, ScalikeJDBC, etc. ‣Wrote: ాॴॣ༎
 גࣜձࣾϏζϦʔνͷιϑτ΢ΣΞΤϯδχΞ

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

sbt-project-switcher ‣ A sbt plugin to switch sub projects quickly⚡ TCUͷαϒϓϩδΣΫτΛαΫαΫ੾Γସ͑ΔϓϥάΠϯ

Slide 6

Slide 6 text

×

Slide 7

Slide 7 text

AWS Lambda ‣a serverless computing service what we call 'FaaS' ‣Runtimes ‣ Python ‣ Node.js ‣ Java8 ‣ Go ‣ C# ‣ PowerShell ‣ Ruby ‣ custom runtime ‣Just write function and execute ͍ΘΏΔ'BB4ͱݺ͹ΕΔαʔόʔϨείϯϐϡʔςΟϯάαʔϏε
 ͨͩؔ਺Λॻ͍࣮ͯߦ͢Δ͚ͩ

Slide 8

Slide 8 text

AWS Lambda ‣ Fully managed ‣ No server management ‣ High Availability & Scalable ‣ So, you can focus on creating value ϑϧϚωʔδυɿ αʔόʔͷ؅ཧ͕ෆཁɺϏδωεՁ஋ΛੜΉ͜ͱʹूதͰ͖Δ

Slide 9

Slide 9 text

AWS Lambda ‣ Fully managed ‣ No server management ‣ High Availability & Scalable ‣ So, you can focus on creating value ‣ Low cost ‣ Free tier ‣ Pay only for compute time ‣ No charge when code is not running ௿ίετɿ ແྉ࿮͋ΓɺίϯϐϡʔςΟϯά࣌ؒʹରͯ͠՝ۚ

Slide 10

Slide 10 text

I hope to run Scala on AWS Lambda! "84-BNCEBͰ΋4DBMBΛ࢖͍͍ͨʂ

Slide 11

Slide 11 text

I hope to run Scala on AWS Lambda! ‣ No context switch cost to my brain ‣ Scala in server app, Python in X, Node.js in Y, Go in Z… ‣ powers of concentration is precious resource ೴಺ίϯςΩετεΠονͷ཈੍ͷͨΊ
 ͜Ε͸1ZUIPO ͋Ε͸/PEF ͋ͬͪ͸(Pͱ͍͏ͷ͸ͳΔ΂͘ආ͚͍ͨ

Slide 12

Slide 12 text

I hope to run Scala on AWS Lambda! ‣ No context switch cost to my brain ‣ Scala in server app, Python in X, Node.js in Y, Go in Z… ‣ powers of concentration is precious resource ‣ Types ‣ Lambda handler is rarely maintained ‣ Information richness comes from types save time
 to understand code -BNCEBϋϯυϥ͸Ұ౓ॻ͔ΕΔͱ์ஔ͞Ε͕ͪ
 ܕͷදݱྗ͸ίʔυͷཧղΛॿ͚ͯ͘ΕΔ

Slide 13

Slide 13 text

I hope to run Scala on AWS Lambda! ‣ No context switch cost to my brain ‣ Scala in server app, Python in X, Node.js in Y, Go in Z… ‣ powers of concentration is precious resource ‣ Types ‣ Lambda handler is rarely maintained ‣ Information richness comes from types save time
 to understand code ‣ Test ‣ Able to use testing library you get used to ׳ΕͨςετϥΠϒϥϦΛ࢖͏͜ͱ͕Ͱ͖Δ

Slide 14

Slide 14 text

However... ‣ It's often said that 
 "Running JVM language on Lambda is too slow!" ‣ So called "cold-start problem" ʮ-BNCEBͰ+7.ݴޠ͸஗͍ʯͱ͠͹͠͹ݴΘΕΔ

Slide 15

Slide 15 text

However... ‣ It's often said that 
 "Running JVM language on Lambda is too slow!" ‣ So called "cold-start problem" ‣ There is limitation of function package size ‣ Jar size: up to 50 MB ‣ Need to care about libraries to depend on ؔ਺ύοέʔδͷαΠζ͸.#Ҏ಺ͱ͍͏੍ݶ΋ଘࡏ͢Δ

Slide 16

Slide 16 text

So, questions are... ‣ How slow Scala on AWS Lambda is? ‣ How can we make package size small? ‣ How can we run Scala on AWS Lambda in a snappy way? Ͳͷ͘Β͍஗͍ͷ͔ʁͲ͏ͨ͠ΒύοέʔδαΠζΛখ͘͞Ͱ͖Δ͔ʁ
 Ͳ͏ͨ͠Β-BNCEBͰ4DBMBΛαΫαΫಈ͔͢͜ͱ͕Ͱ͖Δ͔ʁ

Slide 17

Slide 17 text

"
 Hello world (avg duration & memory usage of 5 times) ·ͣ͸)FMMPXPSME͔Β࣮ݧ

Slide 18

Slide 18 text

Hello world in Scala import collection.JavaConverters._ import com.amazonaws.services.lambda.runtime.Context class Hello { def handleRequest( request: java.util.Map[String, String], context: Context ): java.util.Map[String, String] = { val name = request.asScala("name") Map("message" -> s"Hello, $name.").asJava } } 4DBMBͰͷ)FMMPXPSME+BSͷαΠζ.#
 ࠷େϝϞϦ࢖༻ྔ.# ॴཁ࣌ؒ NT Lambda memory: 128MB Jar size: 9.7MB Max memory used: 115MB Duration: 8,588ms

Slide 19

Slide 19 text

Hello world in Scala import collection.JavaConverters._ import com.amazonaws.services.lambda.runtime.Context class Hello { def handleRequest( request: java.util.Map[String, String], context: Context ): java.util.Map[String, String] = { val name = request.asScala("name") Map("message" -> s"Hello, $name.").asJava } } 4DBMBͰͷ)FMMPXPSME+BSͷαΠζ.#
 ࠷େϝϞϦ࢖༻ྔ.# ॴཁ࣌ؒ NT Lambda memory: 128MB Jar size: 9.7MB Max memory used: 115MB Duration: 8,588ms

Slide 20

Slide 20 text

Hello world in Scala import collection.JavaConverters._ import com.amazonaws.services.lambda.runtime.Context class Hello { def handleRequest( request: java.util.Map[String, String], context: Context ): java.util.Map[String, String] = { val name = request.asScala("name") Map("message" -> s"Hello, $name.").asJava } } 4DBMBͰͷ)FMMPXPSME+BSͷαΠζ.#
 ࠷େϝϞϦ࢖༻ྔ.# ॴཁ࣌ؒ NT Lambda memory: 128MB Jar size: 9.7MB Max memory used: 115MB Duration: 8,588ms

Slide 21

Slide 21 text

Hello world in Scala import collection.JavaConverters._ import com.amazonaws.services.lambda.runtime.Context class Hello { def handleRequest( request: java.util.Map[String, String], context: Context ): java.util.Map[String, String] = { val name = request.asScala("name") Map("message" -> s"Hello, $name.").asJava } } 4DBMBͰͷ)FMMPXPSME+BSͷαΠζ.#
 ࠷େϝϞϦ࢖༻ྔ.# ॴཁ࣌ؒ NT Lambda memory: 128MB Jar size: 9.7MB Max memory used: 115MB Duration: 8,588ms

Slide 22

Slide 22 text

2nd trial... TODO screen shot

Slide 23

Slide 23 text

2nd trial... TODO screen shot

Slide 24

Slide 24 text

2nd trial... TODO screen shot 2nd trial is blazing fast! ճ໨ͷॴཁ࣌ؒ͸NTͱ଎͍

Slide 25

Slide 25 text

2nd trial... TODO screen shot 2nd trial is blazing fast! 1st trial took 8 seconds, so called "cold-start" problem ॳճ͸ඵɺ͍ΘΏΔʮίʔϧυελʔτʯ໰୊

Slide 26

Slide 26 text

cold-start? ίʔϧυελʔτͬͯԿʁ

Slide 27

Slide 27 text

What is cold-start? We should know Lambda lifecycle! DPMETUBSUΛཧղ͢ΔͨΊʹɺ-BNCEBͷϥΠϑαΠΫϧʹ͍ͭͯ஌Δ

Slide 28

Slide 28 text

What is cold-start? We should know Lambda lifecycle! ؔ਺ύοέʔδͷμ΢ϯϩʔυ Download code 1. Download the function package 
 (zip or jar, file on S3) you wrote

Slide 29

Slide 29 text

What is cold-start? We should know Lambda lifecycle! ίʔυ࣮ߦ༻ͷαϯυϘοΫείϯςφͷىಈ Download code Start new container 2. Start the sandbox container where your code will be executed

Slide 30

Slide 30 text

What is cold-start? We should know Lambda lifecycle! ϥϯλΠϜͷىಈ
 +BWBͷ৔߹ɺ+7.ͷىಈ΍ΫϥεϑΝΠϧͷϩʔυͳͲ΋ Download code Start new container Bootstrap runtime 3. Bootstrap runtime to run your code, 
 including JVM spin-up, load class files, etc.

Slide 31

Slide 31 text

What is cold-start? We should know Lambda lifecycle! ؔ਺ύοέʔδͷ࣮ߦ Download code Start new container Bootstrap runtime Run code 4. Run your function package code and
 affect the world

Slide 32

Slide 32 text

What is cold-start? We should know Lambda lifecycle! ίϯςφΛϑϦʔζ͠ɺ࣍ճͷݺͼग़͠Λ଴ͭ
 ͨͩ͠ɺ࣍ճͷݺͼग़͕͠ಉ͡ΠϯελϯεͰ࣮ߦ͞ΕΔอূ͸ͳ͍ Download code Start new container Bootstrap runtime Run code Freeze the container 5. Freeze the container and wait for a next invocation However there's no guarantee it will run on the same instance. 
 Container may be removed.

Slide 33

Slide 33 text

Cold-start is a process that follows 
 "download" to "run". Note that downloading jar and spinning-up
 JVM relatively take time. What is cold-start? We should know Lambda lifecycle! ίʔϧυελʔτ͸ίʔυͷμ΢ϯϩʔυ͔Β࣮ߦ·ͰΛܦΔ
 KBSͷμ΢ϯϩʔυ΍+7.ͷىಈ͸ൺֱత͕͔͔࣌ؒΔॲཧ Download code Start new container Bootstrap runtime Run code Freeze the container

Slide 34

Slide 34 text

Warm-start is a process which reuses the same instance, so there's no spin-up time. This is why each invocations after the first 
 is fast. What is cold-start? We should know Lambda lifecycle! ΢ΥʔϜελʔτͱ͸-BNCBΠϯελϯε͕࠶ར༻͞ΕΔ࣮ߦ
 ͜Ε͕ճ໨Ҏ߱ͷݺͼग़͕͠଎͔ͬͨཧ༝ Download code Start new container Bootstrap runtime Run code Freeze the container

Slide 35

Slide 35 text

first-time-only misunderstanding ʮॳճ͚ͩʯͷޡղ

Slide 36

Slide 36 text

first-time-only misunderstanding ‣ Not the first time only! ίʔϧυελʔτ͕ى͖Δͷ͸ॳճͷݺͼग़͚ͩ͠Ͱ͸ͳ͍ʂ

Slide 37

Slide 37 text

first-time-only misunderstanding ‣ Not the first time only! ‣ If there is no available container, cold-start happens ‣ Lambda containers have the limitation that they can handle 
 only single request at a time ‣ If two requests come in at once, two containers are required 
 to handle these requests ‣ If there is no available one, it starts from container creation ෳ਺ಉ࣌ϦΫΤετͳͲɺ࣮ߦՄೳͳίϯςφ͕ଘࡏ͠ͳ͍৔߹ʹ΋ى ͖Δ

Slide 38

Slide 38 text

first-time-only misunderstanding ‣ Not the first time only! ‣ If there is no available container, cold-start happens ‣ Lambda containers have the limitation that they can handle 
 only single request at a time ‣ If two requests come in at once, two containers are required 
 to handle these requests ‣ If there is no available one, it starts from container creation ‣ When a large request spike comes, the throughput problem occurs or it exceed Lambda's concurrency limitation େ͖ͳϦΫΤετͷεύΠΫ͕དྷͨ৔߹ʹɺεϧʔϓοτ͕໰୊ʹͳͬͨΓ -BNCEBͷಉ࣮࣌ߦ਺ͷ੍ݶʹͻ͔͔ͬͬͯ͠·͏͜ͱ΋

Slide 39

Slide 39 text

What increases 
 cold-start latency? Կ͕ίʔϧυελʔτ࣌ͷϨΠςϯγΛ૿Ճͤ͞Δͷ͔ʁ

Slide 40

Slide 40 text

Factors increase cold-start latency ίʔϧυελʔτͷϨΠςϯγΛ૿Ճͤ͞ΔཁҼ

Slide 41

Slide 41 text

Factors increase cold-start latency ‣ Attached memory size ‣ Memory footprint of JVM spin-up is relatively large ‣ CPU power is proportional to memory size -BNCEBʹׂΓ౰ͯΒΕͨϝϞϦαΠζ
 ଞͷϥϯλΠϜʹൺ΂ɺ+7.͸ىಈʹൺֱతଟ͘ͷϝϞϦΛඞཁͱ͢Δ

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

Factors increase cold-start latency ‣ Attached memory size ‣ Memory footprint of JVM spin-up is relatively large ‣ CPU power is proportional to memory size -BNCEBʹׂΓ౰ͯΒΕͨϝϞϦαΠζ
 ଞͷϥϯλΠϜʹൺ΂ɺ+7.͸ىಈʹൺֱతଟ͘ͷϝϞϦΛඞཁͱ͢Δ

Slide 44

Slide 44 text

Factors increase cold-start latency ‣ Attached memory size ‣ Memory footprint of JVM spin-up is relatively large ‣ CPU power is proportional to memory size ‣ Function package size ‣ The larger jar size is, the more download time takes ؔ਺ύοέʔδͷαΠζ
 େ͖͚Ε͹େ͖͍΄Ͳɺμ΢ϯϩʔυʹ΋͕͔͔࣌ؒΔ

Slide 45

Slide 45 text

includes 30MB
 dummy binary file

Slide 46

Slide 46 text

Factors increase cold-start latency ‣ Attached memory size ‣ Memory footprint of JVM spin-up is relatively large ‣ CPU power is proportional to memory size ‣ Function package size ‣ The larger jar size is, the more download time takes ؔ਺ύοέʔδͷαΠζ
 େ͖͚Ε͹େ͖͍΄Ͳɺμ΢ϯϩʔυʹ΋͕͔͔࣌ؒΔ

Slide 47

Slide 47 text

Factors increase cold-start latency ‣ Attached memory size ‣ Memory footprint of JVM spin-up is relatively large ‣ CPU power is proportional to memory size ‣ Function package size ‣ The larger jar size is, the more download time takes ‣ Number of class files to be loaded ‣ Large number of classes to be loaded and initialized introduces
 large amount of latency ΫϥεϑΝΠϧͷ਺
 ϩʔυ͓ΑͼॳظԽ͞ΕΔΫϥεϑΝΠϧ͕ଟ͚Ε͹ɺͦͷ෼஗͘ͳΔ

Slide 48

Slide 48 text

Factors increase cold-start latency ‣ Attached memory size ‣ Memory footprint of JVM spin-up is relatively large ‣ CPU power is proportional to memory size ‣ Function package size ‣ The larger jar size is, the more download time takes ‣ Number of class files to be loaded ‣ Large number of classes to be loaded and initialized introduces large amount of latency ‣ VPC, etc. ͦͷଞɺ71$ͳͲ΋Өڹ

Slide 49

Slide 49 text

Another factor in Scala app ‣ Scala class files tend to be numerous ‣ These class files are loaded and initialized when it used 4DBMBͷΫϥεϑΝΠϧ͸਺͕ଟ͘ͳΓ͕ͪ
 ར༻ͷࡍʹ͸͜ΕΒ΋ϩʔυɾॳظԽ͞ΕΔ $ tree . /unzipped-jar/scala scala/ ├── AnyVal.class ├── AnyValCompanion.class ├── App.class ├── Array$$anon$2.class ├── Array$.class ... │ ├── Regex$Replacement.class │ ├── Regex.class │ └── UnanchoredRegex.class └── volatile.class 34 directories, 2503 files $ tree ./ ... |____Hello$.class |____Hello.class |____Request.class |____Request$.class ... | |____PartialFunction$anonfun$apply$1.class | |____SttpBackendOptions$Proxy$$anon$1.class ...

Slide 50

Slide 50 text

In short? ͭ·Γʁ

Slide 51

Slide 51 text

Scala on Lambda problems 4DBMBΛ-BNCEBͰಈ্͔͢Ͱͷ໰୊

Slide 52

Slide 52 text

Scala on Lambda problems ‣ Java runtime is at a disadvantage ‣ JVM spin-up memory footprint ‣ Jar size to be downloaded ‣ Number of classes to be loaded and initialized ىಈ࣌ͷϝϞϦϑοτϓϦϯτ΍μ΢ϯϩʔυ͢ΔKBSͷαΠζɺ
 ΫϥεϑΝΠϧͷϩʔυͱॳظԽͳͲͷ఺Ͱɺ+BWBϥϯλΠϜ͸ෆར

Slide 53

Slide 53 text

Scala on Lambda problems ‣ Java runtime is at a disadvantage ‣ JVM spin-up memory footprint ‣ Jar size to be downloaded ‣ Number of classes to be loaded and initialized ‣ Scala's another disadvantage ‣ Scala class files tend to be numerous 4DBMBͷΫϥεϑΝΠϧ͸਺͕ଟ͘ͳΓ͕ͪͳͷ΋ෆརͳ఺

Slide 54

Slide 54 text

Scala on Lambda problems ‣ Java runtime is at a disadvantage ‣ JVM spin-up memory footprint ‣ Jar size to be downloaded ‣ Number of classes to be loaded and initialized ‣ Scala's another disadvantage ‣ Scala class files tend to be numerous ‣ Thus, Scala cold-start in Java runtime takes longer than other language runtime ‣ even "Hello world", it took 8s ‣ when in warm-start, 0.5ms Αͬͯɺ4DBMBY+BWBϥϯλΠϜͷίʔϧυελʔτ͸
 ଞͷϥϯλΠϜΑΓ΋͕͔͔࣌ؒͬͯ͠·͏

Slide 55

Slide 55 text

hmm... so how can we run Scala snappy on Lambda? ͏ʔΉɺ͡Ό͋Ͳ͏ͨ͠ΒαΫαΫಈ͔ͤΔͩΖ͏͔ʁ

Slide 56

Slide 56 text

Run Scala on Lambda without JVM +7.Λ࢖Θͣʹ4DBMBΛಈ͔͢

Slide 57

Slide 57 text

Run Scala on Lambda without JVM ‣ However JVM is great, the short-lived Lambda instance doesn't take advantage of the characteristics of that ‣ Such as dynamic class loading or HotSpot JIT compile, etc. +7.͸Ғେ͕ͩɺੜଘظ͕ؒ୹͍-BNCEBΠϯελϯεͰ͸
 ͦͷྑ͍ಛੑ͕׆͔ͮ͠Β͍

Slide 58

Slide 58 text

Run Scala on Lambda without JVM ‣ However JVM is great, the short-lived Lambda instance doesn't take advantage of the characteristics of that ‣ Such as dynamic class loading or HotSpot JIT compile, etc. ‣ It might be awesome if it runs without JVM! ‣ Not to wait JVM spin-up and loading classes ‣ Make executable package size small ‣ Keep memory footprint small +7.ͳ͠Ͱ࣮ߦͰ͖ͨΒྑ͍݁ՌʹͳΔ͔΋͠Εͳ͍ʂ
 +7.ͷεϐϯΞοϓΛ଴ͨͣɺؔ਺ύοέʔδͱϝϞϦ࢖༻ྔΛখ͘͞

Slide 59

Slide 59 text

How? Ͱ͸Ͳ͏΍ͬͯʁ

Slide 60

Slide 60 text

How? ‣ Scala.js with Node.js runtime 4DBMBKTΛ/PEFKTϥϯλΠϜͰಈ͔͢

Slide 61

Slide 61 text

How? ‣ Scala.js with Node.js runtime ‣ Scala Native with Custom runtime 4DBMB/BUJWFΛΧελϜϥϯλΠϜͰಈ͔͢

Slide 62

Slide 62 text

How? ‣ Scala.js with Node.js runtime ‣ Scala Native with Custom runtime ‣ Native image built by GraalVM with Custom runtime (SBBM7.Ͱੜ੒ͨ͠ωΠςΟϒΠϝʔδΛΧελϜϥϯλΠϜͰಈ͔͢

Slide 63

Slide 63 text

Sample code ‣ https://github.com/todokr/scala-on-lambda-snappy

Slide 64

Slide 64 text

GraalVM IUUQTXXXTDBMBKTPSH

Slide 65

Slide 65 text

Scala.js ‣ A statically typed AltJS ‣ Generate JavaScript code from Scala ‣ Provided as a sbt compiler plugin // plugins.sbt addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.26") // build.sbt enablePlugins(ScalaJSPlugin) // Greet.scala object Greet extends App { println("Hello from Scala.js!") } ੩తܕ෇͚"MU+4ͷҰछͰɺ4DBMBͷίʔυ͔Β+BWB4DSJQUΛੜ੒͢Δ
 TCUͷίϯύΠϥϓϥάΠϯͱͯ͠ఏڙ͞Ε͍ͯΔ

Slide 66

Slide 66 text

class of ES6 & Scala.js class Person(val firstName: String, val lastName: String) { def fullName(): String = s"$firstName $lastName" } class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } fullName() { return `${this.firstName} ${this.lastName}`; } } ES6 Scala.js

Slide 67

Slide 67 text

Scala.js facade for Node.js ‣ scalajs-io/nodejs https://github.com/scalajs-io/nodejs ‣ A facade library provides Node.js API interface ‣ Enable type hinting and checking // before (not type safe) import js.Dynamic def getToken(): UndefOr[String] = Dynamic.global.process.env.ACCESS_TOKEN.asInstanceOf[UndefOr[String]] // after import io.scalajs.nodejs.{Environment, process} def getToken2(): Environment = process.env TDBMBKTJPOPEFKTͱ͍͏/PEFKTͷϑΝαʔυϥΠϒϥϦ͕͋Δ
 /PEFKTͷ"1*Λ҆શʹݺͼग़͢͜ͱ͕Ͱ͖Δ

Slide 68

Slide 68 text

Scala Native IUUQTTDBMBOBUJWFSFBEUIFEPDTJP

Slide 69

Slide 69 text

Scala Native ‣ Generate executable binary file from Scala ‣ Provided as a sbt compiler plugin // plugins.sbt addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.3.8") // build.sbt scalaVersion := "2.11.12" enablePlugins(ScalaNativePlugin) // Greet.scala object Greet extends App { println("Hello from Scala Native!") } 4DBMBͷίʔυ͔Β࣮ߦՄೳͳόΠφϦϑΝΠϧΛੜ੒͢Δ
 TCUͷίϯύΠϥϓϥάΠϯͱͯ͠ఏڙ͞Ε͍ͯΔ

Slide 70

Slide 70 text

Scala Native ‣ Try generating executable and running without JVM # compile & generate machine code $ sbt nativeLink # execute $ time ./target/scala-2.11/greet-out Hello from Scala Native! real 0m0.019s user 0m0.004s sys 0m0.007s όΠφϦΛੜ੒࣮ͯ͠ߦͯ͠ΈΔ

Slide 71

Slide 71 text

AWS Lambda custom runtime ‣ Any language that can run in the Lambda execution environment is available ‣ Simple HTTP based interface ‣ to get the event payload for a new invocation ‣ to return back the response from the function -BNCEBͷ؀ڥͰ࣮ߦͰ͖ΔݴޠͳΒԿͰ΋ར༻Մೳ ϦΫΤετϨεϙϯεͷͨΊͷγϯϓϧͳ)551ΠϯλϑΣʔεΛ࣋ͭ

Slide 72

Slide 72 text

GraalVM IUUQTXXXHSBBMWNPSH

Slide 73

Slide 73 text

GraalVM ‣ Polyglot VM developed by Oracle ‣ Enable to run JVM langs, JS, Python, Ruby, etc. with zero overhead ‣ SubstrateVM ‣ A GraalVM component that allows AOT compilation of Java code
 into executable native images ‣ Community Edition / Enterprise Edition 0SBDMF͕։ൃ͍ͯ͠Δ1PMZHMPU7.
 4VCTUSBUF7.͸࣮ߦՄೳͳωΠςΟϒΠϝʔδΛੜ੒͢Δίϯϙʔωϯτ

Slide 74

Slide 74 text

Java frameworks use SubstrateVM ‣ Quarkus https://quarkus.io ‣ A "Supersonic Subatomic Java" framework ‣ Micronaut Framework https://micronaut.io ‣ A full-stack framework for microservice and serverless applications ‣ Project Helidon https://helidon.io ‣ A collection of Java libraries for writing microservices (SBBM7.ͰωΠςΟϒΠϝʔδΛੜ੒͢Δ+BWBϑϨʔϜϫʔΫ

Slide 75

Slide 75 text

"
 Hello world
 in Scala.js 4DBMBKTͰ)FMMPXPSME

Slide 76

Slide 76 text

Hello world in Scala.js // build.sbt lazy val commonSettings = Seq( scalaVersion := "2.12.8", scalacOptions += "-P:scalajs:sjsDefinedByDefault", scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.CommonJSModule) }) lazy val hello = (project in file("hello")) .settings( commonSettings, artifactPath in (Compile, fastOptJS) := baseDirectory.value / "hello.js", artifactPath in (Compile, fullOptJS) := baseDirectory.value / "hello-opt.js", ).enablePlugins(ScalaJSPlugin) ‣ build.sbt

Slide 77

Slide 77 text

Hello world in Scala.js $PNNPO+4ελΠϧͰϞδϡʔϧΛੜ੒͢Δ // build.sbt lazy val commonSettings = Seq( scalaVersion := "2.12.8", scalacOptions += "-P:scalajs:sjsDefinedByDefault", scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.CommonJSModule) }) lazy val hello = (project in file("hello")) .settings( commonSettings, artifactPath in (Compile, fastOptJS) := baseDirectory.value / "hello.js", artifactPath in (Compile, fullOptJS) := baseDirectory.value / "hello-opt.js", ).enablePlugins(ScalaJSPlugin) ‣ Emit CommonJS style modules

Slide 78

Slide 78 text

Hello world in Scala.js ੜ੒͞Εͨ+4͕഑ஔ͞ΕΔύεΛఆٛ // build.sbt lazy val commonSettings = Seq( scalaVersion := "2.12.8", scalacOptions += "-P:scalajs:sjsDefinedByDefault", scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.CommonJSModule) }) lazy val hello = (project in file("hello")) .settings( commonSettings, artifactPath in (Compile, fastOptJS) := baseDirectory.value / "hello.js", artifactPath in (Compile, fullOptJS) := baseDirectory.value / "hello-opt.js", ).enablePlugins(ScalaJSPlugin) ‣ Define the path which is generated JS placed

Slide 79

Slide 79 text

Hello world in Scala.js // Hello.scala import scala.scalajs.js import scala.scalajs.js.annotation.JSExportTopLevel @js.native trait Request extends js.Object { val name: String = js.native } object Hello { type Callback = js.Function2[Error, js.Any, Unit] @JSExportTopLevel("handleRequest") def handleRequest(req: Request, c: js.Object, callback: Callback): Unit = { val message = s"Hello, ${req.name}!" callback(null, js.Dynamic.literal("message" -> message)) } } ‣ Hello.scala

Slide 80

Slide 80 text

Hello world in Scala.js +4ͷΦϒδΣΫτΛܕ҆શʹѻ͏ͨΊͷϑΝαʔυܕ // Hello.scala import scala.scalajs.js import scala.scalajs.js.annotation.JSExportTopLevel @js.native trait Request extends js.Object { val name: String = js.native } object Hello { type Callback = js.Function2[Error, js.Any, Unit] @JSExportTopLevel("handleRequest") def handleRequest(req: Request, c: js.Object, callback: Callback): Unit = { val message = s"Hello, ${req.name}!" callback(null, js.Dynamic.literal("message" -> message)) } } ‣ A facade type to handle JS object type safely

Slide 81

Slide 81 text

Hello world in Scala.js ίʔϧόοΫؔ਺ͷܕΛఆٛ // Hello.scala import scala.scalajs.js import scala.scalajs.js.annotation.JSExportTopLevel @js.native trait Request extends js.Object { val name: String = js.native } object Hello { type Callback = js.Function2[Error, js.Any, Unit] @JSExportTopLevel("handleRequest") def handleRequest(req: Request, c: js.Object, callback: Callback): Unit = { val message = s"Hello, ${req.name}!" callback(null, js.Dynamic.literal("message" -> message)) } } ‣ Define the type of callback function

Slide 82

Slide 82 text

Hello world in Scala.js ͕͜͜ϋϯυϥͷओཁͳύʔτ // Hello.scala import scala.scalajs.js import scala.scalajs.js.annotation.JSExportTopLevel @js.native trait Request extends js.Object { val name: String = js.native } object Hello { type Callback = js.Function2[Error, js.Any, Unit] @JSExportTopLevel("handleRequest") def handleRequest(req: Request, c: js.Object, callback: Callback): Unit = { val message = s"Hello, ${req.name}!" callback(null, js.Dynamic.literal("message" -> message)) } } ‣ This is the main part of handler

Slide 83

Slide 83 text

Hello world in Scala.js ΦϒδΣΫτΛHMPCBMʹΤΫεϙʔτ͢ΔΞϊςʔγϣϯ // Hello.scala import scala.scalajs.js import scala.scalajs.js.annotation.JSExportTopLevel @js.native trait Request extends js.Object { val name: String = js.native } object Hello { type Callback = js.Function2[Error, js.Any, Unit] @JSExportTopLevel("handleRequest") def handleRequest(req: Request, c: js.Object, callback: Callback): Unit = { val message = s"Hello, ${req.name}!" callback(null, js.Dynamic.literal("message" -> message)) } } ‣ A annotation exports that object to the JS global scope

Slide 84

Slide 84 text

Hello world in Scala.js ϦΫΤετ͔ΒϝοηʔδΛ૊ΈཱͯɺίʔϧόοΫؔ਺ΛݺͿ // Hello.scala import scala.scalajs.js import scala.scalajs.js.annotation.JSExportTopLevel @js.native trait Request extends js.Object { val name: String = js.native } object Hello { type Callback = js.Function2[Error, js.Any, Unit] @JSExportTopLevel("handleRequest") def handleRequest(req: Request, c: js.Object, callback: Callback): Unit = { val message = s"Hello, ${req.name}!" callback(null, js.Dynamic.literal("message" -> message)) } } ‣ Create message from request and invoke callback function

Slide 85

Slide 85 text

Hello world in Scala.js ‣ Let's run! 1BDLBHFTJ[F .BYNFNPSZVTBHF $PMETUBSU %VSBUJPO NT 4DBMB+7. .# .# NT 4DBMBKT ,# .# NT

Slide 86

Slide 86 text

Hello world in Scala.js ‣ Let's run! 1BDLBHFTJ[F .BYNFNPSZVTBHF $PMETUBSU %VSBUJPO NT 4DBMB+7. .# .# NT 4DBMBKT ,# .# NT

Slide 87

Slide 87 text

Hello world in Scala.js ‣ Let's run! 1BDLBHFTJ[F .BYNFNPSZVTBHF $PMETUBSU %VSBUJPO NT 4DBMB+7. .# .# NT 4DBMBKT ,# .# NT

Slide 88

Slide 88 text

Hello world in Scala.js ‣ Let's run! 1BDLBHFTJ[F .BYNFNPSZVTBHF $PMETUBSU %VSBUJPO NT 4DBMB+7. .# .# NT 4DBMBKT ,# .# NT

Slide 89

Slide 89 text

Hello world in Scala.js ‣ Let's run! 1BDLBHFTJ[F .BYNFNPSZVTBHF $PMETUBSU %VSBUJPO NT 4DBMB+7. .# .# NT 4DBMBKT ,# .# NT So fast! ΊͬͪΌ଎͍ʂ

Slide 90

Slide 90 text

"
 Hello world
 in Scala Native 4DBMB/BUJWFͰ)FMMPXPSME

Slide 91

Slide 91 text

Hello world in Scala Native Building executable for Lambda is complex a bit -BNCEB޲͚࣮ߦՄೳϑΝΠϧΛ4DBMB/BUJWFͰ࡞Δͷ͸গʑෳࡶ

Slide 92

Slide 92 text

Hello world in Scala Native Building executable for Lambda is complex a bit ‣ Write Scala Native code 4DBMB/BUJWFͷίʔυΛॻ͘

Slide 93

Slide 93 text

Hello world in Scala Native Building executable for Lambda is complex a bit ‣ Write Scala Native code ‣ Build the Amazon Linux based docker container ‣ Install required libs such as LLVM, curl, openssl, re2, etc. ‣ Publish those as a Lambda Layer "NB[PO-JOVYϕʔεͷ%PDLFSίϯςφΛϏϧυ͢Δɻ ඞཁͳϥΠϒϥϦΛΠϯετʔϧ͠ɺͦΕΒΛ-BNCEB-BZFSͱͯ͠഑ஔ

Slide 94

Slide 94 text

Hello world in Scala Native Building executable for Lambda is complex a bit ‣ Write Scala Native code ‣ Build the Amazon Linux based docker container ‣ Install required libs such as LLVM, curl, openssl, re2, etc. ‣ Publish those as a Lambda Layer ‣ Build executable with the docker container and deploy %PDLFSΛ࢖࣮ͬͯߦՄೳϑΝΠϧΛϏϧυ͠ɺσϓϩΠ

Slide 95

Slide 95 text

Hello world in Scala Native ‣ build.sbt // build.sbt lazy val commonSettings = Seq( scalaVersion := "2.11.12", nativeLinkingOptions ++= Seq("-static-libstdc++", "-L/lib/"), nativeGC := "immix", // default is Boehm GC nativeCompileOptions := Seq("-O3") ) lazy val hello = (project in file("hello")) .settings( commonSettings, libraryDependencies ++= Seq( "com.softwaremill.sttp" %%% "core" % "1.5.11", "io.argonaut" % "argonaut_native0.3_2.11" % "6.2.2" ) ).enablePlugins(ScalaNativePlugin)

Slide 96

Slide 96 text

Hello world in Scala Native ‣ Settings for Scala version, linkage option, compile option, etc. // build.sbt lazy val commonSettings = Seq( scalaVersion := "2.11.12", nativeLinkingOptions ++= Seq("-static-libstdc++", "-L/lib/"), nativeGC := "immix", // default is Boehm GC nativeCompileOptions := Seq("-O3") ) lazy val hello = (project in file("hello")) .settings( commonSettings, libraryDependencies ++= Seq( "com.softwaremill.sttp" %%% "core" % "1.5.11", "io.argonaut" % "argonaut_native0.3_2.11" % "6.2.2" ) ).enablePlugins(ScalaNativePlugin) 4DMBMBόʔδϣϯ΍ϦϯέʔδɺίϯύΠϧͷΦϓγϣϯΛઃఆ

Slide 97

Slide 97 text

Hello world in Scala Native ‣ Libraries written for Scala Native are available // build.sbt lazy val commonSettings = Seq( scalaVersion := "2.11.12", nativeLinkingOptions ++= Seq("-static-libstdc++", "-L/lib/"), nativeGC := "immix", // default is Boehm GC nativeCompileOptions := Seq("-O3") ) lazy val hello = (project in file("hello")) .settings( commonSettings, libraryDependencies ++= Seq( "com.softwaremill.sttp" %%% "core" % "1.5.11", "io.argonaut" % "argonaut_native0.3_2.11" % "6.2.2" ) ).enablePlugins(ScalaNativePlugin) 4DBMB/BUJWFʹରԠ͍ͯ͠ΔϥΠϒϥϦͳΒར༻͕Մೳ

Slide 98

Slide 98 text

Hello world in Scala Native ‣ STTP: HTTP lib, to invoke Custom runtime API ‣ Argonaut: JSON lib, to handle JSON request / response // build.sbt lazy val commonSettings = Seq( scalaVersion := "2.11.12", nativeLinkingOptions ++= Seq("-static-libstdc++", "-L/lib/"), nativeGC := "immix", // default is Boehm GC nativeCompileOptions := Seq("-O3") ) lazy val hello = (project in file("hello")) .settings( commonSettings, libraryDependencies ++= Seq( "com.softwaremill.sttp" %%% "core" % "1.5.11", "io.argonaut" % "argonaut_native0.3_2.11" % "6.2.2" ) ).enablePlugins(ScalaNativePlugin) 4551)551ϥΠϒϥϦ ΧελϜϥϯλΠϜ"1*Λݺͼग़͢༻
 "SHPOBVU+40/ϥΠϒϥϦ ϦΫΤετϨεϙϯεͷ+40/༻

Slide 99

Slide 99 text

Hello world in Scala Native ‣ Hello.scala import com.softwaremill.sttp._ import argonaut._, Argonaut._ object Hello { def main(args: Array[String]): Unit = { implicit val backend = CurlBackend() implicit val requestCodec = casecodec1(Request.apply, Request.unapply)("name") val runtimeApi = System.getenv("AWS_LAMBDA_RUNTIME_API") while (true) { val next = sttp.get(uri"http://$runtimeApi/2018-06-01/runtime/invocation/next").send() val requestId = next.headers("Lambda-Runtime-Aws-Request-Id") val request = Parse.decodeOption[Request](next.unsafeBody).get val message = Json("message" -> jString(s"Hello, ${request.name}!")).nospaces sttp.post( uri"http://$runtimeApi/2018-06-01/runtime/invocation/$requestId/response" ).body(message).send() } } } case class Request(name: String)

Slide 100

Slide 100 text

Hello world in Scala Native ‣ Initialize: get runtime api path, etc. import com.softwaremill.sttp._ import argonaut._, Argonaut._ object Hello { def main(args: Array[String]): Unit = { implicit val backend = CurlBackend() implicit val requestCodec = casecodec1(Request.apply, Request.unapply)("name") val runtimeApi = System.getenv("AWS_LAMBDA_RUNTIME_API") while (true) { val next = sttp.get(uri"http://$runtimeApi/2018-06-01/runtime/invocation/next").send() val requestId = next.headers("Lambda-Runtime-Aws-Request-Id") val request = Parse.decodeOption[Request](next.unsafeBody).get val message = Json("message" -> jString(s"Hello, ${request.name}!")).nospaces sttp.post( uri"http://$runtimeApi/2018-06-01/runtime/invocation/$requestId/response" ).body(message).send() } } } case class Request(name: String) ॳظԽॲཧϥϯλΠϜ"1*ͷύεऔಘͳͲ

Slide 101

Slide 101 text

Hello world in Scala Native ‣ Process 1 request with 1 loop import com.softwaremill.sttp._ import argonaut._, Argonaut._ object Hello { def main(args: Array[String]): Unit = { implicit val backend = CurlBackend() implicit val requestCodec = casecodec1(Request.apply, Request.unapply)("name") val runtimeApi = System.getenv("AWS_LAMBDA_RUNTIME_API") while (true) { val next = sttp.get(uri"http://$runtimeApi/2018-06-01/runtime/invocation/next").send() val requestId = next.headers("Lambda-Runtime-Aws-Request-Id") val request = Parse.decodeOption[Request](next.unsafeBody).get val message = Json("message" -> jString(s"Hello, ${request.name}!")).nospaces sttp.post( uri"http://$runtimeApi/2018-06-01/runtime/invocation/$requestId/response" ).body(message).send() } } } case class Request(name: String) ϧʔϓͰϦΫΤετΛॲཧ͢Δ

Slide 102

Slide 102 text

Hello world in Scala Native ‣ Fetch event from next API and parse as request import com.softwaremill.sttp._ import argonaut._, Argonaut._ object Hello { def main(args: Array[String]): Unit = { implicit val backend = CurlBackend() implicit val requestCodec = casecodec1(Request.apply, Request.unapply)("name") val runtimeApi = System.getenv("AWS_LAMBDA_RUNTIME_API") while (true) { val next = sttp.get(uri"http://$runtimeApi/2018-06-01/runtime/invocation/next").send() val requestId = next.headers("Lambda-Runtime-Aws-Request-Id") val request = Parse.decodeOption[Request](next.unsafeBody).get val message = Json("message" -> jString(s"Hello, ${request.name}!")).nospaces sttp.post( uri"http://$runtimeApi/2018-06-01/runtime/invocation/$requestId/response" ).body(message).send() } } } case class Request(name: String) OFYU"1*Λୟ͖ɺ݁ՌΛ3FRVFTUΦϒδΣΫτͱͯ͠ύʔε

Slide 103

Slide 103 text

Hello world in Scala Native ‣ Send build message to response API import com.softwaremill.sttp._ import argonaut._, Argonaut._ object Hello { def main(args: Array[String]): Unit = { implicit val backend = CurlBackend() implicit val requestCodec = casecodec1(Request.apply, Request.unapply)("name") val runtimeApi = System.getenv("AWS_LAMBDA_RUNTIME_API") while (true) { val next = sttp.get(uri"http://$runtimeApi/2018-06-01/runtime/invocation/next").send() val requestId = next.headers("Lambda-Runtime-Aws-Request-Id") val request = Parse.decodeOption[Request](next.unsafeBody).get val message = Json("message" -> jString(s"Hello, ${request.name}!")).nospaces sttp.post( uri"http://$runtimeApi/2018-06-01/runtime/invocation/$requestId/response" ).body(message).send() } } } case class Request(name: String) ૊ΈཱͯͨϝοηʔδΛϨεϙϯε"1*ʹૹΔ

Slide 104

Slide 104 text

Hello world in Scala Native Build code with docker

Slide 105

Slide 105 text

Hello world in Scala Native Build code with docker FROM amazonlinux:latest ENV SCALA_VERSION="2.11.12" WORKDIR /build/ RUN yum install -y java-1.8.0 && \ yum install -y tar.x86_64 && \ yum install -y gzip gunzip RUN curl -O http://downloads.typesafe.com/scala/${SCALA_VERSION}/scala-${SCALA_VERSION}.tgz RUN tar -xzvf scala-${SCALA_VERSION}.tgz && \ rm -rf scala-${SCALA_VERSION}.tgz && \ echo "export SCALA_HOME=/home/ec2-user/scala-${SCALA_VERSION}" >> ~/.bashrc && \ echo "export PATH=$PATH:/home/ec2-user/scala-${SCALA_VERSION}/bin:/opt/llvm-3.9.0/bin" >> ~/.bashrc && \ source ~/.bashrc #SBT RUN curl https://bintray.com/sbt/rpm/rpm | tee /etc/yum.repos.d/bintray-sbt-rpm.repo RUN yum install -y sbt WORKDIR /build/runtime/ RUN yum install -y -q yum-utils RUN yum-config-manager --enable epel > /dev/null RUN yum -y update RUN yum -y group install "development tools" RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm RUN echo $'[alonid-llvm-3.9.0] \n\ name=Copr repo for llvm-3.9.0 owned by alonid \n\ baseurl=https://copr-be.cloud.fedoraproject.org/results/alonid/llvm-3.9.0/epel-7-$basearch/ \n\ type=rpm-md \n\ skip_if_unavailable=True \n\ gpgcheck=1 \n\ gpgkey=https://copr-be.cloud.fedoraproject.org/results/alonid/llvm-3.9.0/pubkey.gpg \n\ repo_gpgcheck=0 \n\ enabled=1 \n\ enabled_metadata=1' >> /etc/yum.repos.d/epel.repo RUN yum install -y clang-3.9.0 RUN yum install -y llvm-3.9.0 llvm-3.9.0-devel RUN yum install -y zip which libunwind libunwind-devel python-pip jq libcurl-devel RUN mkdir -p /build/runtime/lib/ && cp /usr/lib64/libunwind.so /build/runtime/lib/libunwind.so.8 && cp /usr/lib64/libunwind-x86_64.so.8 /build/runtime/lib/libunwind-x86_64.so.8 RUN yum install -y libidn libidn-devel && cp /usr/lib64/libidn.so.11 lib/libidn.so.11 RUN yum install -y git make openssl-devel RUN curl -O -L https://github.com/curl/curl/releases/download/curl-7_62_0/curl-7.62.0.tar.gz && tar -zxvf curl-7.62.0.tar.gz RUN curl -O -L https://github.com/openssl/openssl/archive/OpenSSL_1_0_2l.tar.gz && tar -zxvf OpenSSL_1_0_2l.tar.gz RUN git clone https://github.com/google/re2.git WORKDIR /build/runtime/re2/ ENV LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH ENV CXX=/opt/llvm-3.9.0/bin/clang++ LDFLAGS="-static-libstdc++" RUN make && make install RUN cp /usr/local/lib/libre2.so.0 /build/runtime/lib/libre2.so.0 WORKDIR /build/runtime/openssl-OpenSSL_1_0_2l RUN ./config --prefix=/opt/lib/ssl --openssldir=/opt/lib/ssl shared zlib RUN make && make install WORKDIR /build/runtime/curl-7.62.0/ ENV LD_LIBRARY_PATH=/opt/lib:/usr/lib64:$LD_LIBRARY_PATH RUN mkdir -p /build/runtime/lib/ssl && cp -r /opt/lib/ssl/lib /build/runtime/lib/ssl/lib RUN ./configure --prefix=$(/build/runtime) --with-ssl=/opt/lib/ssl && make && make install # libs RUN cp /lib/libcurl.so.4 /build/runtime/lib/libcurl.so.4 && cp /opt/lib/ssl/lib/libcrypto.so.1.0.0 /build/runtime/lib/libcrypto.so.1.0.0 && cp /opt/lib/ssl/lib/libssl.so.1.0.0 /build/runtime/lib/libssl.so.1.0.0 WORKDIR /build/runtime/ RUN rm OpenSSL_1_0_2l.tar.gz curl-7.62.0.tar.gz RUN mkdir -p /build/main WORKDIR /build/main ENV LD_LIBRARY_PATH=/opt/lib/ssl/lib:/usr/local/lib:$LD_LIBRARY_PATH ADD build.sbt /build/main/ ADD project/ /build/main/ CMD tail -f /dev/null

Slide 106

Slide 106 text

Hello world in Scala Native Build code with docker ڊେ FROM amazonlinux:latest ENV SCALA_VERSION="2.11.12" WORKDIR /build/ RUN yum install -y java-1.8.0 && \ yum install -y tar.x86_64 && \ yum install -y gzip gunzip RUN curl -O http://downloads.typesafe.com/scala/${SCALA_VERSION}/scala-${SCALA_VERSION}.tgz RUN tar -xzvf scala-${SCALA_VERSION}.tgz && \ rm -rf scala-${SCALA_VERSION}.tgz && \ echo "export SCALA_HOME=/home/ec2-user/scala-${SCALA_VERSION}" >> ~/.bashrc && \ echo "export PATH=$PATH:/home/ec2-user/scala-${SCALA_VERSION}/bin:/opt/llvm-3.9.0/bin" >> ~/.bashrc && \ source ~/.bashrc #SBT RUN curl https://bintray.com/sbt/rpm/rpm | tee /etc/yum.repos.d/bintray-sbt-rpm.repo RUN yum install -y sbt WORKDIR /build/runtime/ RUN yum install -y -q yum-utils RUN yum-config-manager --enable epel > /dev/null RUN yum -y update RUN yum -y group install "development tools" RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm RUN echo $'[alonid-llvm-3.9.0] \n\ name=Copr repo for llvm-3.9.0 owned by alonid \n\ baseurl=https://copr-be.cloud.fedoraproject.org/results/alonid/llvm-3.9.0/epel-7-$basearch/ \n\ type=rpm-md \n\ skip_if_unavailable=True \n\ gpgcheck=1 \n\ gpgkey=https://copr-be.cloud.fedoraproject.org/results/alonid/llvm-3.9.0/pubkey.gpg \n\ repo_gpgcheck=0 \n\ enabled=1 \n\ enabled_metadata=1' >> /etc/yum.repos.d/epel.repo RUN yum install -y clang-3.9.0 RUN yum install -y llvm-3.9.0 llvm-3.9.0-devel RUN yum install -y zip which libunwind libunwind-devel python-pip jq libcurl-devel RUN mkdir -p /build/runtime/lib/ && cp /usr/lib64/libunwind.so /build/runtime/lib/libunwind.so.8 && cp /usr/lib64/libunwind-x86_64.so.8 /build/runtime/lib/libunwind-x86_64.so.8 RUN yum install -y libidn libidn-devel && cp /usr/lib64/libidn.so.11 lib/libidn.so.11 RUN yum install -y git make openssl-devel RUN curl -O -L https://github.com/curl/curl/releases/download/curl-7_62_0/curl-7.62.0.tar.gz && tar -zxvf curl-7.62.0.tar.gz RUN curl -O -L https://github.com/openssl/openssl/archive/OpenSSL_1_0_2l.tar.gz && tar -zxvf OpenSSL_1_0_2l.tar.gz RUN git clone https://github.com/google/re2.git WORKDIR /build/runtime/re2/ ENV LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH ENV CXX=/opt/llvm-3.9.0/bin/clang++ LDFLAGS="-static-libstdc++" RUN make && make install RUN cp /usr/local/lib/libre2.so.0 /build/runtime/lib/libre2.so.0 WORKDIR /build/runtime/openssl-OpenSSL_1_0_2l RUN ./config --prefix=/opt/lib/ssl --openssldir=/opt/lib/ssl shared zlib RUN make && make install WORKDIR /build/runtime/curl-7.62.0/ ENV LD_LIBRARY_PATH=/opt/lib:/usr/lib64:$LD_LIBRARY_PATH RUN mkdir -p /build/runtime/lib/ssl && cp -r /opt/lib/ssl/lib /build/runtime/lib/ssl/lib RUN ./configure --prefix=$(/build/runtime) --with-ssl=/opt/lib/ssl && make && make install # libs RUN cp /lib/libcurl.so.4 /build/runtime/lib/libcurl.so.4 && cp /opt/lib/ssl/lib/libcrypto.so.1.0.0 /build/runtime/lib/libcrypto.so.1.0.0 && cp /opt/lib/ssl/lib/libssl.so.1.0.0 /build/runtime/lib/libssl.so.1.0.0 WORKDIR /build/runtime/ RUN rm OpenSSL_1_0_2l.tar.gz curl-7.62.0.tar.gz RUN mkdir -p /build/main WORKDIR /build/main ENV LD_LIBRARY_PATH=/opt/lib/ssl/lib:/usr/local/lib:$LD_LIBRARY_PATH ADD build.sbt /build/main/ ADD project/ /build/main/ CMD tail -f /dev/null Oh, huge scala-on-lambda-snappy/scalanative/Dockerfile

Slide 107

Slide 107 text

Hello world in Scala Native ‣ Build docker container & build executable %PDLFSίϯςφͷϏϧυͱɺ࣮ߦՄೳϑΝΠϧͷϏϧυ # bootstrap $ cd scala-on-lambda-snappy/scalanative $ docker build -t native-builder-image . $ docker run --name native-builder -dt native-builder-image $ docker cp ./ native-builder:/build/main/ $ docker exec -it native-builder sbt 'project hello' nativeLink $ docker cp native-builder:/build/main/hello/target/scala-2.11/hello-out \ hello/bootstrap $ zip -Dj hello.zip ./hello/bootstrap # Deploy this zip # runtime layer $ docker cp native-builder:/build/runtime/ ./runtime/ $ cd ./runtime $ zip -r runtime.zip . # Publish this zip as Lambda Layer

Slide 108

Slide 108 text

Hello world in Scala Native ‣ Let's run! 1BDLBHFTJ[F .BYNFNPSZVTBHF $PMETUBSU %VSBUJPO NT 4DBMB+7. .# .# NT 4DBMBKT ,# .# NT 4DBMB/BUJWF .# .# NT

Slide 109

Slide 109 text

Hello world in Scala Native ‣ Let's run! 1BDLBHFTJ[F .BYNFNPSZVTBHF $PMETUBSU %VSBUJPO NT 4DBMB+7. .# .# NT 4DBMBKT ,# .# NT 4DBMB/BUJWF .# .# NT

Slide 110

Slide 110 text

Hello world in Scala Native ‣ Let's run! 1BDLBHFTJ[F .BYNFNPSZVTBHF $PMETUBSU %VSBUJPO NT 4DBMB+7. .# .# NT 4DBMBKT ,# .# NT 4DBMB/BUJWF .# .# NT

Slide 111

Slide 111 text

Hello world in Scala Native ‣ Let's run! 1BDLBHFTJ[F .BYNFNPSZVTBHF $PMETUBSU %VSBUJPO NT 4DBMB+7. .# .# NT 4DBMBKT ,# .# NT 4DBMB/BUJWF .# .# NT

Slide 112

Slide 112 text

Hello world in Scala Native ‣ Let's run! 1BDLBHFTJ[F .BYNFNPSZVTBHF $PMETUBSU %VSBUJPO NT 4DBMB+7. .# .# NT 4DBMBKT ,# .# NT 4DBMB/BUJWF .# .# NT Yay! ΍ͬͨͶʂ

Slide 113

Slide 113 text

"
 Hello world
 in GraalVM native image (SBBM7.ͷOBUJWFJNBHFͰ)FMMPXPSME

Slide 114

Slide 114 text

Hello world in GraalVM native image Build is easier than Scala Native a bit 4DBMB/BUJWFͷϏϧυΑΓ͸গ͠؆୯

Slide 115

Slide 115 text

Hello world in GraalVM native image Build is easier than Scala Native a bit ‣ Write Scala code 4DBMBͷίʔυΛॻ͘

Slide 116

Slide 116 text

Hello world in GraalVM native image Build is easier than Scala Native a bit ‣ Write Scala code ‣ Build fat-jar with sbt-assembly TCUBTTFNCMZͰGBUKBSΛϏϧυ͢Δ

Slide 117

Slide 117 text

Hello world in GraalVM native image Build is easier than Scala Native a bit ‣ Write Scala code ‣ Build fat-jar with sbt-assembly ‣ Build the GraalVM docker container ‣ Community Edition, in this sample (SBBM7.ͷ%PDLFSίϯςφΛϏϧυ͢Δ

Slide 118

Slide 118 text

Hello world in GraalVM native image Build is easier than Scala Native a bit ‣ Write Scala code ‣ Build fat-jar with sbt-assembly ‣ Build the GraalVM docker container ‣ Community Edition, in this sample ‣ Build executable from jar with the docker and deploy %PDLFSΛ࢖ͬͯKBS͔Β࣮ߦՄೳϑΝΠϧΛϏϧυ͠ɺσϓϩΠ͢Δ

Slide 119

Slide 119 text

Hello world in GraalVM native image ‣ build.sbt // build.sbt lazy val commonSettings = Seq( scalaVersion := "2.12.8" ) lazy val hello = (project in file("hello")) .settings( commonSettings, libraryDependencies ++= Seq( "com.softwaremill.sttp" %% "core" % "1.5.11", "io.argonaut" %% "argonaut" % "6.2.2" ) )

Slide 120

Slide 120 text

Hello world in GraalVM native image ‣ Almost the same as Scala Native's Hello world 4DBMB/BUJWFͷ)FMMPXPSMEͱ΄΅ಉ͡ import argonaut._; import Argonaut._; import com.softwaremill.sttp._ object Hello { implicit val backend = HttpURLConnectionBackend() implicit val requestCodec = casecodec1(Request.apply, Request.unapply)("name") def main(args: Array[String]): Unit = { val runtimeApi = System.getenv("AWS_LAMBDA_RUNTIME_API") while (true) { val next = sttp.get(uri"http://$runtimeApi/2018-06-01/runtime/invocation/next").send() val requestId = next.headers("lambda-runtime-aws-request-id").head val request = next.unsafeBody.decodeOption[Request].get val responseJson = Json("message" -> jString(s"Hello, ${request.name}!")).nospaces sttp.post(uri"http://$runtimeApi/2018-06-01/runtime/invocation/$requestId/response") .body(responseJson).send() } } } case class Request(name: String)

Slide 121

Slide 121 text

Hello world in GraalVM native image ‣ First, build fat-jar ‣ Then, build native image from jar with GraalVM ·ͣGBUKBSΛϏϧυ
 ࣍ʹ(SBBM7.ͰKBS͔ΒOBUJWFJNBHFΛϏϧυ $ cd scala-on-lambda-snappy/graalvm # build fat-jar $ sbt 'project hello' assembly # build native image $ docker build -t graal-builder-image . $ docker run --name graal-builder -dt graal-builder-image $ docker cp ./hello/target/scala-2.12/hello-assembly-0.1-SNAPSHOT.jar \ graal-builder:/hello.jar $ docker exec -it graal-builder native-image -jar hello.jar \ -H:EnableURLProtocols=http,https --no-server $ docker cp graal-builder:/hello ./hello/bootstrap $ zip -Dj hello.zip ./hello/bootstrap

Slide 122

Slide 122 text

Hello world in GraalVM native image ‣ Let's run! 1BDLBHFTJ[F .BYNFNPSZVTBHF $PMETUBSU %VSBUJPO NT 4DBMB+7. .# .# NT 4DBMBKT ,# .# NT 4DBMB/BUJWF .# .# NT (SBBM7. .# .# NT

Slide 123

Slide 123 text

Hello world in GraalVM native image ‣ Let's run! 1BDLBHFTJ[F .BYNFNPSZVTBHF $PMETUBSU %VSBUJPO NT 4DBMB+7. .# .# NT 4DBMBKT ,# .# NT 4DBMB/BUJWF .# .# NT (SBBM7. .# .# NT

Slide 124

Slide 124 text

Hello world in GraalVM native image ‣ Let's run! 1BDLBHFTJ[F .BYNFNPSZVTBHF $PMETUBSU %VSBUJPO NT 4DBMB+7. .# .# NT 4DBMBKT ,# .# NT 4DBMB/BUJWF .# .# NT (SBBM7. .# .# NT

Slide 125

Slide 125 text

Hello world in GraalVM native image ‣ Let's run! 1BDLBHFTJ[F .BYNFNPSZVTBHF $PMETUBSU %VSBUJPO NT 4DBMB+7. .# .# NT 4DBMBKT ,# .# NT 4DBMB/BUJWF .# .# NT (SBBM7. .# .# NT

Slide 126

Slide 126 text

Hello world in GraalVM native image ‣ Let's run! 1BDLBHFTJ[F .BYNFNPSZVTBHF $PMETUBSU %VSBUJPO NT 4DBMB+7. .# .# NT 4DBMBKT ,# .# NT 4DBMB/BUJWF .# .# NT (SBBM7. .# .# NT Good! ͍͍Ͷʂ

Slide 127

Slide 127 text

"
 More practical example:
 AWS Integration
 with Scala.js ΋͏গ࣮͠༻తͳྫଞͷ"84αʔϏεͱͷ౷߹Λ4DBMBKTͰ

Slide 128

Slide 128 text

AWS integration with Scala.js ‣ Use AWS SDK for JavaScript ‣ There is some tips to use the SDK type safely ‣ In this example, use DynamoDB Document Client "844%,GPS+BWB4DSJQUΛ࢖͏͕ɺܕ҆શʹѻ͏ʹ͸গʑίπ͕͍Δ ͜ͷྫͰ͸%ZOBNP%#ͷ%PDVNFOU$MJFOUΛ࢖͏

Slide 129

Slide 129 text

Querying DynamoDB with Scala.js ‣ AWS.scala // AWS.scala @JSImport("aws-sdk", JSImport.Namespace) @js.native object AWS extends js.Object { @js.native object DynamoDB extends js.Object { @js.native class DocumentClient extends js.Object { def query( param: js.Dictionary[String], callback:js.Function2[js.Object, js.Object, js.Any] ): Unit = js.native } } }

Slide 130

Slide 130 text

Querying DynamoDB with Scala.js ‣ Import AWS SDK for JavaScript // AWS.scala @JSImport("aws-sdk", JSImport.Namespace) @js.native object AWS extends js.Object { @js.native object DynamoDB extends js.Object { @js.native class DocumentClient extends js.Object { def query( param: js.Dictionary[String], callback:js.Function2[js.Object, js.Object, js.Any] ): Unit = js.native } } } "844%,GPS+BWB4DSJQUͷΠϯϙʔτ

Slide 131

Slide 131 text

Querying DynamoDB with Scala.js ‣ Facade for DocumentClient to handle type safely // AWS.scala @JSImport("aws-sdk", JSImport.Namespace) @js.native object AWS extends js.Object { @js.native object DynamoDB extends js.Object { @js.native class DocumentClient extends js.Object { def query( param: js.Dictionary[String], callback:js.Function2[js.Object, js.Object, js.Any] ): Unit = js.native } } } %PDVNFOU$MJFOUΛܕ҆શʹѻ͏ͨΊͷϑΝαʔυ

Slide 132

Slide 132 text

Querying DynamoDB with Scala.js ‣ DynamoAccessor.scala object DynamoAccessor { val documentClient = new AWS.DynamoDB.DocumentClient() @JSExportTopLevel("handleRequest") def handleRequest(req: Request, cx: js.Object, callback: Callback): Unit = { val param = js.Dynamic.literal( "TableName" -> "PriceHistory", "KeyConditionExpression" -> "#ji = :jobid", "ExpressionAttributeNames" -> js.Dynamic.literal("#ji" -> "JobId"), "ExpressionAttributeValues" -> js.Dynamic.literal(":jobid" -> req.jobId) ) documentClient.query( param, (err: js.Object, data: js.Object) => callback(null, data)) } }

Slide 133

Slide 133 text

Querying DynamoDB with Scala.js ‣ Initialize DocumentClient object DynamoAccessor { val documentClient = new AWS.DynamoDB.DocumentClient() @JSExportTopLevel("handleRequest") def handleRequest(req: Request, cx: js.Object, callback: Callback): Unit = { val param = js.Dynamic.literal( "TableName" -> "PriceHistory", "KeyConditionExpression" -> "#ji = :jobid", "ExpressionAttributeNames" -> js.Dynamic.literal("#ji" -> "JobId"), "ExpressionAttributeValues" -> js.Dynamic.literal(":jobid" -> req.jobId) ) documentClient.query( param, (err: js.Object, data: js.Object) => callback(null, data)) } } %PDVNFOU$MJFOUͷΠχγϟϥΠζ

Slide 134

Slide 134 text

Querying DynamoDB with Scala.js ‣ Prepare param (using Dynamic, so not type safe...) object DynamoAccessor { val documentClient = new AWS.DynamoDB.DocumentClient() @JSExportTopLevel("handleRequest") def handleRequest(req: Request, cx: js.Object, callback: Callback): Unit = { val param = js.Dynamic.literal( "TableName" -> "PriceHistory", "KeyConditionExpression" -> "#ji = :jobid", "ExpressionAttributeNames" -> js.Dynamic.literal("#ji" -> "JobId"), "ExpressionAttributeValues" -> js.Dynamic.literal(":jobid" -> req.jobId) ) documentClient.query( param, (err: js.Object, data: js.Object) => callback(null, data)) } } ύϥϝʔλͷ༻ҙ %ZOBNJDΛ࢖͍ͬͯΔͷͰܕ҆શͰ͸ͳ͍

Slide 135

Slide 135 text

Querying DynamoDB with Scala.js ‣ To make it type safe, define type like the Request trait object DynamoAccessor { val documentClient = new AWS.DynamoDB.DocumentClient() @JSExportTopLevel("handleRequest") def handleRequest(req: Request, cx: js.Object, callback: Callback): Unit = { val param = js.Dynamic.literal( "TableName" -> "PriceHistory", "KeyConditionExpression" -> "#ji = :jobid", "ExpressionAttributeNames" -> js.Dynamic.literal("#ji" -> "JobId"), "ExpressionAttributeValues" -> js.Dynamic.literal(":jobid" -> req.jobId) ) documentClient.query( param, (err: js.Object, data: js.Object) => callback(null, data)) } } ܕ҆શʹ͢ΔͳΒɺ3FRVFTUτϨΠτͷΑ͏ʹܕΛఆٛ͢Δ

Slide 136

Slide 136 text

Querying DynamoDB with Scala.js ‣ Submit a query with the client object DynamoAccessor { val documentClient = new AWS.DynamoDB.DocumentClient() @JSExportTopLevel("handleRequest") def handleRequest(req: Request, cx: js.Object, callback: Callback): Unit = { val param = js.Dynamic.literal( "TableName" -> "PriceHistory", "KeyConditionExpression" -> "#ji = :jobid", "ExpressionAttributeNames" -> js.Dynamic.literal("#ji" -> "JobId"), "ExpressionAttributeValues" -> js.Dynamic.literal(":jobid" -> req.jobId) ) documentClient.query( param, (err: js.Object, data: js.Object) => callback(null, data)) } } ΫϥΠΞϯτΛ࢖ͬͯΫΤϦΛ౤͛Δ

Slide 137

Slide 137 text

Facade library for aws-sdk ‣ exoego/aws-sdk-scalajs-facade 
 https://github.com/exoego/aws-sdk-scalajs-facade ‣ Scala.js type facade for aws-sdk-js ‣ A fork of balshor/aws-sdk-scalajs-facade ‣ It's also good for learning how to write facade type by yourself FYPFHPBXTTELTDBMBKTGBDBEFͱ͍͏ϑΝαʔυϥΠϒϥϦ͕͋Δ
 ϑΝαʔυͷॻ͖ํΛֶͿͷʹ΋Αͦ͞͏

Slide 138

Slide 138 text

AWS with Scala Native? ‣ Currently, there's no Scala Native library of AWS SDK ‣ So need to implement a client which invokes AWS REST API ‣ cf. rusoto: A third-party AWS SDK for Rust https://rusoto.org 4DBMB/BUJWF൛ͷ"844%,GPS+BWB͸ݱঢ়ͳ͍
 ΋͠"84αʔϏεΛ࢖͍͍ͨ৔߹ɺΫϥΠΞϯτΛ࣮૷͢Δඞཁ͕͋Δ

Slide 139

Slide 139 text

AWS with GraalVM? ‣ GraalVM is able to build native images from Java, however... (SBBM7.͸+BWB͔ΒOBUJWFJNBHFΛϏϧυͰ͖Δ͕

Slide 140

Slide 140 text

AWS with GraalVM? ‣ GraalVM is able to build native images from Java, however... ‣ There is some limitations of SubstrateVM 4VCTUSBUF7.ͷ͍͔ͭ͘ͷ੍ݶ͕͋Δ

Slide 141

Slide 141 text

AWS with GraalVM? ‣ GraalVM is able to build native images from Java, however... ‣ There is some limitations of SubstrateVM ‣ AOT compilation doesn't support Dynamic class loading
 https://github.com/oracle/graal/blob/master/substratevm/LIMITATIONS.md ྫ͑͹ɺDMBTTͷಈతͳMPBEJOHVOMPBEJOH͸αϙʔτ͞Ε͍ͯͳ͍

Slide 142

Slide 142 text

AWS with GraalVM? ‣ GraalVM is able to build native images from Java, however... ‣ There is some limitations of SubstrateVM ‣ AOT compilation doesn't support Dynamic class loading
 https://github.com/oracle/graal/blob/master/substratevm/LIMITATIONS.md ‣ AWS SDK for Java uses commons-logging which uses ClassLoader... "844%,GPS+BWBͷDPNNPOTMPHHJOH͕$MBTT-PBEFSΛ࢖͍ͬͯΔ

Slide 143

Slide 143 text

AWS with GraalVM? ‣ GraalVM is able to build native images from Java, however... ‣ There is some limitations of SubstrateVM ‣ AOT compilation doesn't support Dynamic class loading
 https://github.com/oracle/graal/blob/master/substratevm/LIMITATIONS.md ‣ AWS SDK for Java uses commons-logging which uses ClassLoader... "844%,GPS+BWBͷDPNNPOTMPHHJOH͕$MBTT-PBEFSΛ࢖͍ͬͯΔ

Slide 144

Slide 144 text

"
 More practical example:
 Kuromoji with GraalVM ΋͏গ࣮͠༻తͳྫ,VSPNPKJΛ(SBBM7.ͰOBUJWFJNBHFʹ

Slide 145

Slide 145 text

Kuromoji ‣ atilika / kuromoji https://github.com/atilika/kuromoji ‣ A Japanese morphological analyzer written in Java ‣ Its name is derived from "ࠇจࣈ" ‣ A traditional small wooden knife to cut Japanese sweets in tea ceremony ,VSPNPKJ+BWB੡ͷ೔ຊޠܗଶૉղੳϥΠϒϥϦ
 ໊લ͸࿨՛ࢠΛ੾Γ෼͚Δʮࠇจࣈʯʹ༝དྷ͢ΔʢΒ͍͠ʣ

Slide 146

Slide 146 text

Kuromoji ‣ atilika / kuromoji https://github.com/atilika/kuromoji ‣ A Japanese morphological analyzer written in Java ‣ Its name is derived from "ࠇจࣈ" ‣ A traditional small wooden knife to cut Japanese sweets in tea ceremony ‣ Let's create a morphological analysis API with this! ؆୯ͳܗଶૉղੳ"1*Λ࡞ͬͯΈΑ͏ʂ

Slide 147

Slide 147 text

Kuromoji with GraalVM ‣ Kuromoji.scala object Kuromoji { implicit val backend = HttpURLConnectionBackend() def main(args: Array[String]): Unit = { val runtime = System.getenv("AWS_LAMBDA_RUNTIME_API") val tokenizer = new Tokenizer() while (true) { val req = sttp.get(uri"http://$runtime/2018-06-01/runtime/invocation/next").send() val requestId = req.headers("lambda-runtime-aws-request-id").head val text = Parse.parseWith(req.unsafeBody, _.field("text").flatMap(_.string).get, identity) val results = tokenizer.tokenize(text).asScala.map { token => jString(s"${token.getSurface}: ${token.getAllFeatures}") } sttp.post(uri"http://$runtime/2018-06-01/runtime/invocation/$requestId/response") .body(Json.array(results :_*).nospaces).send() } } }

Slide 148

Slide 148 text

Kuromoji with GraalVM ‣ Parse text with Kuromoji & tokenize object Kuromoji { implicit val backend = HttpURLConnectionBackend() def main(args: Array[String]): Unit = { val runtime = System.getenv("AWS_LAMBDA_RUNTIME_API") val tokenizer = new Tokenizer() while (true) { val req = sttp.get(uri"http://$runtime/2018-06-01/runtime/invocation/next").send() val requestId = req.headers("lambda-runtime-aws-request-id").head val text = Parse.parseWith(req.unsafeBody, _.field("text").flatMap(_.string).get, identity) val results = tokenizer.tokenize(text).asScala.map { token => jString(s"${token.getSurface}: ${token.getAllFeatures}") } sttp.post(uri"http://$runtime/2018-06-01/runtime/invocation/$requestId/response") .body(Json.array(results :_*).nospaces).send() } } } ,VSPNPKJΛ࢖ͬͯςΩετΛύʔε͠ɺτʔΫϯԽ͢Δ

Slide 149

Slide 149 text

Kuromoji with GraalVM

Slide 150

Slide 150 text

Other examples in repo ‣ Takeuchi function ‣ As known as "Tarai-mawashi Function" ‣ High load function; when takeuchi(2n, n, 0), O(n^n) ‣ Slack notification of S3 put with Scala Native ͦͷଞͷαϯϓϧ https://github.com/todokr/scala-on-lambda-snappy

Slide 151

Slide 151 text

Pros & Cons ௕ॴͱ୹ॴ

Slide 152

Slide 152 text

Scala.js ‣ Pros ‣ Very small code size (hello.zip: 4KB) ‣ Integration with AWS services ‣ Cons ‣ Need to write some boilerplaty facade for type safe ‣ Need to know Node.js API, ecosystem, manners, etc... ‣ I use this for ‣ DynamoDB accessor ௕ॴίʔυαΠζͷখ͞͞ɺ"84αʔϏεͱͷ࿈ܞ ୹ॴϘΠϥʔϓϨʔτతϑΝαʔυ /PEFKTͷ஌͕ࣝඞཁ

Slide 153

Slide 153 text

Scala Native ‣ Pros ‣ Relatively small package size (hello.zip: 1.3M) ‣ Cons ‣ Tricky to build for Lambda ‣ Need to check if the library is supported for Scala Native ௕ॴൺֱతখ͍͞ύοέʔδαΠζ
 ୹ॴ-BNCEB޲͚ͷϏϧυʹίπ͕͍Δɺ࢖͍͍ͨϥΠϒϥϦ͕
 4DBMB/BUJWFʹରԠ͍ͯ͠Δ͔֬ೝ͢Δඞཁ͕͋Δ

Slide 154

Slide 154 text

Native image built by GraalVM ‣ Pros ‣ Easy to use Scala/Java libraries ‣ Cons ‣ Relatively large package size (hello.zip: 7.3MB) ‣ Tricky to build a bit ‣ Some limitation of AOT compilation ௕ॴ4DBMB΍+BWBͷϥΠϒϥϦΛ؆୯ʹ࢖͑Δ
 ୹ॴύοέʔδ͕ͦͦ͜͜େ͖͍ Ϗϧυʹগʑίπ͕͍Δ 
 "05ίϯύΠϧͷ੍ݶ͕͋Δ

Slide 155

Slide 155 text

My case: EC Discount Notifier cron Cloudwatch Events Crawler Price history Amazon etc. Notifier ࢲͷར༻έʔε&$ͷ஋Լ͛৘ใΛ௨஌

Slide 156

Slide 156 text

My case: EC Discount Notifier cron Cloudwatch Events Crawler Price history Amazon etc. Notifier Ϋϩʔϥʔ͸(SBBM7.OBUJWFJNBHF
 +TPVQ +BWBϥΠϒϥϦ Λ࢖͑Δ͜ͱ΍ɺจࣈίʔυͷѻ͍Ͱ༗ར GraalVM native-image - Using Jsoup (Java library) - Charset

Slide 157

Slide 157 text

My case: EC Discount Notifier cron Cloudwatch Events Crawler Price history Amazon etc. Notifier /PUJpFS͸4DBMB+4Y/PEFKTϥϯλΠϜ 4%,͕࢖͑ΔͷͰɺ%ZOBNP%#΁ͷΞΫηε͕༰қ GraalVM native-image - Using Jsoup (Java library) - Charset ScalaJS x Node.js -Accessing DynamoDB

Slide 158

Slide 158 text

Java improvement for the container age ‣ Java continue to evolve! +BWB΋ਐԽ͠ଓ͚͍ͯΔ

Slide 159

Slide 159 text

Java improvement for the container age ‣ Java continue to evolve! ‣ jlink (Java9) ‣ A command-line tool to create customized small JRE খ͞ͳ+3&Λ࡞ΔͨΊͷKMJOL

Slide 160

Slide 160 text

Java improvement for the container age ‣ Java continue to evolve! ‣ jlink (Java9) ‣ A command-line tool to create customized small JRE ‣ Class-Data Sharing (JEP 310, 341) ‣ storing the preprocessed class metadata to file ‣ loading classes from CDS file improves startup performance ىಈΛߴ଎Խ͢Δ$MBTT%BUB4IBSJOH

Slide 161

Slide 161 text

✅
 Conclusion ·ͱΊ

Slide 162

Slide 162 text

‣ Run Scala on Lambda without JVM is not so simple 4DBMBΛ+7.ͳ͠Ͱಈ͔͢ͷ͸ͦΜͳʹγϯϓϧͰ͸ͳ͍

Slide 163

Slide 163 text

‣ Run Scala on Lambda without JVM is not so simple ‣ However, it's powerful on some special occasion ͔͠͠ɺಛผͳঢ়گԼͰ͸ͱͯ΋ύϫϑϧ

Slide 164

Slide 164 text

‣ Run Scala on Lambda without JVM is not so simple ‣ However, it's powerful on some special occasion ‣ So, we should consider the trade-off ͳͷͰɺࢲͨͪ͸τϨʔυΦϑΛߟ͑Δඞཁ͕͋Δ

Slide 165

Slide 165 text

‣ Run Scala on Lambda without JVM is not so simple ‣ However, it's powerful on some special occasion ‣ So, we should consider the trade-off ‣ Need to integrate with other AWS service 
 => Scala.js with Node.js runtime "84αʔϏεͱͷ࿈ܞ͕ඞཁ/PEFKTϥϯλΠϜͰ4DBMBKT

Slide 166

Slide 166 text

‣ Run Scala on Lambda without JVM is not so simple ‣ However, it's powerful on some special occasion ‣ So, we should consider the trade-off ‣ Need to integrate with other AWS service 
 => Scala.js with Node.js runtime ‣ Need to use Java library & run snappy 
 => Native Image with GraalVM +BWBͷϥΠϒϥϦΛ࢖͍ɺαΫαΫಈ͔͢ඞཁ͕͋Δ
 (SBBM7.ͰOBUJWFJNBHF

Slide 167

Slide 167 text

‣ Run Scala on Lambda without JVM is not so simple ‣ However, it's powerful on some special occasion ‣ So, we should consider the trade-off ‣ Need to integrate with other AWS service 
 => Scala.js with Node.js runtime ‣ Need to use Java library & run snappy 
 => Native Image with GraalVM ‣ Invoked constantly and throughput is not so important 
 => Just use Java8 runtime ఆظతͳݺͼग़͕͋͠Γɺεϧʔϓοτ͕ॏཁͰͳ͍
 ૉ௚ʹ+BWBϥϯλΠϜΛ࢖͓͏

Slide 168

Slide 168 text

‣ Run Scala on Lambda without JVM is not so simple ‣ However, it's powerful on some special occasion ‣ So, we should consider the trade-off ‣ Need to integrate with other AWS service 
 => Scala.js with Node.js runtime ‣ Need to use Java library & run snappy 
 => Native Image with GraalVM ‣ Invoked constantly and throughput is not so important 
 => Just use Java8 runtime ‣ _ => Give up and use other runtime such as Python or Node.js ͦΕҎ֎ͳΒɺఘΊͯ1ZUIPO΍/PEFKTͳͲଞͷϥϯλΠϜΛ࢖͓͏

Slide 169

Slide 169 text

Thank you! Contact(via) match { case GitHub => "@todokr" case Twitter => "@todokr" case Facebook => "shusnuke.tadokoro" case _ => Dynamic.talk } ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ