Spring Fest 2017 Fallに参加してきた

弊社がいいよって言ってくれたので、弊社Springframework率ゼロに等しいのに平日に1日使って仕事としてSpring Fest 2017 Fallに参加してきた。弊社ありがとう。

聞いてきた話を感想や学びと一緒にまとめておく。

NOTE : 間違いのないように気をつけてはいますが、誤解している箇所があればぜひ後学のためにご指摘ください。

普段Javaを触らない各位のために

ちょっとだけ解説すると、SpringframeworkはJava製のアプリケーションフレームワーク。 数年前まではいくつかのフレームワークがあったが、現在は一強になりつつあるように思う。 オブジェクトをDIで組み合わせて巨大なアプリケーションを構築できるのが特徴。

リクルートホールディングスYahoo!Japanなどのメガ企業にはじまり、様々な企業が採用している。私が浅学なだけで山ほど採用企業はある。

基調講演: What's new in Spring?

Pivotalの強い人で、Springframeworkファミリーの様々なプロダクトの開発に関わってきたDave Syer氏による基調講演。 穏やかな話し方をする方だった。イケるやろと思って同時通訳なしでチャレンジしてみたら半分くらいしかわからなかった。

スライドは以下。

What’s New in Spring?

PivotalはSpringframeworkのメンテナ企業。Pivotal Cloud FoundryというクラウドプラットフォームやConcourse CIも開発している。

Springプロダクトのレイヤーについての概要

Springframeworkの各プロダクトは、大きく分けて3階層で構成されている。 生SpringframeworkとSpring Boot、そしてSpring Cloudである。

Spring Bootを使うと生Springframeworkで辛かった設定の管理が簡単になって、Spring Cloudができたことで分散アプリケーションを開発できるようになった。

直近のアップデート内容

2017/11にかなりいろいろアップデートがあった。 Framework自体5.x系に上がったし、Securityも5.0.0.RC1に。Bootは2.0.0に。 Project Reactorというのもあって、WebsocketサポートとかReactiveなアプリケーション開発の基盤を提供している。

Spring 5.0ができること

以下のような変更を行っている。

  • パフォーマンス改善
  • Functional bean configuration(設定をもっと簡単に書ける)
  • ReactiveにWebFluxとRouter Functionsを追加(イベントループ型の処理を可能にする)
  • JUnit5サポート(最新のテストライブラリに対応)
  • JDK9サポート(最新のJavaに対応)
  • HTTP2サポート
  • Kotlinサポート

Project Reactorについて

今までは、IOExceptionを起こしうる操作はtry-catchしなければいけなくて、Imperative(命令的)でBlockingだった。 でもFunctionalスタイルだと、Mono型を返してdoOnErrorでエラー処理できるのでNon-blocking。

Javaではもともと、1つのHTTPリクエストに対して1スレッドを起動するモデルでWebアプリケーションを開発する必要があって、つまり大量のリクエストを一度に受け付けるとスレッドが枯渇してしまう問題があった。 それに対する解決策としてSpring 5.0で提供されたのがFunctional Routerで、これでNode.jsに代表されるイベントループの仕組みをSpringframeworkが実現できるようになる。

Controller層もReactiveに書けるようになった!ControllerからMono型を返せる。 ただしWebFluxを使うと組み込みサーバーがNettyになる。TomcatはNon-blockingをサポートしないので。

新しいAPIクライアント

WebClientを使うと、APIアクセスする時にWebClient.create()してそのまま使える。 書き方はBuilderパターンみたいになっていて、client.get()...とメソッドチェーンをつなげていって、結果Reactiveなオブジェクトを取得できたりする。 テスト用のモックオブジェクトなども用意されていてテスタブル。

ServletとWeb MVCはなくならない。

Cloud

Spring Cloud Function / Spring Cloud Gatewayが2018Q1、SpringBoot2.0.Xに計画されている。 FaaSをSpringで書けたり、API GatewayをSpringで書けたりするようになるらしい。これまた楽しそうなテーマ...!

所感

最近さらに、どの言語でやるかではなく何をするかに集中できるようになってきた気がする。 JavaでもRailsでもそれ以外でも、ノンブロッキングIOが使いたくて使えるならそれでいいし、dev.toみたいに適切にCDNを噛ませれば早くなる。

Functional Routerは書き方の問題じゃないか?なんでフィーチャーされてるんだ?と思ってたので、Dave Syer氏に質問してきた。 いわく、「Function」Routerとはいうけど実際にはFunctionalであることよりもリソースの削減ができるのが良い。これがない時代には、何百ものクライアントからの接続をさばく時山ほどスレッドプールを用意して処理が終わるまでスレッドプールを開放できなかった。でもFunctional RouterやMonoを返すようなControllerを書けばスレッドプールのリソースを削減できる。だから、たしかにFunctionalなのはtaste(好み)の問題だけど、良いことはある。

