Java Day Tokyo 2015 メモ

(Qiita:Teamにあげそこなったので)

基調講演

Java EE

ゴールドマン・サックス

  • テクノロジー部
  • 自分たちで作る、決済システムとか
  • 2000年ごろからやってるらし、JCP Executive Committeeだったりする
  • 世界でJavaエンジニア3000人 テクノロジー部は15%
  • ヒープ190Gとかコードキャッシュが限界超えるとか
  • OpenJDK
    • ソース、チューニング、セキュリティのため
    • トラブルシューティング、リサーチ
      • JVMTI
      • 圧縮OOP
  • GS Collections

Nashorn

  • ナスホーンまたはナズホーン
  • Rhinoのおきかえ
  • ECMAScript5.1
  • 相互呼び出し可
  • jjsコマンド
  • functionオブジェクト渡してlambda expression

  • 8u20

    • セキュリティ強化
    • JIT/JDK強化
    • const as var (v8向けのコード対応)
    • no-java
    • no-syntax-extentions (-scripting時はfalse)
    • sourceUrl対応
    • クラスキャッシュ対応 => evalを逐次行うのに比べて高速化
  • 8u40

    • コンパイル時の楽観的型推論
    • --optimistic-types
    • 間違ってたらフォールバック
    • コードキャッシュ
    • 型推論結果のキャッシュ
    • Nashorn class filter
    • 任意クラスを参照不可にする
    • ECMAScript6

      • const
      • let (lexical scope)
    • Server Side Scripting

    • avatorはclose
    • ウォームアップ改善
    • parser api jdk9 ea b55から使える
      • AST出すデモ
      • flight recorder

エンタープライズアーキテクチャ

  • システムのわけかたと組み合わせ方
  • 空間的、時間的バランス
  • 利害関係者の関心、将来の変化
  • システムの構造とプロセスの決定
  • 要素への分解と組立の方法
  • さらにリソースとスケジュールを入れるとWBS
  • エンタープライズ
  • 利害が多い、連携が多く複雑、へんかしづらい、現状とルールが大切
  • プロジェクトマネージメントに先立つ構造とプロセス
  • 全てfixするのではなく、選択肢を残す決定も

選択 - バランスをとる - ITサービス運営、品質、技術トレンド - ITサービス運営=webっぽい、運用 - リーンスタートアップとか言われた - 満足を得るための持続的な改善、UXっぽい話 - この運営モデル分かりやすい - 継続的な活動を前提とした効率性 - 利用されて評価される

品質 - 多面的、バランスを - 経産省の品質メトリクスセット

  • 性能特性、キャパプラはスモールスタートでフィッティングさせてく
  • 互換性、コネクティビティ、一般的な仕組みを使うこと
  • 共有化、プラットフォーム化
  • プラットフォーム、レイヤー化
  • saas, paas, iaas, ミドルウェアスタック=baas

  • 固有化、マイクロサービス

    • サービスが独立した構造とプロセスを持ち、APIで連携
    • それぞれ独自のライフサイクルを持ち、個別のドメインに従う
    • OSレイヤの上にプラットフォーム管理レイヤを。
    • ミドルウェアスタック以降はデプロイメントに従って構築される。dockerとか。
    • マイクロサービスによる個別の構造とプロセスを企業の中で許容できるか。

実践 - ECサイト, フロントの購買システムはアジャイルに、受注管理はウォーターフォールで、などのドメイン分割 - 完璧な選択はできない、観点を持って考え、利害関係者で合意を

覚悟 - 正解がないからこその覚悟 - 最小公倍数じゃなくては最大公約数 - 全員の意見を合わせるんじゃなくて、全員の我慢を得る - 意見に基づいてアーキテクトが覚悟を持って判断 - 銀の弾丸はないが、そうだと思ったら撃ち抜く、銀色にする覚悟を - 妥協はできないが諦めを。判断できないならもっと考える。あきらめたらきちんと未来へ託す。 - アーキテクチャはチームで考える

HotSpot

fluentdを導入しました&webサーバー上のagentが結構メモリを消費するよ

