EclipseLinkでデータベースのパーティショニングをするぞ

データベースにおいてパーティショニング(Partitioning)という負荷分散手法をご存知でしょうか。

先日のエントリ「JPAでマスター/スレーブ構成のMySQLを使うぞ」で紹介した方法ではスレーブをスケールアウトさせることでSELECTなど参照系のクエリに対してはある程度まで負荷分散ができました。しかしINSERTやUPDATE、DELETEなど更新系のクエリはスケールアウトすることができません

パーティショニングはこのような問題を解決する手法の1つで、テーブルを一定のルールに基づいて複数のデータベースに分割し、データの格納先を分散させることで更新系のクエリの負荷を軽減させる仕組みです。シャーディング(Sharding)と呼ばれることもあります。

EclipseLinkはJPAの実装ですが、パーティショニングを簡単に扱うことができるように独自の拡張が施されています。今回はその方法をご紹介します。サンプルプロジェクトはこちらです。

続きを読む EclipseLinkでデータベースのパーティショニングをするぞ

Mavenでマスター/スレーブ構成のMySQLを起動して結合テストをするぞ

この記事はJava Advent Calendarの23日目の記事です。昨日はtoradukaさんのJavaのクラスファイルをjavapとバイナリエディタで読むでした。激しいですねー。明日はsmogamiさんです。

さて、Java EE Advent Calendar18日目の記事の予告通りMavenでまっさらなマスター/スレーブ構成のMySQLクラスタを構築し、そのデータベースに対して結合テストを実行する方法について解説します。サンプルのリポジトリはこちらです。makingチャソがフォークしてSpring Boot版作ってました。Springな方はこちらもぜひ参考にしてみてください!

続きを読む Mavenでマスター/スレーブ構成のMySQLを起動して結合テストをするぞ

JPAでマスター/スレーブ構成のMySQLを使うぞ

この記事はJava EE Advent Calendarの18日目のエントリです。昨日はn_agetsuさんのApache Shiro を使ってみましたでした。

Webサービスやソーシャルゲームのボトルネックになりやすいのがデータベースアクセスです。そしてこれらのサービスではデータベースにMySQLが多く使われています。

高負荷なMySQLの負荷分散の一つにデータベースをマスター/スレーブのレプリケーション構成にしてINSERT/UPDATE/DELETEなど更新系のクエリはマスターに対して行い、スレーブにマスターの更新内容をレプリケート、SELECTなど参照系のクエリはスレーブのデータベースにクエリを発行して負荷分散を行う手法があります。

このエントリではそのようなマスター/スレーブのレプリケーション構成のMySQLにJPAを使ってクエリを発行する方法をご紹介します。

続きを読む JPAでマスター/スレーブ構成のMySQLを使うぞ

Javaによる関数型プログラミング

@skrbより献本いただいた「Javaによる関数型プログラミング」を、ちまちまと通勤時間などを利用して読了しました。

今年はどのJava関連の勉強会に行っても「ラムダ式とStream APIで関数型プログラミングで安心安全!」という話がされていて耳タコな人も多いのではないでしょうか。

とは言え勉強会で聞くのは関数型プログラミングの”さわり”だけの場合がほとんどです。本書はそんな関数型プログラミングの”さわり”から、後半は実践的な例までひと通り書かれているため、本書を読んでおけばJava8での開発にも、とりあえず臆することはなくなるはずです。

関数型プログラミングの本質は1章の「まるで要求仕様を述べるようにロジックが流れていきます」という一文に込められています。入力と出力を関数(function)によって簡潔に記述し、連鎖することで目的の値を求める数学的なアプローチと言えるでしょう。

それに対して命令形プログラミングはメソッド(Method)によるデータ構造の破壊的変更や副作用を伴う、叙述的で「まるで小説のような」ロジックと言えます。

我々エンジニアは小説のようなプログラムを書くのではなく、仕様を明確かつ簡潔に書くことを善とします。本書で得られる関数型プログラミングの考え方は、Java8に限らず他の関数型言語への足掛けとして、将来のプログラミングライフを間違いなく豊かにしてくれるでしょう。

ScalaやErlang、LispやHaskellといった関数型言語がここ数年のトレンドですが、Java界隈での関数型プログラミングのアプローチはJava8で突然始まったわけではなく、Guavaのコレクションライブラリなどでそのエッセンスを感じとった人も多いのではないでしょうか。Guavaを触ったことがあれば、4章まではスラスラと頭に入ってくると思います。

ラムダ式の応用として5章からは非常に参考になります。Execute around methodパターンなどはJava7までは匿名クラスを使った非常に冗長な書き方をしていましたが、Java8からはラムダ式のお陰で非常にすっきりと記述することができます。

以前JJUGナイトセミナーで紹介したJPAのCriteriaを生成するExecute around methodパターンも、

これが

このように簡潔に記述ができるようなります。EclipseやIntelliJ IDEA、NetBeansなど最新のIDEではラムダを適用できるコードは自動的に変換する機能があるので、はじめはIDEの力を借りて既存のコードを修正しながらラムダ式適用の勘を掴んでいくのもいいでしょう。