Introduction to Spring WebFlux

Pivotalの中の人になったmakingさん。

スライドは一度公開されたのだが現在非公開設定の模様。 アウトラインはgistにあがっている。

まずWebFluxを使ったデモアプリケーションのお披露目があった。

github.com

このデモアプリケーションはIoTデバイスからの通信を受け取ってリアルタイムにさばくアプリケーションで、このセッションを聞くために集まった聴衆からの80ほどのリクエストをさばいていた。 Tomcatは1リクエスト1スレッド消費するので、普通に書くとリクエストの数だけスレッドを消費するはずだが、このアプリはWebFluxというReactive Programmingの基盤を使っているので、5-10スレッドでさばける。なんだそれすごい!!!

Springに追加されたReactive StackはNon-Blockingを扱う。

今までのServlet Stackは1リクエストごとに1スレッドを生成するが、Reactive Stackはイベントループを使って処理を行うので、少ないスレッド数で処理を行える。具体的には、Tomcatがデフォルトで200のスレッドプールまで対応するのに比べてWebFluxはデフォルトでCPU数と同じ数だけのスレッドを使いまわしてスレッド数の10倍の数のリクエストを捌く。

Reactive Stream自体はJava API仕様で、SubscriberとPublisherが存在する。 Java9 APIでもRxJavaでもSpring ReactorでもAkka Streamsでも使える。 Flux(0..n件用)とMono(0..1件用)というインターフェースが重要。

Publisher側は情報を流す量を調整できて、1秒ごとに情報を流す、みたいなことができる。

Spring MVCとSpring WebFluxの違い

全く同じコードベースでも動くがそのままだと同期的なコードのままになるので、Mono.fromCallableとかを使ってMono型やFlux型を返す。 Spring MVC上でMonoを使うこともできる。が、非同期処理専用スレッドを立ててそいつを同期的に動かすことになる。(?)

無限ストリーム

content-typeをstreamに指定すると、無限ストリームを受け取ることができる。 使えるのは以下 - text/event-stream - application/stream+json - application/json

BackPressureを調整できるcontent-typeは上の2つだけ。これが効いてるとサーバー側でよしなにBackPressureを調整してくれるので、サーバーが圧倒されることがなくなる。(?)

POSTする時にRequest BodyをFluxでもらうこともできて、これをやるとリクエストが終わる前にレスポンスが返りはじめる。 Transfer-encoding: chunkedにするとじわじわとHTTPリクエストを送ることができる。

Streamをshare()すると、Streamがブロードキャストされて接続してきた人全員に同じストリームを配信できる。

Blockingなコードを使う時は気をつけて

Reactive StuckでBlockingなコードを書かなきゃいけない時は、あっさりCPUコア数分のリソースを食いつぶす。

Spring Data Kay

Reactiveサポートが入った。RedisとかのNoSQLとの通信でReactiveなインターフェースを扱えるようになった。 Repositoryのインターフェースが変わったので、バージョンをあげるとそのままでは動かないかも。気をつけて。

JDBCはReactorと一緒に使うとブロッキングになる。 具体的にはJDBC自体がブロッキングなI/Oしか提供しないので、イベントループ型のControllerなどを書いても結局JDBCアクセスで詰まってしまう。 すると、CPUコア数しかスレッドがないのでパフォーマンスが落ちる。 次のJavaでは非同期JDBCが入るはずなので、それを待つ方が良い。

だから、RDBMSにつなぐアプリケーションはWebFluxじゃない方が良い。

また、Spring SecurityもReactive用の設定がある。 ThymeleafでもReactiveモードがあって、chunked modeをサポートしてる。

これからWebFluxを使いたい時は、 FrontendにWebFlux、BackendのRDBがある時はSpring MVCで作ると良い。 BackendもWebFluxを取り入れたい時はNoSQLが必須。

Spring Cloud GatewayAPI GatewayをSpringで作れるようになる。

所感

Reactiveに胸躍った。 Javaレベルが足りなくてスレッドを生成するコストとか保持するコストのイメージが沸かない。 でもAndroidでUIスレッドとBackendスレッドを使いわけるコードを書いたおかげで、ちょっとは分かる。

Yahoo! JAPANのコンテンツ・プラットフォームを支えるSpring Cloud Streamによるマイクロサービスアーキテクチャ

コンテンツプラットフォームというYJ内部の基盤開発の話。 スライドは以下。

www.slideshare.net

コンテンツとは

天気、スポーツの試合情報、ニュースなど...。

コンテンツプラットフォームとは