そこそこのトラフィックのあるWebサーバー上で、アプリケーションから出力されるいくつかのログファイルを収集するためにFluentdを導入しました。

セットアップはこんな感じ。

fluentdのバージョンは0.10.15, rvmが1.10.3, rubyが1.9.3p125 です。

Webサーバーは20台で、一番多いサーバーで800万req/dayくらいの規模です。
各Webサーバー上ではin_tailで3つのファイルをtailし、out_roundrobin & out_forwardで計4台の集計用サーバーに流して、そこでレコメンデーションやKPIの集計を行っています。

Webサーバー上のagentとして動くFluentdの設定ファイルはこんな感じ。

この3つのファイルは、それぞれdailyでローテートされてて、1日当たり 460万行、640万行、370万行くらいです。

起動は以下のスクリプトで行っていて、今のところ定期的な再起動はなし。運用開始から2週間ほどたってて、設定変更のために何回か手動で再起動をしています。

最長1週間ほど起動しっぱなしでしたが、その時点で1G程メモリを使ってました。

改めてFluentdプロセスのRSSをグラフ化してみるとこんな感じ。(再起動から2日たってますが、値を取り始めたばっかなのでまだちょっとわかりません)

なおVSZは起動当初260Mくらいから、2日で1.1Gくらいになってます。

現状こんなところです。

なお、動き自体は一点を除いて(だれかマージして!)うまくいっていて、PV/UU/処理時間などを詳細かつリアルタイムに視覚化できていたり、ユーザーの行動データをもとにしたレコメンデーションをほぼリアルタイムに実現できています。とってもハッピー!

      • -

※ 3/30 追記

メモリ使用量ですが、1日たって以下のようになりました。朝4時でログファイルのローテートが発生してるんですが、そのタイミングでスカッと落ちました。(また上がってますが)

ついでに、Webサーバーからforwardされたログを受け取って処理している側のfluentdのメモリ状況は以下の通り低い数字で安定していますし、トラフィックに応じて上下しています。

Jetty6と7をJava6と7でパフォーマンス実験してみました

rpscala第45回で黙々とパフォーマンス実験をしてきました。
Scala勉強会第45回 in 秋葉原 : ATND
勉強会第45回 - Scala勉強会 in 東京

内容

Jetty6とJetty7のパフォーマンス実験です。
Java6とJava7をそれぞれ組み合わせて、単純なアプリケーションのスループットを測りました。

なんでこれをScala勉強会でやってるのか、というと、動かしているアプリケーションがScalatraだからです。
要するに、ScalaのWebアプリケーションを載っけるのに、Jetty6と7、どっちが速いのか+Java7だったらどうなのか、という実験です。

結果

  • Jetty7 + Java6が最速でした。

というわけで、ScalaのWebアプリならJetty7をJava6で使うと速いです。Jetty側でいろいろと最適化されているものと思われます。

なお、Jetty6ではJava6よりもJava7のほうが多少速かったので、Java7が遅いという訳ではないようです。
※ 限られた実験結果です。業務で使う人はもっとちゃんと実験しましょう。

環境

EC2のlargeインスタンス1でJettyを動かし、もう1つのlargeインスタンスから負荷をかける構成。
OSはAmazon Linux 64bit
コンポーネントのバージョンは以下のとおり。

  • Jetty7 7.4.5
  • Jetty6 6.1.26
  • JDK7 GA
  • JDK6 1.6.0 u26
動かしたアプリケーション

このmaven archetypeで作ったサンプルアプリケーション(HelloWorld)
Srirangan/simple-scalatra-archetype · GitHub


ScalaとScalatraのバージョンを以下のとおり変えたものです。

  • Scala 2.8.1 => 2.9.0-1
  • Scalatra 2.0.0M3 => 2.0.0M4

mvn packageでビルドしたwarをjettyのwebappディレクトリにデプロイして動かしました。

Jettyの設定

Jetty7の設定に合わせて、Jetty6のNIOコネクタのlowResourcesConnectionsを5000から20000に変更してあります。
その他の値はデフォルトの状態です。

