Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Spark Framework with Kotlin
Search
stormcat24
February 20, 2017
Programming
3
3.1k
Spark Framework with Kotlin
2017.02.20 JJUG Night Seminor Kotlin
stormcat24
February 20, 2017
Tweet
Share
More Decks by stormcat24
See All by stormcat24
素早く賢く失敗するDeveloper Productivityの実現を目指して
stormcat24
4
4.6k
KubernetesのマニフェストをそれなりにCIしたい
stormcat24
4
1.2k
令和時代のSaaS開発
stormcat24
1
240
History in 5 years of CircleCI and CyberAgent
stormcat24
3
810
Kubernetes Handson Osaka
stormcat24
5
540
Kubernetes Handson
stormcat24
5
4.2k
DockerとKubernetesでアプリケーション開発にコンテナをフル活用!
stormcat24
0
290
Base Image Journey 2018
stormcat24
29
130k
kotlin-fest
stormcat24
13
17k
Other Decks in Programming
See All in Programming
受け取る人から提供する人になるということ
little_rubyist
0
230
Pinia Colada が実現するスマートな非同期処理
naokihaba
4
220
OnlineTestConf: Test Automation Friend or Foe
maaretp
0
110
Amazon Bedrock Agentsを用いてアプリ開発してみた!
har1101
0
330
Why Jakarta EE Matters to Spring - and Vice Versa
ivargrimstad
0
1.1k
シールドクラスをはじめよう / Getting Started with Sealed Classes
mackey0225
4
640
最新TCAキャッチアップ
0si43
0
140
3 Effective Rules for Using Signals in Angular
manfredsteyer
PRO
0
110
LLM生成文章の精度評価自動化とプロンプトチューニングの効率化について
layerx
PRO
2
190
距離関数を極める! / SESSIONS 2024
gam0022
0
280
とにかくAWS GameDay!AWSは世界の共通言語! / Anyway, AWS GameDay! AWS is the world's lingua franca!
seike460
PRO
1
860
3 Effective Rules for Using Signals in Angular
manfredsteyer
PRO
1
100
Featured
See All Featured
Embracing the Ebb and Flow
colly
84
4.5k
Reflections from 52 weeks, 52 projects
jeffersonlam
346
20k
jQuery: Nuts, Bolts and Bling
dougneiner
61
7.5k
Fontdeck: Realign not Redesign
paulrobertlloyd
82
5.2k
How STYLIGHT went responsive
nonsquared
95
5.2k
Building Better People: How to give real-time feedback that sticks.
wjessup
364
19k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
33
1.9k
GraphQLの誤解/rethinking-graphql
sonatard
67
10k
The Cost Of JavaScript in 2023
addyosmani
45
6.7k
Adopting Sorbet at Scale
ufuk
73
9.1k
What's new in Ruby 2.0
geeforr
343
31k
Gamification - CAS2011
davidbonilla
80
5k
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