7章は前半の末尾再帰/末尾呼び出し最適化に関する説明が分かりづらくて、初めて末尾再帰を理解するには少々ツラそうです。「再帰が深いとスタックを喰い潰す通常の再帰を、関数の末尾で再帰呼び出しするコードを単純なループに展開する最適化」みたいな一般的な末尾再帰呼び出し最適化が何を目的としているのか書いてあるとよかったのかなと思います。このあたりが比較的分りやすいかと思うので7章を読む前に目を通しておくといいかもしれません。

8章の「8.2.2 命令形スタイルからの脱却」では、メソッドの実装を整理する際にやってしまいがちな例が書かれています。

    final List<StockInfo> stocks = new ArrayList<>();
    for(String symbol : Tickers.symbols) {
      stocks.add(StockUtil.getPrice(symbol));
    }
    
    final List<StockInfo> stocksPricedUnder500 = new ArrayList<>();
    final Predicate<StockInfo> isPriceLessThan500 = StockUtil.isPriceLessThan(500);
    for(StockInfo stock : stocks) {
      if(isPriceLessThan500.test(stock))
        stocksPricedUnder500.add(stock);
    }
    
    StockInfo highPriced = new StockInfo("", BigDecimal.ZERO);
    for(StockInfo stock : stocksPricedUnder500) {
      highPriced = StockUtil.pickHigh(highPriced, stock);
    }
    
    System.out.println("High priced under $500 is " + highPriced);

このような3つのforループを

    StockInfo highPriced = new StockInfo("", BigDecimal.ZERO);
    final Predicate<StockInfo> isPriceLessThan500 = StockUtil.isPriceLessThan(500);

    for(String symbol : Tickers.symbols) {
      StockInfo stockInfo = StockUtil.getPrice(symbol);
      
      if(isPriceLessThan500.test(stockInfo))
        highPriced = StockUtil.pickHigh(highPriced, stockInfo);
    }
    System.out.println("High priced under $500 is " + highPriced);

1つのforループにまとめています。これを本書では「得たものと失ったものがあります」と表現しています。それはなんでしょうか?

ぱっと答えが浮かぶ方は本書を読まなくても大丈夫かもしれません。関数型プログラミングを適用することで、上記どちらよりもエレガントなコードに生まれ変わります。自信が無い方はぜひ本書を手にとって確認してみてください。

Cloudera Managerで手軽にNorikraを試す

NorikraをCloudera Managerの管理下に置き手軽に試すためのCSD/Parcelを作りました。NorikraとはSQLでストリーム処理を行えるOSSで、いくつかの制約はありますが、大量のログを低レイテンシで処理することができます。

NorikraはJRubyで実装されているのでgemコマンドでインストールすればすぐ使うことが出来る反面、そもそも標準パッケージにJRubyがないのでインストールが面倒だったり、他のHadoopのコンポーネントはそもそもCloudera Managerで管理しているので、Norikraだけ管理が違うのなんかやだなあ、ということでCloudera Managerで管理できるようにしてみました。

Cloudera Managerとは?

Cloudera社が開発しているCDHというHadoopディストリビュージョン用の管理ツールです。Webコンソールからサービスの追加削除、起動停止、監視や障害検知など運用に関するほぼ全てを行うことができます。管理用のREST APIも用意されているので内製の管理ツールとの連携も簡単です。

Cloudera Managerのバージョン5.0.0以降からアドオンサービスが利用できるようになりました。Custom Service Descriptor(CSD)と呼ばれるサービスの動作を定義したパッケージと、Parcelと呼ばれるサービスのファイル一式が入ったパッケージを用意すれば、Clouderaが提供しているHadoop関連のサービス以外でもCloudera Manager上でサービスの管理ができるようになります。

今回はこの仕組を使ってNorikraを管理できるようにしました。

インストール

まずCloudera Managerのインストールされているホストの/opt/cloudera/csdにNorikraのCSDを配備します。

wget -P /opt/cloudera/csd https://nagaseyasuhito.github.io/norikra-csd/NORIKRA-1.0.5-cdh5.1.0.p0.4.jar

次に配備したパッケージをCloudera Managerにインストールします。REST APIっぽいですが、URIがほかのREST APIのエンドポイントとは違うんですよね。以下のURLにアクセスします。

http://<<Cloudera Manager Server>>:7180/cmf/csd/install?csdName=NORIKRA

レスポンスが

{"data":null,"message":"OK"}

であれば正常にインストールができています。Parcelのステータスを確認してみましょう。

http://<<Cloudera Manager Server>>:7180/cmf/parcel/status

cloudera-manager-04他のサービスと同様にNorikraのサービスがDownloadableのステータスになっています。ダウンロード後Distribute、Activateすれば準備は完了です。

cloudera-manager-05クラスターのAdd a ServiceからNorikraを選択してインストールできます。