測定方法

  1. Jetty起動
  2. ab -n 10000 -c 100 を5回(ならし)
  3. ab -n 10000 -c 100 を5回(計測して平均request/secを取る)

数字

数値はrequest/secです。

構成 スループット
Jetty6 - Java6 2811
Jetty6 - Java7 3104
Jetty7 - Java6 4730
Jetty7 - Java7 4329

おまけ

Tomcatも測ってみました。
結果、Tomcat7はNIOコネクタに変えると遅いんですが、標準のブロッキングIOのコネクタが速かったです。Jettyよりも。

構成 スループット
Tomcat7.0.19 - Java6 5361
Tomcat7.0.19 - Java7 5198
Tomcat7.0.19 NIO - Java6 3618
Tomcat7.0.19 NIO - Java7 3452
Tomcat6.0.32 - Java6 4212
Tomcat6.0.32 - Java7 4370
Tomcat6.0.32 NIO - Java6 4578
Tomcat6.0.32 NIO - Java7 4211

なお、あくまでデフォルトの設定で、かつこの環境で速かっただけなので、必ずしも常にTomcat7がJetty7より速いわけではないです。
また機会があったら、もっと突っ込んで調べようと思います。

Scala用DBアクセスライブラリ Querulous の使い方

(この記事は Scala Advent Calendar jp 2010 の1日目です。)


Scala用のScalaで書かれたDBアクセスのためのライブラリ、querulousについて書きます。

とりあえず読み方がよくわかりませんが、クゥエルァラス??みたいな感じです。すごく言いにくいので「クエララス」ってことにしましょう。英語の形容詞で、意味は「不平たらたらの、不平をブツブツ言う」らしいです。ヒドイ名前ですね。

querulousは以前紹介したKestrelと同様、Twitterで作られて使われているものです。もう辞めちゃったらしいですが、元 TwitterのNick Kallen氏が作ったそうです。今はGithub上でtwitterというIDの中で管理されています。

(12/8 追記 Nick Kallen氏はまだ辞めてませんでした。すみません、Alex Payne氏と勘違い。kzys さん指摘ありがとうございます)


twitter/querulous · GitHub


機能と特長をreadmeから抜粋すると

  • JDBCのめんどくさいことをいい感じにやっちゃうよ。
  • タイムアウトとか死活検知とかリトライとか、障害耐性も考えてるよ。
  • 統計情報とかいろんなデバッグログとか出すから便利だよ。
  • コードとか規約とか依存関係とか最小限で、SQLチューニングの邪魔はしないよ。
  • モジュール化されててカスタマイズもOKさ。

という感じらしいです。
「最小限」ってのは、例えばJNDIは使えなかったり、MySQLしかサポートしてなかったりです。
依存関係が最小限ってとこは納得しかねるんですが、Liftみたいなヘビーなものから比べれば少ないと思います。依存するのは以下のライブラリ群です。

  • configgy (設定とロギングのためのライブラリ)
  • xrayspecs (Specsの拡張ライブラリ、以下の3つと合わせてテスト用。この中の時間計測関連のクラス・関数がヘビーに使われてて、インターフェイスにも出てきます)
  • mysql-connector-java !! (潔くMySQLオンリーです)
  • commons-dbcp&commons-pool (ここも潔いですね)
  • objenesis (リフレクション用のライブラリ)
  • cglib&asm (バイトコードを実行時にゴニョゴニョするやつ)


これまたreadmeから、実装についての説明を抜粋すると

  • QuerulousはQueryEvaluators, Queries, Databasesの3つのコンポーネントがメイン。
    • QueryEvaluatorsはクエリ実行のためのインターフェイス
    • Queriesは SELECT/UPDATE/INSERT/DELETE クエリを抽象化したもの。直接Queriesを操作することはあんまりない。
    • DatabasesはDB接続の管理を行うもの。
  • この3つはそれぞれのFactoryがインターフェイスとして書かれてて、実装はdecorator-patternで重ねて使う。