個人・企業などの配信者から入稿されたコンテンツを管理する基盤。 リプレイス前はC+Perlの巨大なアプリケーションでテスト不可能・リファクタ不可能。

リプレイスの設計

処理自体は文字列の処理が中心なのでPaaSに行けるはず。 スパイクアクセスに耐えられるよう柔軟にしたい。 MQで非同期に処理を流したい。 データストアはCassandra。YJ!っぽい。 入稿受付サービス、入稿処理サービス(形態素解析、ジャンル判定など)、入稿通知サービスなど20ほどのサービスが連携してPivotal Cloud Foundryで動いている。 (ここらへんの仕組みが必要な点は、弊社にも共通する。本筋と少し違うけど、入稿するデータごとの違いはどうモデリングしてるんだろう。) 非同期部分はSpring Cloud StreamとApache Pulsar。 Apache PulsarはYahoo.Inc製のMQ。

Spring Cloud Stream

Source Processor Sinkの概念がある。 Brokerが必要。 テストツールでBrokerをモック化してテストできる。

つくってみて得た知見

処理のどこでエラーが発生したのか、関連するどのサービスが原因なのかわからない。 これを解決するために、Spring Cloud Sleuthを使ってリクエストごとに一意のIDを振る。 これにさらにZipkinを組み合わせてIDを可視化することができる。

所感

弊社も規模は比較にならないくらい小さいといえど、入稿 -> 配信の流れは同じ。 同じようにキューを挟んでマイクロサービス化するのはアリだと思う。

ドメイン駆動設計のためのSpringの上手な使い方

現場で役立つシステム設計の原則」の著者、Guildworksの増田さんによるセッション。 博士みたいな風貌のおじいちゃん。

スライドは以下。

www.slideshare.net

DDDの魅力

サックと作ってリリースして終わり、であればいらない。 長く保守し続けること,価値を生み続けることが真意である。

DDDの基本活動

開発者がドメインを学ぶ

学んだことを"コード"として書けることこそ技術者 「継続的に学習する」 深い洞察に進む、姿勢

学んだことをコードで表現する

技術者たるものドメインの知識をコードで表現できる、説明できること

モデルと実装(の構造)を一致させる

  • モデルと実装を関連付けることで、実装が整理され見通しが良くなる 実装からfeedbackすることで、モデルが実用的になる
テクニック
  • ドメインの記述を 技術の関心事から独立させる isolating-the-domain
  • 概念の単位とプログラミングの単位を一致させる
    • モジュール化
    • 型(class interface enum)で知識を表現する
    • 基本データ型ではなく、ユーザ定義型で表現する
  • 最初からピッタリの方は見つからない
    • [実験 feedback 設計]の改善を繰り返す

深いモデルを探求する

  • 正直言って... ここの議論はされていない。 (エバンス本の9-13章だったかな...?)
  • 成果を最大化するために必要な作業だ

  • 中核の複雑さ/機会に焦点を合わせる "中核"を探す作業こそが "モデルの探求作業"

  • 役に立つ型を見つけるための実験を繰り返す
    • 暗黙の概念を明示的に表現する
      • 制約 (BeanValidation, Policy)
      • プロセス (業務の流れ/手順)
      • 区分の分析 「12の区分を分析したときに、3種類の状態の組み合わせだったなど」 -> 暗黙の知識を宣言的に表現できると if文がどんどん減っていく!!

巨大な複雑さに立ち向かう

  • 戦略的に取り組む
    • 時間がかかる
    • 地道な努力の積み重ねのエネルギー
  • 巨大な複雑さに立ち向かうためのスキル (14-16章) 巨大になればなるほど如何にシンプルな構造を見つけるか 「コードとしてどう表現するか?」
    • 俯瞰
    • 蒸留
    • 大きな構造化

SpringとDDD

Springのprograming-model

Springはアプリケーションの「基盤」を提供する 開発者はドメイン固有のロジックに集中する ドメイン駆動設計の考え方そのもの -> SpringはDDDを実践するためのフレームワーク (@Service, @RepositoryはDDD本からでてきているのだ)

Springを使えばDDDになる?

MVCのモデル(@Controller/@Service/@Repository)をやっているだけでは(サービス層にスクリプトをゴリゴリ書くだけでは)得られない -> この3層からドメインを抽出することで初めて効果が得られる

DDDのためのSpringの使い方

spring-boot-starter-*
  • 初日から...
    • 動くアプリケーションで考える
    • 学んだことをコードで記録する
    • コードでモデルを表現する
    • End to Endで実験してみる
spring integration

「巨大な複雑さに立ち向かう」 - 境界づけられたコンテキスト (Bounded Context) = gitリポジトリ単位 - コンテキストマップ - EIPの実装技術 分析・設計・実装するための枠組み - Messaging Model

