SpringOne Platform2017報告として、以下のことについて話します (QA入れて40分~ぐらいある気がする)
- カンファレンスの観光的要素: 5分
- 聞いたセッションの話: 大体後述するのに集約されるのでさっと5分
- セッションを踏まえ、主要なトピックについて、社内で(将来的に)使える感じの便利情報として: 30分
- Spring Framework 5.0 / Spring Boot 2
- reactive-streams / reactor / spring-webflux
- Micrometer
- サンフランシスコ事情
- SpringOnePlatform的な
- Pivotal カクテルセッション行ったよ
- 他
- 面白かったやつ
- What's new Spring Boot2 (後でまとめて話す)
- spring framework 5.0 on JDK 8 & 9 (後でまとめて話す)
- Project Reactor: Now & Tommorrow (後でまとめて話す)
- Spring Framework 5: Hidden Gems (後でまとめて話す)
- Observability with Micrometer Metrics (後でまとめて話す)
- 55 New Features in JDK 9 (資料まとまってるので見てね^^)
- そこまで面白くなかったやつ
- Reactor in Action (基礎)
- New in Spring Framework 5.0: Function WebFramework: RouterFunctionsの基礎
- main stage: 軽く
- PCF2.0 (社内じゃ使わん)
- Spring Boot 2.0 demo
- Boeingの人/HCSCの人/Accentureの人/Air Forceの人
- Distribution System話
- Googleの人: service mesh~
- 全体の様子
- live coding多かった
- 観客が直接声かけて助けたりしてるの良かった
- 最大10並列あって、あたりはずれ選ぶの難しい
- 大体発表時に自分 or projectのtwitter account紹介して、なんかあったら聞いてねって言ってたの良かった
- live coding多かった
- Java8+, tomcat8+, thymeleaf3, hibernate5.2
- reactive spring
- reactive stack: netty, servlet3.1, undertow, reactive streams, spring webflux
- reactive streams: reactor (Mono, Flux)
- functional apis: RouterFunctions
- kotlin support
- anigif banner
- environment variable
- MY_VAR_1_2=b => my.var[1][2] = "b"
- java.time integration
- Duration: "1s", "2m", "5d"
- bootRepackage -> bootJar/bootWar
- actuator improvements: https://spring.io/blog/2017/08/22/introducing-actuator-endpoints-in-spring-boot-2-0
- endpoint annotation: @Endpoint("example"), @WebEndpoint, @JmxEndpoint
- tech independent operations: @ReadOperation(String read()), @WriteOperation(void write(String[] args)), @DeleteOperation
- tech specific extensions: @EndpointWebExtension, @EndpointJmxExtension
- spring security improvements: 結構色々してる?
- webflux対応
- No ordering issues with WebSecurityConfigurerAdapter
- web actuator endpoints have consistent behavior
- webflux: reactor <--
- micro meter metrics <--
- spring-jcl: custom commons loggin bridge
- no custom bridges and no custom excludes in application poms
- build-time components indexer
- build時にcomponennt scan 対象を META-INFO/spring.components のファイルにまとめて、起動速度を上げる
- ListenableFuture から CompletableFuture に変換する
.completable()
の追加 - Data Class Binding: ...TODO
- Spring data binding can work with immutable classes now
- Property names matched against constructor parameter names
- explicit property names via @ConstructorProperties or simply inferred from class bytecode(-parameters or -debug)
- Perfect match: Kotlin data classes and Lombok data classes
http://www.reactive-streams.org/
ノンブロッキングな排圧制御を持つ非同期ストリーム処理の標準化
データのinterfaceのみ提供して、皆で以下のinterfaceをまもったapiを提供していこうねっていう取り決め的なsomething
org.reaactivestreams:reactive-streams には以下のinterfaceしか無い
- Pulisher: データをsubscriberに渡すやつ
- void subscribe(Subscriber<? super T> s)
- Subscriber: Publisherのデータを購読するやつ
- void onNext(T t);
- void onError(Throwable t);
- void onComplete();
- void onSubscribe(Subscription s);
- Subscription
- 1:1対応されているpub/subに対するinterface (cancelとか出来る)
- Processor<T, R> extends Subscriber, Publisher
- データの処理をして中継したりするやつ
- ノンブロッキングな処理を並行に処理出来る、ちゃんとcpu使える
- back pressure
- お互いに共通のmethodがあるので、かんたんにadapterを提供出来る
- e.g. JdkFlowAdapter: reactor -> Java Flow
for (int i = 1; i <= 1000; i++) {
handleBody(blockingHttpGet())
}
Flux.range(1, 1000)
.flatMap(i -> reactiveHttpCall())
.subscribe(this::handleBody)
- reactor: springで使われてる
- RxJava: reactive
- akka-stream: lightbend
- Java9: java.util.concurrent.Flow <- !!
- Flow.Publisher
- Flow.Subscriber
- 基本的にresponse書き込みSubscriberが用意されているので、来たリクエストに対してresponseをpublishするPublisher(e.g. Mono/Flux)を実装してあげたら良い
- e.g. ServletHttpHandlerAdapter.serviceとかにあるよ
- SSEとかFluxを使うと簡単に出来て面白いよ
(Project Reactor: Now & Tomorrow)
reactive-streamの実装の1つで、spring-webfluxで使われている
- Mono implements Publisher
- 0個か1子のデータをpublishする、特別なPublisher
- Flux implements Publisher
- 0個以上のデータをpublishする、基本的なPublisher
- refactoring
- reactor x kotlin
- Scannable
- 階層的にデータを辿れるVisitorパターンなどに利用出来るもの
- Tagging, Naming
Flux.range(1, 10).name("name").tag("foo", "bar")
- Hooks
- e.g. tagに"METRICS"って名前があるやつのメトリクスを取得するとか...
- Immutable Context
- event-drivenで処理する際に利用するimmutableなContextを内部で持つ
より詳細は: https://spring.io/blog/2017/09/28/reactor-bismuth-is-out
- reactor-netty -reactor- kafka
- reactor-rabbitmq
- reactor-addons
- retry support
- Math
- Cache (
CacheMono
/CacheFlux
)
- spring
- reactive-gRPC from salesforce
- lettuce
- reactor-scala-extensions
- より高度なエラーハンドリング
- ASIS: Flux.range(0,3).flatMap(v -> Mono.just(v).map(i -> 100 / i).doOnError(...).doErrorResume(Mono.Empty()))
- TOBE?: Flux.range(0,3).map(i -> 100 / i).errorStrategyContinue().filter(i -> 100 / i > 4);
- 監視系
- Migrometer integration
- Sleuth / Zipkin integration
- reactor-netty
- initial user guide
- http2 support
- java9
- rsocket
- asynchronous db adapter?
- "web"flux: reactive-streamの機能をserver/clientの繋ぎ込みの部分で使えるようにするやつ
- server
@GetMapping("ok")
Mono<String> ok() {
return Mono.just("ok");
}
- client
Mono<Person> bodyMono = webClient.get()
.uri("/persons/1")
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(Person.class);
Webアプリケーション側のエンジニアとして、2つの観点から必要性を考えます
- application layer で non-blocing を使う必要性
- server で non-blocking(async) を使う必要性
正直な所、これは大凡便利
- POS
- 並列に投げたいとこが出たら簡単に並列に処理出来る
- コード綺麗になる
- back pressure
- NEG
- 学習コスト少し (基本的にblockしてはならないなど)
これは必要に応じて
request threadで大量のリクエストを裁こうとするとコストが高いので、きちんとendpointに対して一貫してnon-blockingな処理が出来てるなら、きちんとcpu使い切れるようになります
https://engineering.linecorp.com/ja/blog/detail/213 も読んでね
- JDBCはblockする処理だけどどうするの?
- AsyncJDBCを待つ
- 専用のThreadPool用意する
- blockしてる箇所とかどうやって調べるの?
- flight recorderが便利らしいよ
- thread専有してる箇所とか探せば良い
良く言われてるのはこれ
@GetMapping("ok")
Mono<String> ok() {
return Mono.just("ok");
}
実はこれでもいい (Mono/Flux implements Publisher)
@GetMapping("ok")
Publisher<String> ok() {
return Mono.just("ok");
}
これも動く(が、どこかにblockingな処理がありえるので注意)
@GetMapping("ok")
String ok() {
return "ok";
}
-
これらの変換をしているのは AbstractMessageWriterResultHandler.writeBody
- Stringは Mono.justOrEmpty で包まれる
- Mono/Publisher/CompletableFuture/... などは、ReactiveAdapterRegistry で変換される
-
ReactiveAdapterRegistry?
-
nettyしか使えないの?
- servletのasync supportを有効にして、 org.springframework.http.server.reactive.TomcatHttpHandlerAdapter/JettyHttpHandlerAdapter とか使えるよ
Observability with Microemter Metrics
- Think SLF4J, but for metrics
- メトリクスを収集して、色々な所へ飛ばせるfacade的なもの
- JMX, Prometheus, InfluxDB, Graphite, Datadog, ...
- IMON?
- springへの依存は無いので、どこでも使える e.g. armeria
- タグがある
- name + tag により、それらの概念を利用してるデータリポジトリとの統合が簡単に
- spring-boot2 Micrometer is autoconfigurered by Actuator
dependencies {
compile 'org.springframework.boot:spring-boot-starter-actuator'
// pick any number of backing stores
runtime 'io.micrometer:micrometer-registry-prometheus'
runtime 'io.micrometer:micrometer-registry-jmx'
}
- boot1
dependencies {
compile 'org.springframework.boot:spring-boot-starter-actuator'
runtime 'io.micrometer:microemter-spring-legacy:1.0.0-rc.4'
// pick any number of backing stores
runtime 'io.micrometer:micrometer-registry-prometheus:1.0.0-rc.4'
runtime 'io.micrometer:micrometer-registry-jmx:1.0.0-rc.4'
}
- Counter / Timer / Gauge
CompositeMeterRegistry registry = new CompositeMeterRegistry();
regitstry.add(SampleRegistries.jmx()); // jmx に metrics を吐く
regitstry.add(SampleRegistries.prometheus()) // prometheus用のhttp serverが立つ
// registryから作るapi
Counter counter = registry.counter(name, ...tags);
// builder的に作るapi
Counter counter = Counter.builder(name).tag(...).baseUnit().registry(registry);
// Counterはデータを inc/dec させるもの
counter.increment();
任意のobjectのstateから値を取得する事が出来る
AtomicInteger n = new AtomicInteger(); // state
FunctionCounter.builder(name, n, AtomicInteger::get).register(registry);
- spring-boot2の場合はactuatorのautoconfigurationがあるので、設定で色々変えれるよ
spring.metrics.filter.my.timer:
percentilesHistogram: true // default false
sla: 100ms
- とあるmethodにかかる時間を測定したい
@Timed(percentiles = {0.5, 0.95, 0.999}, histgram = true)
@GetMapping(...)
public Mono<String> ok() {
// ...
}
- jvmの基本的なメトリクス取るものはそのままついてくるよ
- logback/tomcat/jetty/...などなどへのintegrationも本家にあるよ
- documentちゃんとあるので、一通り読むともっと学べます