val queryFactory = new DebuggingQueryFactory(new TimingOutQueryFactory(new SqlQueryFactory))
val query = queryFactory(...) // this query will have debugging information and timeouts!

(これはScalaなんだからtraitをwithで重ねればいいのに、と思うけど、そうはできないのかな・・・わからない)

使ってみる

使ってみましょう。querulousのjarは maven.twttr.com で公開されていて、sbtやmavenから参照することができるようになってます。
それぞれの設定は以下のとおりです。

sbtの設定

プロジェクトファイルに以下のようにリポジトリとライブラリへの参照を書けばOKです。以下はScala 2.8系の場合の設定です。2.7系の場合はquerulous_2.8.0のところをquerulous_2.7.7にしてください。なお、querulous_2.8.1はリポジトリに存在しないので、2.8.1で使う場合はquerulous_2.8.0を使いましょう。

import sbt._

class QuerulousSampleProject(info: ProjectInfo) extends DefaultProject(info) {
  val twitterRepos = "Twitter Maven Repository" at "http://maven.twttr.com"
  val querulous = "com.twitter" % "querulous_2.8.0" % "1.4.3"
}
Mavenの設定

Mavenの場合はpom.xmlに以下のとおりにrepositoryとdependencyの設定を書けばOKです。MavenとIvyの場合の説明は、readmeにも書いてありますが、readmeの説明はバージョン表記やartifactIdが古いものになっているので注意してください。以下の記述は上記のsbtの場合と同様Scala 2.8系向けです。2.7系の場合はquerulous_2.8.0のところをquerulous_2.7.7にしてください。

<repository>
  <id>twitter.com</id>
  <url>http://maven.twttr.com/</url>
</repository>

<dependency>
    <groupId>com.twitter</groupId>
    <artifactId>querulous_2.8.0</artifactId>
    <version>1.4.3</version>
</dependency>
QueryEvaluatorの取得

querulousでは、データベースにアクセスするために、まずQueryEvaluatorFactoryを作ります。前述の通り、decolator-patternになっていて、以下のようなコードで作成できます。(commons-dbcpを使ってコネクションプールを作る例です)

import com.twitter.xrayspecs.TimeConversions._
import com.twitter.querulous.evaluator._
import com.twitter.querulous.query._
import com.twitter.querulous.database._

object Database {
  val factory = new StandardQueryEvaluatorFactory(
      new ApachePoolingDatabaseFactory(
        minConns    = 2,
        maxConns    = 200,
        checkIdle   = 0 seconds,
        maxWait     = 200 millis,
        checkHealth = false,
        evictTime   = 30 minutes
      ), new SqlQueryFactory)
  // secondsとかmillisはcom.twitter.xrayspecs.TimeConversionsで定義されています
}

続いて、ここで作成したQueryEvaluatorFactoryのapplyメソッドを使用して、QueryEvaluatorを作成します。

(12/8 追記 パラメータdbhostsに渡すのは、List[String]です。そのままMySQLJDBCドライバに渡されます。)

  lazy val evaluator = factory(
    dbhosts = List("192.168.0.1:3306", "192.168.0.2:3306"),
    dbname = "dbname",
    username = "username",
    password = "password",
    urlOptions = "urloption" )
クエリの実行

先ほど作成したQueryEvaluatorを使ってクエリを実行します。以下のようにSQLを直接書いて、直感的に利用することが出来ます。

  case class User(userId : Long, serviceId : Int, userName : String)

  // 1レコードのSELECT 戻り値はOption型になる
  val oneUser : Option[User] = evaluator.selectOne("SELECT user_id, service_id, user_name FROM users WHERE user_id = ?", userId) { row =>
    User(row.getLong("user_id"), row.getString("user_name"))
  }
  
  // 複数レコードのSELECT 戻り値はSeq型になる
  val users : Seq[User] = evaluator.select("SELECT user_id, service_id, user_name FROM users WHERE user_id = ?", userId) { row =>
    User(row.getLong("user_id"), row.getString("user_name"))
  }
  
  // UPDATE/DELETE 戻り値は影響のあった行数 Int型になる
  val excuteRet : Int = evaluator.execute("DELETE FROM users WHERE user_id = ? ", userId)
  
  // INSERT 戻り値はauto incrementの結果値 Long型になる
  // executeを実行した後、SELECT LAST_INSERT_ID() を実行する仕様です
  val ret : Int = evaluator.insert("INSERT INTO users(user_id, user_name ) VALUES(?, ?)", 123, "hito_asa")

