GROUPエンジニアブログです。2012年03月2012年03月27日16:01カテゴリ第3回チューニンガソンで2位になりました!!こんにちは!株式会社adingoでエンジニアをしている前田(@brtriver)といいます。弊社の岩川(@hogehiko)とペアで参戦し2位に入賞することができました!TOPのスコアは本当に僅差でしたので、運も味方に付けた結果なのですが、簡単にレポートしてみたいと思います。前日に作戦会議といいつつドイツビールがおいしいお店で二人してただ呑んだくれるという状態で何も準備せずに当日を迎えました。して、緊張せずに寝れたことが大事だったかもしれません。作業分担お題はblojsomというJavaアプリケーションのチューニングでした。PHPのアプリでなかったことは想定内でしたが、JavaでTomcat縛りというのは予想していませんでした。Javaまわりは岩川が詳しいので私はMySQL周りを担当とある程度分業してチューニングをすることに参考スコアが63だったので、この値を目標にがんばることに。check=1.000)アナウンスでは初期ベンチが23ぐらいと聞いていたのでかなり低いなぁという印象。設定を色々変更し、アプリケーションの再起動もかなりの回数を重ねるだろうということでrestart.shというシェルスクリプトを用意し、再起動やDBのコメントデータのtruncateなどをあらかじめ用意。どの設定や変更が有効なのかを把握するために、一度の多くの変更は行わずにこまめにベンチを取得するようにしました。当たり前のことなのですがこのおかげもあって、突然スコアが劇的に下がった場合に原因がわからないということもなく安定していたと思います。サーバーの状態はtopとvmstatで確認というレベルでした。チューニングの記録MySQLの設定は最初からある程度行われている状態でした。メモリ周りの設定を増やすことでスコアは24.377に。スロークエリなども確認したのですが全く出ていないのでボトルネックにはなっていない印象。java周りでは、Tomcatのメモリを増やして調整することで一気に48.278に!この時点の中間発表で2位になっていたので、「もしかしたら...!!」という期待をもちつつ気合が入りました。Tomcatのスレッド数を減らしたり、MySQLのバージョンを5.5に上げる+スレッド数を調整した結果スコアも60近くになりました。このころに自身のベンチで最高値を叩いていました。check=1.000)しかし、このあと何故か60台を超えることなく、50台をさまようことに....だいたい思いつく施策はやった感があったので、あとは本番の計測でベストな値を出すためにはどうすればよいか?という点を相談していました。ベンチ結果は複数回実行するとスコアに変化が見られました。作業開始当初はアプリケーション再起動後に複数回ベンチを叩くことでスコアが上昇する傾向だったのが、JVMを6から7に上げたあたりから再起動後最初のベンチが一番良いスコアを叩く傾向に変わって来ました。直接の原因はわからないですが、本番で一番よい結果を出すには、終了直前にアプリケーションを再起動させて何も触らない状態で終わることだろうと判断。ラスト15秒ぐらいで一番最初に用意したrestart.shを叩いてあとは神に祈るのみという状態でした。59.486また、弊社のもうひとつのチーム(@kenichikat)が相方が障害対応のため急遽個人参戦にもかかわらず10位入賞と大検討していました!まとめ今回のチューニンガソンはJavaの環境設定をどこまで最適化できるかが大きかったと思います。GROUPの水越(@Akiyah)です。最近、仕事でデータ解析環境「R」を使ってデータベースからデータを取り出して加工することが多いです。いったとき、データベースからデータをとる部分はSQLでまるまる取得して、その後Rでもりもり加工するのが好きです。その場合、何度も実行するとSQLの処理が重いしデータベースに負担をかけることになるので、ちょっと困っていました。そこで今回、Rのメタプログラミングで関数呼び出しをキャッシュ化してみることにしました。キャッシュと言ってもずっと同じ値を返すのではデータベースに新しいデータが入ったときに更新されないで困るので、ある一定期間(例えば24時間)を過ぎたら最新の値をとるように作ります。キャッシュ無しまず最初に、"重い処理"という文字列を出力する関数を作ります。return(result)}このprint("重い処理")が重いSQLであると思ってください。-0.277692何度も"重い処理"が実行されているのがわかります。グローバル変数を用いたキャッシュそれではキャッシュするバージョンを作ってみましょう。Rでは実行環境(ワークスペース)にデータを持たせて、Rの終了時にファイルに保存して次のR起動時に読み込む事ができるので、グローバル変数にキャッシュを入れておけば今回の用途には十分です。単純に書くとこうなります。return(result)}<<-は永続代入と言って、関数定義からグローバル変数に代入するときに使います。キャッシュ(heavy_func2.cache)にはキャッシュする値(value)と更新日時(updated_at)のリストを入れておきます。-0.06969717"重い処理"がはじめの一回しか呼ばれていない事がわかります。戻り値はキャッシュが効いて同じ値を返しています。キャッシュの更新時間はここでは10秒にしているので10秒経つともう一度処理が実行されて、値も新しいものになります。0.8203284ちなみにRでは変数名に"."(ピリオド)が使えます。逆に言うとピリオドが使われていたからと言ってそれはJavaやRubyなどの言語のようなオブジェクトの属性へのアクセスと言うわけではありません。実はこのままだと困る事があります。関数定義の直前にキャッシュのグローバル変数を定義しているので、たとえば関数定義を別ファイルにして何度も呼び出すと、その度にキャッシュが消えてしまうのです。そこを改善してみます。return(result)}グローバル変数を直接定義するのではなく、変数が定義されているかどうか確認する関数existを使うようにした事で、明示的なグローバル変数の定義を消す事ができました。メタプログラミングっぽくなってきましたね。assign)経由にしました。assignの引数にある.GlobalEnvはグローバル環境を表します(このあたりをもっと有効に使う例はまた今度)。キャッシュを別関数化そろそろ仕上げです。このキャッシュの仕組みを共通化して別の関数に出します。残りタスク残りタスクキャッシュの更新時間を設定できるようにするキャッシュを高階関数化して関数を渡すとキャッシュ化した関数を返すようにするグローバル環境を使わないようにするキャッシュ化する関数のソースコードが変更された場合はキャッシュをクリアするようにする残りタスクは解決できたらまた報告します。