spring batch
  • 今でも多くの業務を裏で支えている
  • ドメインの理解度の違いが現れる場所
    • job/step etc.

まとめ(DDDを現場で取り組むためのヒント)

日本一やさしく説明する予定のマイクロサービス入門

JSUG会長長谷川さんのセッション。 スライドは以下。

www.slideshare.net

メッセージングでコラボレーションを行いつつ全体で1つの仕事をする、自立分散協調のアーキテクチャオブジェクト指向をシステムレベルに適用した、と考えることができる。 マイクロサービスにはチームや会社のチームワークが必要だよ。でもそれもオブジェクト指向からの拡張と考えれば同じ。

オブジェクト指向が騒がれた当初、小さすぎるクラスや神クラスを作ってしまって今笑い話になるように、マイクロサービスに関してもそうなると思う。 今は大きすぎたり小さすぎるマイクロサービスを作ってしまうことがあると思うけど、正解は一つじゃない。

複雑なものは新しい技術で簡単にはならない!!! 今すごく複雑な業務プロセスを、マイクロサービスで簡単にするんだ!みたいなのは通用しない。 また新しい複雑なものができるだけ。

本当に簡単にしたければ、やり方を変えるしかない。業務プロセスを変えるとかね。

データモデルがぐちゃぐちゃだと、マイクロサービス化をそもそもできない場合がある。 Mybatis便利だよね、と言っている時点でなにかおかしくて、やばいSQLが書いてあるのでは?

最初から最高を目指さずに、切り出せるところから切り出していった方がいい。

マイクロサービスが増えると、「誰も知らないサービス」が出てきそう。100とか200のマイクロサービスを作ったとして、全体の仕様を管理できない、復元もできないみたいなことになる。 開発チームがバラバラ、RDB製品もバラバラでは、今後それをマネジメントする人がいなくなったらどうするのか? 全部SpringBoot x Javaで揃えた方が良いのでは? あるいは本当に必要なところだけ、その特性を活かしてNodeなりRubyなりつかえばよいと思う。

所感

最近あんまりマイクロサービスについての議論を追っていなかったけど、納得感のある話。 今はまだ提唱されてからの時間が短すぎて、今後どうなるかわからない。 でも今時点で試す価値は十分にある。要点を間違えなければ。

The Road to Serverless: Spring Cloud Function

Cloud abstractionについて話す。 Spring Cloud Functionについて話す。 Raising the value lineについて話す。

スライドは以下。

The Road to Serverless: Spring Cloud Function

Cloud Abstraction

VMから始まってコンテナ、アプリケーション、Functionの順に抽象度を増していく。

Serverlessはイベント・ドリブン、動的リソース最適化、メッセージに対して課金され、プロダクションコードを極めて高速に開発できる。 ビジネスロジックに集中できる。

Google Cloud Functionはなかなか良いよ。 WebUIで試せるよ。もちろんちゃんとやるならこれじゃダメだけど。CIが必要だし自動化が必要。

JavaのFunction APIを試せるよ。

Spring Boot Thin Launcherってのがあるよ。

SpringでOAuth 2.0 / OpenID Connect 1.0を使う

インスタンスを初めて目視確認したうらがみさんのセッション。

SpringでOAuth 2.0・OpenID Connect 1.0を使う

OAuth 2.0は仕様の日本語訳があるから見てみてね。 もちろんリソースオーナーもそれを利用する側もSpringで作れる。

cloud-oauth2を依存に追加する。 @EnableAuthorizationServerアノテーションで、それ用のエンドポイントとかが作られる。

アノテーションとapplication.propertiesの設定でSpring Securityを使ってOAuth2による認可を使ったログインが可能になる。

OIDCのくわしい仕様とかは話さない。

所感

OIDCまわりが全然前提知識として足りず、ついていけなかったので勉強する。 TwitterのOAuthログインも、専用ライブラリに頼らないでもここらへんを使うと作れるのかな。 要はユーザーの名前とかアイコン画像、メールアドレスを取得できればいいわけだしね。

まとめ

Springframeworkは今、特にクラウドネイティブ・非同期処理・マイクロサービスまわりのエコシステムが整ってきていると感じた。 NetflixやPivotalのような企業がJavaやSpringframeworkの周辺ツールを提供してくれているおかげでこのような環境が整ってきた。

たしかにマイクロサービスをやろうと思ってエコシステムから作るはしんどい。 すると、アプリケーション開発言語はエコシステムがどの程度整っているかで選ぶのも筋が悪くはないのでは?と思う。 PHPにはPHPに得意な、RailsにはRailsに得意な、SpringにはSpringに得意な領域がある。 そして現状Springのそれは、マイクロサービス開発に関わる部分のようだ。