以上です!

(12/13 修正 INSERTとUPDATE/DELETEの説明が一緒になっていたのを修正しました。INSERTはauto incrementの結果値を返すようです)

Scalaでtreeコマンド

出遅れましたが、Scalaでtreeコマンド書いてみました。

元ネタは11/17のScala勉強会 in 渋谷 @sagara177 さんが発表されてたやつです。


tree/Tree.scala at master · hito-asa/tree · GitHub


ディレクトリとファイルの違いとか、ディレクトリ内の最後のエントリだけ枝の描画が変わるところとかの表現を、Java由来っぽいOOな書き方をしてみました。

こういうのを関数型っぽく書くのって難しい。。。どうしてもクラスとオブジェクトが出てきちゃう。頭がJavaに毒されている気がしてきた。

「WebプログラマのためのScala入門勉強会@渋谷」を開催しました。

初心者向けのScala勉強会として、「WebプログラマのためのScala入門勉強会@渋谷」というのを開催しました。(2週間も前の話ですが。)
参加者は20人強で、大半がPHPエンジニア(あとはJava, Ruby, Perl, Pythonあたり)だったようです。

資料はこちら。

開催概要とかは上記リンクのATNDのページのとおりですが、ざっと以下のような内容でした。

ScalaでHello, World!

Hello, World!からやってやる、という強い意志のもと、20分ほどかけてHello, World!を解説しました。
途中、環境的な理由によりHello, World!が動かないというまさかの事態が発生したり、時間不足で応用編が紹介できなかったりしました。
なお、応用編の内容はそんなに面白いものではないのですが、以下に紹介しておきます。

コンパイラプラグインでHello, World!

Scalaには、コンパイル時に独自のプラグインを実行させる仕組みがあります。コンパイラソースコードをパースした後のフェーズに処理を挿し込んで、構文木を受け取って、それを操作して次のフェーズに渡すことができます。
差し込めるフェーズは、parser, typer, pickler, liftcode, tailcalls, erasure, cleanup, jvm, terminalとあります。詳しい内容については、こちらを参照してください

ここでは、parserフェーズの後にHello, World!するコンパイラプラグインを書いてみます。

package wpscala

import scala.tools.nsc
import nsc.Global
import nsc.Phase
import nsc.plugins.Plugin
import nsc.plugins.PluginComponent

class EverythingHello(val global: Global) extends Plugin {
  import global._

  val name = "everything_hello"
  val description = "say hello to everything."
  val components = List[PluginComponent](Component)
  
  private object Component extends PluginComponent {
    val global : EverythingHello.this.global.type = EverythingHello.this.global
    val runsAfter = List("parser")
    val phaseName = EverythingHello.this.name
    def newPhase(_prev: Phase) = new SayHelloPhase(_prev)    
    
    class SayHelloPhase(prev: Phase) extends StdPhase(prev) {
      override def name = EverythingHello.this.name
      def apply(unit: CompilationUnit) {
        println("Hello, World!")
      }
    }
  }
}

いろいろとめんどくさいですが、parserフェーズの後に、SayHelloPhaseというフェーズを挟み込む処理を記述しています。
これをコンパイルして以下のXMLと一緒にJarにまとめたものを作成したうえで...

scalac-plugin.xml

<plugin>
  <name>everything_hello</name>
  <classname>wpscala.EverythingHello</classname>
</plugin>

以下のように使います。

scalac -Xplugin:everything_hello.jar hoge.scala

