Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Spark Framework with Kotlin
Search
stormcat24
February 20, 2017
Programming
3.4k
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Spark Framework with Kotlin
2017.02.20 JJUG Night Seminor Kotlin
stormcat24
February 20, 2017
More Decks by stormcat24
See All by stormcat24
素早く賢く失敗するDeveloper Productivityの実現を目指して
stormcat24
4
5.5k
KubernetesのマニフェストをそれなりにCIしたい
stormcat24
4
1.6k
令和時代のSaaS開発
stormcat24
1
360
History in 5 years of CircleCI and CyberAgent
stormcat24
3
920
Kubernetes Handson Osaka
stormcat24
5
650
Kubernetes Handson
stormcat24
5
4.6k
DockerとKubernetesでアプリケーション開発にコンテナをフル活用!
stormcat24
0
400
Base Image Journey 2018
stormcat24
30
140k
kotlin-fest
stormcat24
13
19k
Other Decks in Programming
See All in Programming
変化を抱擁するドキュメントの作り方 - ビジネスルール駆動開発がもたらす、コードとの新しい関係
ioki
2
120
思考垂れ流し開発 ~音声入力 × AIエージェント × 開発ハーネスによる試行錯誤~
npostring
0
980
The Good Stuff, Not the Slop: Engineering High-Quality Android Apps with Modern AI Tooling
danybony
1
210
Swift愛好会と私(ウホーイ) / Swift Fan Club and Uhooi
uhooi
0
150
GKE で Pod の見方を変えたら、スケールアウト時の挙動を真に捉えられた話
stkk
0
100
WebMCP Challenge に星空観察アプリで参加した話
okajun35
0
110
Intent as Code
shoppingjaws
4
560
Hono + Inertia + React で LP を構築した話
oukayuka
2
220
Seeing Through Serverless: Observability for AWS Lambda with ADOT and CloudWatch Application Signals
seike460
PRO
1
130
Oxlintはいいぞ(続)
yug1224
1
560
世界の中心で、AI(App Intents)をさけぶ ー App Intents中心設計の実践ガイド
touyou
0
180
Swift愛好会100回記念 第1回を振り返る
jollyjoester
0
120
Featured
See All Featured
Everyday Curiosity
cassininazir
0
310
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.3k
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
1
2.9k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
880
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
520
From π to Pie charts
rasagy
0
360
Making the Leap to Tech Lead
cromwellryan
135
10k
What's in a price? How to price your products and services
michaelherold
247
13k
Side Projects
sachag
455
43k
Into the Great Unknown - MozCon
thekraken
41
2.7k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
3k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.9k
Transcript
2017.02.20 JJUG Night Seminor Kotlin Spark Framework with Kotlin @stormcat24
stormcat24 ‣ CyberAgent, Inc. ‣ FRESH! ‣ DevOps / Docker
Comedian ‣ ワタシコトリンチョットカケルアルヨ ‣ 最近の興味はRust
None
None
technology stack ‣ Microservices Architecture ‣ Full Dockernized ‣ Amazon
Web Services ‣ EC2 Container Services(ECS) ‣ Golang
https://speakerdeck.com/stormcat24/docker-darakefalse-fresh-nadong-hua-pei-xin-puratutohuomu
https://aws.amazon.com/jp/solutions/case-studies/cyberagent/
Golang と FRESH ‣ 2016/01のリリースから一貫してGolangを主要言語として採用 ‣ 1Service = 1Container =
1Repository ‣ Public/Internal問わず十数個のMicroservicesが誕生 ‣ シンプル
しかしつらくなってきた ‣ 基本的に筋力に頼る言語 ‣ 記述量が多い ‣ 高階関数ほしい ‣ 生産性を上げるためのコード生成 ‣
タイプ量 成果と満足感❓ ‣ ゴリゴリとAPIを書いていくのはしんどいというメンバーの総意
新たな基軸言語を求めた
Microservicesの特性を活かす ‣ 言語はServiceによって変えられる ‣ 将来的に変えることも想定していた ‣ Serviceの特性によって、適材適所なものを選んでいくのが重要 ‣ ミドル層、低レイヤー層は引き続きGolang ‣
新たに、一つの基軸言語を選ぶ(乱立は(・A・)イクナイ!!)
None
基軸言語にKotlinを選択 ‣ API実装の基軸言語として、新たにKotlinを採用 ‣ 新しいMicroservicesは基本Kotlinで ‣ Golangの既存Serviceを置き換えるわけではない
Kotlinの理由 ‣ モダンな文法 ‣ IDE(IntelliJ IDEA) ‣ 一番現実的だった ‣ 社内リソース(JVM系人材、Androidでの実績)
助走期間 ‣ 正式に選定する前に、内部の決済用ServiceをKotlinで実装 ‣ Spring Boot ‣ Springfox ‣ AnnotationからSwaggerを吐き出すやつ
‣ domaframework ‣ すごい
感想 ‣ 高い生産性 ‣ そこそこの学習コスト(Java/Spring経験による) ‣ もうちょっと薄いものでいいかもしれない? ‣ MonolithicなServiceを作るわけではないため
Spark Framework
http://sparkjava.com/
Spark Framework is ‣ Java8ベースのマイクロWebフレームワーク ‣ Apache Sparkとは別物 ‣ ググラビリティ・・・
‣ Lambda式を利用 ‣ Imspired by Sinatra ‣ Routing/Filter等最低限の機能、DIとか無いです
In Java package io.stormcat; import static spark.Spark.*; public
class Server { public static void main(String[] args) { get("/echo", (req, res) -> "Hello, " + req.queryParams("name") + "!"); } }
Spark Framework with Kotlin ‣ Java8 Lambda式だけでは満足できない ‣ Spark Frameworkのシンプルさと、Kotlinの良さを活かす
‣ 必要なライブラリを追加して、自力で統合していくスタイル ‣ SpringのようにIntegrationが充実しているわけではないが、相 性の悪さだったり、迷いはあまり無い
Kotlin使ってこ fun main(args: Array<String>) { get("/echo", { req, res
-> "Hello, ${req.queryParams("name")}!" }) }
Spark with Kotlinお品書き ‣ Controller / Routing ‣ Filters ‣
ResponseTransformer(JSON) ‣ data class ‣ 拡張関数 ‣ Guice(Dependency Injection) ‣ 愚直なDI ‣ okhttp ‣ hystrix ‣ Metrics(Jolokia)
Controller package io.stormcat.controller import spark.* class EchoController {
val echo = Route { req, res -> "Hello, ${req.queryParams("name")}!" } }
Routing package io.stormcat import io.stormcat.controller.EchoController import spark.Spark.* fun
main(args: Array<String>) { get("/echo", EchoController().echo) }
Filters package io.stormcat.filter import spark.Filter import spark.Request import spark.Response
class ResponseHeaderFilter : Filter { override fun handle(request: Request, response: Response) { response.header("Server", "Your Kotlin Server") } }
Filters package io.stormcat import io.stormcat.controller.EchoController import io.stormcat.filter.ResponseHeaderFilter import spark.Spark.*
fun main(args: Array<String>) { // filters after(ResponseHeaderFilter()) // routing get("/echo", EchoController().echo) } ‣ before/after ‣ 認証や、横断的関心事の解決
ResponseTransformer package io.stormcat import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule import com.fasterxml.jackson.module.kotlin.KotlinModule
import spark.ResponseTransformer class JsonTransformer : ResponseTransformer { val mapper = ObjectMapper() .registerModule(JavaTimeModule()) .registerModule(KotlinModule()) override fun render(model: Any?): String { return mapper.writeValueAsString(model) } } ‣ JacksonのKotlinModule ‣ data class をサポート
data class package io.stormcat.controller import spark.* class EchoController
{ data class EchoResult( val name: String, val message: String ) val echo = Route { req, res -> EchoResult( name = req.queryParams("name"), message = "Hello" ) } } ‣ レスポンスをdata classで扱う ‣ Controller内に気軽に書けて(・∀・)イイ!!
拡張関数 package io.stormcat.controller import spark.Request fun Request.authUser(): User
{ val user = this.attribute<User>("authUser") return user ?: throw RuntimeException("Authorization Required") } ‣ spark.Requestに認証情報をセット ‣ spark.Requestに関数を生やして取れるようにしてしまう ‣ ラップするより拡張という選択
Guice(Dependency Injection) package io.stormcat.controller import com.google.inject.Inject import io.stormcat.service.UserService import
spark.* class UserController @Inject constructor( val userService: UserService ) { val getUser = Route { req, res -> val userId = req.params("id")?.toLong() ?: throw RuntimeException("id is required") userService.getUser(userId) } } ‣ Guiceを使ってconstructor injection
愚直なDI fun main(args: Array<String>) { val injector = Guice.createInjector(object
: AbstractModule() { override fun configure() { bindConstant().annotatedWith( Names.named("apiDomain")).to("api.yourexample.com") bind(ObjectMapper::class.java) .toProvider(ObjectMapperProvider::class.java) .`in`(Singleton::class.java) } }) val userController = injector.getInstance(UserController::class.java) // routing get("/user/:id", userController.getUser) } ‣ 依存関係、スコープを愚直に定義 ‣ ControllerをInjectorから取得
okhttp class UserApiClient @Inject constructor(val mapper: ObjectMapper, val client: OkHttpClient,
@Named("apiDomain") val apiDomain: String ) { fun getUser(ids: List<Long>): List<User> { val urlBuilder = HttpUrl.Builder().scheme(“https").host(apiDomain) .addPathSegment("users").addPathSegment(ids.joinToString(",")) val request = Request.Builder().url(urlBuilder.build()).build() val response = client.newCall(request).execute() if (response.code() != 200) { throw RuntimeException("api error") } val raw = response.body().string() val tr = object : TypeReference<List<User>>() {} return mapper.readValue<List<User>>(raw, tr) } } ‣ Microservices間の通信 ‣ data classにdeserialize
Hystrix ‣ github.com/Netflix/Hystrix ‣ 分散システムにおいて、回復力のあるアーキテクチャを実現するた めのライブラリ ‣ Circuit Brakerをサポート
Circuit Braker ‣ どこか一つのServiceがダウンした際に、リクエストをブロックする して依存サービスが連鎖的に影響を受ける ‣ エラー率が閾値を超えた際に、自動でアクセスを遮断するための仕 組み
Hystrix Dashboard https://github.com/Netflix/Hystrix/wiki/Dashboard
HystrixCommand ‣ 外部サービスへのリクエストや、Latencyを注視しておきたい処理 をHystrixCommandとして実装する ‣ HTTP Client実装を内包するような実装が多い ‣ 対象処理を容易にFutureやObservable化することができる
Hystrix interface GetUserCommandFactory { fun create(@Assisted("id") ids: List<Long>): GetUserCommand }
interface GetUserCommand { fun execute(): List<User> } class GetUserCommandImpl @Inject constructor( @Assisted("ids") val ids: List<Long>, val userApiClient: UserApiClient, val getUserCommandKey: HystrixCommandGroupKey ) : HystrixCommand<List<User>>(getUserCommandKey), GetUserCommand { override fun run(): List<User> { return userApiClient.getUser(ids) } }
Circuit Braker val circuitBreakerProperties = HystrixCommandProperties.Setter() .withCircuitBreakerEnabled(true) .withCircuitBreakerErrorThresholdPercentage(50) val
getUserCommandKey = HystrixCommand.Setter .withGroupKey(HystrixCommandGroupKey.Factory.asKey("getUser")) .andCommandPropertiesDefaults(circuitBreakerProperties) ‣ Circuit Brakerの閾値を設定できる ‣ HystrixCommand初期化時にCommandKeyとして設定
Metrics(Jolokia) ‣ Jolikiaを入れておけばJVMのMetricsが取れる ‣ Dockerを使う場合、Dockerビルドの際に入れておいて、HTTPで取 れるようにしとくのが楽
Metrics(Jolokia) FROM java:openjdk-8-jdk-alpine COPY . /spark-kotlin RUN apk
update && \ apk add --virtual build-dependencies build-base bash curl && \ cd /spark-kotlin && ./gradlew clean && \ cd /spark-kotlin && ./gradlew build && \ mkdir -p /usr/local/spark-kotlin/lib && \ cp -R /spark-kotlin/build/libs/* /usr/local/spark-kotlin/lib/ && \ curl -o /usr/local/spark-kotlin/lib/jolokia-jvm-agent.jar \ https://repo1.maven.org/maven2/org/jolokia/jolokia-jvm/1.3.5/jolokia-jvm-1.3.5-agent.jar && \ apk del build-dependencies && \ rm -rf /var/cache/apk/* && \ rm -rf ~/.gradle && \ rm -rf /spark-kotlin ENTRYPOINT java $JAVA_OPTS \ -javaagent:/usr/local/spark-kotlin/lib/jolokia-jvm-agent.jar=port=8778,host=0.0.0.0 \ -jar /usr/local/spark-kotlin/lib/spark-kotlin.jar EXPOSE 4567 8778
FRESHにおけるSparkとKotlin ‣ ユーザー・配信主用の公開APIとして本番稼働開始 ‣ 各種MicroservicesへのGatewayとしての役割を担う ‣ Hystrix Dashboardこれから活用していきたい
まとめ ‣ Spark + Kotlin十分運用していけるし、現実的な選択肢になった ‣ Microservicesトレンドの中、シンプルなものが求められている ‣ Server Side
Kotlinの波は少しずつ来ている ‣ Kotlin気持ち(・∀・)イイ!!
Thanks