コマンド(jruby, norikra, norikra-client)も合わせてインストールされます。起動終了はもちろんのこと、サービスページからNorikra Web UIへのリンク、設定画面ではPort Number、Threading TypeやStats File Pathなども変更できる上、ログもCloudera Manager上で確認できるので、標準的な範囲での利用はとりあえず事足りるのではないでしょうか。

まとめ

足りない設定や不具合など見つけたらPull Requestお待ちしています。コードはこちら
https://github.com/nagaseyasuhito/norikra-csd
https://github.com/nagaseyasuhito/norikra-parcel

近々PrestoのCSD/Parcelも作ろうかと思います。

fluentdでネストされたデータを扱いやすくする方法

前回の記事でJMXのメトリクスをfluentd経由で蓄積する方法を書きましたが、殆どの場合JMXのメトリクスは深い入れ子構造になっています。

$ curl -X POST -d '{"type":"read","mbean":"java.lang:type=Memory"}' http://localhost:8778/jolokia/ | python -mjson.tool

{
    "request": {
        "mbean": "java.lang:type=Memory",
        "type": "read"
    },
    "status": 200,
    "timestamp": 1389278295,
    "value": {
        "HeapMemoryUsage": {
            "committed": 133054464,
            "init": 16432320,
            "max": 518979584,
            "used": 67861272
        },
        "NonHeapMemoryUsage": {
            "committed": 46202880,
            "init": 24313856,
            "max": 251658240,
            "used": 45135144
        },
        "ObjectName": {
            "objectName": "java.lang:type=Memory"
        },
        "ObjectPendingFinalizationCount": 0,
        "Verbose": false
    }
}

こういったメトリクスの場合に蓄積先をTreasure Data DWHにするとネストされた部分は直接参照できず、get_json_objectというUDFを使う必要があり非常に面倒です。

# 蓄積されているデータを確認
$ td table:tail -n 1 -P glassfish memory
{
  "timestamp": 1389278845,
  "time": 1389278845,
  "status": 200,
  "request": {
    "mbean": "java.lang:type=Memory",
    "type": "read"
  },
  "value": {
    "Verbose": false,
    "ObjectPendingFinalizationCount": 0,
    "NonHeapMemoryUsage": {
      "max": 251658240,
      "committed": 46202880,
      "init": 24313856,
      "used": 45156080
    },
    "ObjectName": {
      "objectName": "java.lang:type=Memory"
    },
    "HeapMemoryUsage": {
      "max": 518979584,
      "committed": 133054464,
      "init": 16432320,
      "used": 59201544
    }
  }
}

# 直接参照できないためエラーとなる
$ td query -d glassfish -w "select v['value']['HeapMemoryUsage']['used'] from memory"

# このように参照する必要がある
$ td query -d glassfish -w "select get_json_object(v['value'], '$.HeapMemoryUsage.used') from memory"

今回はデータをフラットな形式に変換して蓄積することで、クエリを書きやすくする方法のご紹介です。

続きを読む fluentdでネストされたデータを扱いやすくする方法

JMXのメトリクスをfluentd経由で蓄積する

みなさんJMXは使っていますか?Javaアプリケーションのメモリ使用量を始めとした統計情報を取得したりできる、運用には欠かせないモニタリング・管理の仕組みですが、統計情報を蓄積する方法に悩んでいる方も多いのではないでしょうか。

今回はアプリケーションから取得できる様々な統計情報をfluentd経由で蓄積し、分析やトラブルシュートに活用する方法を紹介します。

続きを読む JMXのメトリクスをfluentd経由で蓄積する

mvn siteのtips三連発

この記事はJava Advent Calendar 2013の21日目として書かれたものです。昨日は@yoshioteradaさんの「Java EE 7 WebSocket アンチパターン」でした。

みなさん、mvn site使ってますか?

ドキュメントが自動生成できる!と思ってワクワクしながら実行するも、

  • 見た目がイマイチでテンション上がらなかったり
  • 大したドキュメントが生成されずにガッカリしたり
  • デプロイの設定が面倒でやらず、生成しても見なかったり

する事で有名なアイツです。やれば(pom.xmlをがっつり書けば)できる子なのに、初見でポイですよね。

そんなmvn siteですが、pom.xmlにちょっと化粧をしてやれば案外使いやすい場面もあるんです!今日はそんなTipsを3つほどご紹介しましょう。

続きを読む mvn siteのtips三連発

メソッドバリデーションのユニットテスト

この記事はJavaEE Advent Calendar 2013の12日目として書かれたものです。昨日は@yoshioteradaさんの「JSF + WebSocket で実装した IMAP Web メール・クライアント」でした。

11月に開催されたJJUGナイトセミナーの「おっぴろげJavaEE DevOps」のテストに関するセクションで「極力ユニットテストに寄せることで、JavaEEコンテナを使わずテストの実行速度を早くする」というお話をしました。

セッションではJPAのテストをJavaEEコンテナから切り離し、ユニットテストとして実行する方法をご紹介しましたが、時間の関係で省いたトピックをご紹介します。メソッドバリデーションのユニットテストです。
続きを読む メソッドバリデーションのユニットテスト