すると、hoge.scalaの内容とは無関係に、とりあえずコンパイル時にHello, World!が出ます。
ホントはこれじゃ面白くないので、ちゃんと構文木を操作して中身をHello, World!に書き換えてやろうと思ったのですが、そのためには構文木がどうなっているのかを調べたりしないといけないので挫折してしまいました。すみません。。。

source-readerでHello, World!

先程のコンパイラプラグインでは、パース処理の前に処理を差し込むことはできません。そのため、Scalaの文法としてパースできないソースコードについてはどうしようもありませんでした。
source-readerはパースよりも前、ソースコードを読み込むフェーズに処理を差し込みます。読み込んだソースコードを改変してコンパイラに渡すことができます。
これを応用して、コンパイラディレクティブを記述して、マクロを定義・展開したり、テンプレートエンジンを組み込んでコンパイル時にコード生成をするなんてことも可能です。

というわけで、何を読み込んでも全部Hello, World!にしてしまうsource-readerのコードは以下のとおりです。

package wpscala

import scala.tools.nsc.io.SourceReader
import java.nio.charset.CharsetDecoder
import scala.tools.nsc.reporters._

class EverythingHelloReader(decoder : CharsetDecoder, reporter : Reporter)
    extends SourceReader(decoder, reporter) {
  
  def this() = this(null, null)
  override def read(file : java.io.File) : Array[Char] = {
    """object Hello {
         def main(args : Array[String]) {
           println("Hello, World!")
         }
       }""".toCharArray
  }
}

これをコンパイルしてJarファイルにしたものを$SCALA_HOME/libに配置したうえで、以下のように使います。

scalac -Xsource-reader wpscala.EverythingHelloReader hoge.scala

すると、hoge.scalaの中身がなんであろうと、コンパイラにはHello, World!のコードが渡される、というわけです。

Scala開発環境構築

sbt, ENSIME, codefellow, Eclipse, NetBeans, IntelliJ IDEAの紹介をしました。

アンケートによると、大半がEclipseユーザーだったのですが、Scala + Eclipseはあまりおすすめできません。メモリ8Gでメモリ8G積んで高級なSSDマシンだったりするのならいいんですが、とにかく重いし遅いし固まります。
個人的にはNetBeans6.9.1がいい感じなのと、巷の評判ではIntelliJ IDEAが良かったりします。
素のエディタを使っている人も多いようでしたので、そういう人にはemacs + ENSIMEも便利かと思います。vim + codefellowは、どうしてもvimじゃないとダメな人にしかおすすめしません。動かすまでが大変なので。

コップ本読書会

コップ本(Scalaスケーラブルプログラミング)の第1章〜第3章を対象として、読書会を行いました。

と言ってもいきなりすぎるので、第1章については軽く解説して、残りを各小テーブルで進める形式にしました。
結果、テーブルごとに全然違うことをやっていたようで、環境構築の続きをやっていた人達もいれば、Scalaについてひたすら論議してた人たちもいました。
小テーブルだと話がし易いですし、各自やりたいことは違ったりもするので、この形式は良かったかなと思います。

事前アンケートの結果

当日発表しようと思って忘れていたんですが、事前にATNDでアンケートを取った結果です。
「この勉強会に何を期待しますか?」という設問で、目立った回答は以下のとおりです。

  • Scalaを基礎から勉強したい 5人
  • 仕事のため 3人
  • Scala再入門 2人
  • 参加者同士の交流 2人
  • Javaからの脱却
  • 関数型言語を学びたい
  • 手を動かしながら学びたい
  • GAEでFacebookアプリ作りたい
  • Scala自体に期待している

やっぱり基礎から勉強したいという人が多いですね。というわけで、この勉強会のターゲットは、主にそこを主眼としていこうと思います。

次回

そもそも勉強会の主催は初めてだし、いきあたりばったりなコンセプトのない状態で開催してしまいましたが、「Scala」という単語のおかげで予想以上の人にお越しいただきました。
期待していただいた内容とは違ったかもしれませんが、継続希望の声もいただけました。本当にありがとうございます。


というわけで、第2回を本日(2010/11/16)開催しますので、よろしくお願い致します。

http://atnd.org/events/9664