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.5k
KubernetesのマニフェストをそれなりにCIしたい
stormcat24
4
1.2k
令和時代のSaaS開発
stormcat24
1
240
History in 5 years of CircleCI and CyberAgent
stormcat24
3
800
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
Kotlinの好きなところ
kobaken0029
0
220
Piniaの現状と今後
waka292
5
1.4k
WEBエンジニア向けAI活用入門
sutetotanuki
0
290
/←このスケジュール表に立ち向かう フロントエンド開発戦略 / A front-end development strategy to tackle a single-slash schedule.
nrslib
1
580
カスタムしながら理解するGraphQL Connection
yanagii
0
680
Prompt Engineering for Developers @ AWS Community Day Adria 2024
slobodan
0
120
Tuning GraphQL on Rails
pyama86
2
780
Jakarta Concurrencyによる並行処理プログラミングの始め方 (JJUG CCC 2024 Fall)
tnagao7
0
200
Vue3の一歩踏み込んだパフォーマンスチューニング2024
hal_spidernight
3
2.9k
OpenTelemetryでRailsのパフォーマンス分析を始めてみよう(KoR2024)
ymtdzzz
3
1k
Generative AI Use Cases JP (略称:GenU)奮闘記
hideg
0
120
watsonx.ai Dojo #3 プロンプトエンジニアリング入門
oniak3ibm
PRO
0
490
Featured
See All Featured
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
504
140k
Large-scale JavaScript Application Architecture
addyosmani
510
110k
A Modern Web Designer's Workflow
chriscoyier
692
190k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
231
17k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
225
22k
We Have a Design System, Now What?
morganepeng
50
7.2k
The Language of Interfaces
destraynor
154
24k
How To Stay Up To Date on Web Technology
chriscoyier
788
250k
Unsuck your backbone
ammeep
668
57k
Imperfection Machines: The Place of Print at Facebook
scottboms
264
13k
Art, The Web, and Tiny UX
lynnandtonic
296
20k
The Cult of Friendly URLs
andyhume
78
6k
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