読者です 読者をやめる 読者になる 読者になる

Kansai RubyKaigi 06に参加してきた

参加してきた!

7月11日 (土)にKansai RubyKaigi 06がエムオーテックス新大阪ビルで開催されました。場所はビルの名前の通り新大阪駅近くで、非常に便利の良い場所です。 セッションは映画館みたいな大会議室で行われました。参加者は200名以上で大変な盛り上がりでした! f:id:tech-kazuhisa:20150711095345j:plain

以下、気になったセッションのメモです。

Rubyにみるプログラミングスタイルの進化(まつもとゆきひろさん)

早口のMatzのセッションにしては珍しく、スライド上でうさぎがカメを追いかけてる状態が長かったです。I/Oを読んでる17歳の時の写真から始まり、ポケコン、紙のノート上でのプログラミング、SONY NEWSワークステーションでのRuby開発の話とMatz自身の人生を垣間見ることができました。 印象的だったのがGitの利便性についてMatzの口から説明があったこと。これって珍しいですよね。 あとは、静的型付けの話。型があるのが嫌なわけではなく、いちいち書くのがめんどくさいとのこと。この辺りの話は「オープンソースの代弁者」としてセミナーでスーツ組に対して話をする白Matzとは異なり、いきいきしていました(笑)。 今でもRubyMineなどのIDEではかなりいい感じにコード補完がされるので、さらにPCの処理能力が進化し、言語側から型情報のサポートを受けることができれば、さらに楽ちんなプログラミングができる世界がやってくるのでは、と感じることができたセッションでした。

Readable RSpec(株式会社spice life)

LT枠でのお話でした。RSpecの書き方についてのあれやこれや。 let(:user)をどこで定義するのかは確かに難しいですね。私はスコープが狭くなることになるべくこだわりたいので、同じ定義を2箇所で書いてしまうこともあります。DRYに書けるのがRSpecの利点と思いますが、見通しが悪くなるくらいならDRYは捨てます!

Railsガイドを支える技術(@yasulabさん)

railsguides.jp

Railsガイドを和訳したときのノウハウについて。Gitのコミットログをスキャンして変更点を探し出すという手法が素晴らしかった。私自身、この手のガイドは1箇所でも情報が古ければ全体的に古く感じてしまうこともあり、情報の鮮度へのこだわりをひしひしと感じました。

スモウルビー1.0:小学3年生から始めるRubyプログラミング(@takaokoujiさん)

Scratchベースのプログラミングツール「スモウルビー」でプログラミング少年団という活動を行っているお話。素のScratchはブロックを組み合わせるだけで、その後のアップグレードパスが用意されていないけど、スモウルビーを動かすためにはRuby + Railsが必須なので、より複雑なプログラミングを行う環境が自然にできあがるとのことでした。 我々も同じことが言えて勉強会で意識が高まったけど、家や会社で試そうとすると環境構築でつまずいてしまうパターンが多いので、この取組はとても理にかなっていると思います。スモウルビーはScratchをRubyのコードに変換することもできたと思うので、そのあたりデモンストレーションで見たかった気もします。

RSpec、Minitest、使うならどっち?(伊藤 淳一さん)

偉い人がRSpecを使いたがらない風潮は私も以前から感じていました。今回の発表では機能やスピードをわかりやすく比較してRSpecに優位性があることが証明されました(って理解でOKよね?)。とはいえ、Githubでプルリク出したりForkしたソフトウェアの修正時にMinitestの知識が必要になってくることもあるので、基本的なことは抑えておこうと思いました。 余談ですがMinitestがランダムな順序でテストを実行するがデフォルト動作なのは良いことですね!「手元で動かしてOKで、CIでコケる」というテスト組み合わせ問題の単純な解決方法になりそうです。

API server/client development using JSON Schema(@izumin5210さん)

単なるテキストファイルであるJSONに制約を付けてバリデーションを行うことができる仕組みを「JSON Schema」と言うそうです。今回はじめて知りました。私自身、仕事でAPIを作ることが多いので調べてみようと思います。 発表の中で「RailsではStrong parameterがあるのに JSON Schema必要?」みたいな話があったのですが、JSON Schemaの一番の利点はクライアント・サーバー両方のテストが容易に書けることだそうです。 具体的なコードが少なく話しの後半はちょっとついて行けてなかったのであとで調べてみます。

キーワードパラメータを支える技術(笹田 耕一さん)

Ruby2.1から2.2に変わったタイミングでキーワード引数が大幅にスピードアップしたそうです。今回の発表ではどのような取り組みで高速化したのかをわかりやすく説明されていました。 通常Rubyの高速化の話はC言語で語られることが多く、私にはチンプンカンプンなのですが今回はRubyで作られた擬似コードによる説明で非常に分かりやすかったです。

def f3
  3
end

def foo(k1: 1, k2: eval(“k3”)), k3: f3())
  p k1, k2, k3
end

foo

この場合、一見 1, 3, 3 と表示さそうですが、Rubyのコードは左から実行されるのが大原則なので、 1, nil, 3 と表示されるべきなのだそうです。めったに書かれないこのコードを実現するために複雑な処理が入っているとのこと。 懇親会の居酒屋でもノートPCを開いてこの点を丁寧に説明して下さり、より理解が深まりました。ビール片手にRubyコミッターから言語の仕様の話を聞かせてもらえるという貴重な体験ができました。

まとめ

大阪や東京で開催されるRubyイベントに何度か顔を出すうちに、親しくお話させてもらえる方も増えてきました。こういったイベントでの話はブログやSNSでは得られない生の声を聞くことができるので楽しいですね。 最後になりましたがスタッフの皆さんお疲れ様でした。楽しい時間をありがとう! 来年はOkayamaRubyKaigiを開催しようかな?

RubyKaigi2014に参加してきた(2日目、3日目)

1日目はこちら

2日目

Coming soon…(Yukihiro "Matz” Matsumoto)

  • 2001年にRuby2の話をしている
    • VirtualMachineが入る
      • 6年後
      • 笹田さんがきちんと実装してくれた
    • M17N
    • Native thread
    • Generational GC
  • RubyConf 2005
    • Stabby lambda ( -> )
  • RubyConf 2006
    • Bikeshed argument encouraged
      • 自転車小屋の色を何色にするかは盛り上がってすぐに決まるが、原子力発電所をどこに作るかは有識者の間で勝手に決まってしまう
  • 22のアイデアのうち7つは入らなかった
  • オープンソースコミュニティはサメのようなものなので泳ぎ続けないと死んでしまう
    • 燃料を投下したい
  • Ruby 3.0のアイデア
    • Concurrency
    • JIT(LLVM?)
    • Static typing
  • 最近登場した言語はスクリプト言語でありながら静的な型を持っている
    • TypeAnnotation
      • def connect(r -> arg) -> Fiber みたいな
    • パフォーマンスのためのStatic言語が必要なわけではない
      • 思い込み
    • コンパイルタイムの短縮
    • 型を導入すると柔軟性が減る
      • ダックタイピングと相性が悪い
    • Documentation
      • 今はnumと書いてたら数字というルール
      • メソッドに何を渡せばいいか型宣言をみればわかる
    • RubyがStatic Typingを持っていない理由
      • なくてもなんとかなる
      • ダックタイピング
    • 静的な型を導入するとしてもOptionalな仕様になる
      • 型ありの世界から型なしの世界に渡すと情報が失われる
        • ごく一部だけの型チェックしか行われない
      • TypeScriptは頑張ってすべての型を指定している
      • すべてを型指定したRubyRubyじゃない
      • 型が推測できるようなコードを書いている
        • いちいち型宣言したくない
        • ベストエフォートな型チェックをする技術
          • Duck Typing的に型を推測する
      • コンパイラに型を教えるのではなくて、コンパイラが「こう思って書いてるんですよね?」という推測を行ってほしい。IDEやエディタから補完できるようになる。
      • Two language is one.

感想:Ruby3.0に導入されるかもしれない機能のお話。私はPythonのように、制約はないけどDocumentとして引数の型を書いておくという手法はアリかなと思う。けど、まつもとさんはとにかくコード量を減らしたい仕様にしたいみたい。コードの文脈からしてこのメソッドの引数にはintが入るであろうことは、言語が判断すべき。わざわざ型を指定しなくても、文脈で判断できるのが良いコードという認識なんだと思った。現在RubyMineとかのコード補完やチェックはかなりのレベル(ホント、どうやってるのか不思議なくらい)まで来ているので、言語側がサポートしてくれればより精度の高いコーディング補助が可能になると思う。今後Rubyがどのような進化をとげるのか楽しみ!

<%= link_to "bundle", "update" %> - Make "bundle update" more fun to review(Kensuke Nagae)

  • bundle update
    • Gemfile.lockが更新されるが、各Gemがどんな変更が行われているかを見たい。
  • Compare Linker
  • GithubからCompare Linkerがwebhookを受け取る

感想: bundle updateする→Gemfile.lockがなんか更新されてる→いつ更新してるんだろうとRubyGemsを見に行く→何が変わってるんだろうとGithubを見に行く... という流れは私もよく体験する。これを自動化してGithubに変更点のDiffを見ることができるリンクをpushする仕組みを作ったお話。3回同じことをやったら自動化しろとはよく聞くが、この複雑な処理を自動化したのは素晴らしい。

ServerEngine: a framework for multiprocess servers in Ruby(Masahiro Nakagawa)

  • fruentd
    • ログ収集ソフトウェアのメイン開発
  • System programs
    • Chef
    • Serverspec
    • Apache Deltacloud
  • Network server
  • Log Server
    • Fluentd
  • サーバープログラミングで考慮すべきこと
    • マルチプロセス、マルチスレッド
    • エラーハンドリング
    • ログ
  • ServerEngineを作った
  • 何ができるか
    • Unicornみたいなサーバーを簡単に作れる
    • Worker moduleとServer moduleをユーザーが作る
  • 3層構造
    • Supervisor
      • ユーザーがあまりいじる箇所はない
    • Server
    • Worker
  • USR2 signalでリロードできる

感想: 操作感はまさに慣れ親しんだunicornそのもの!webrickも非常に便利なWebサーバーだが、ServerEngineを使えば大規模アクセスにも対応したunicornライクなサーバーを作ることができそうだ。

3日目

おはようRails

  • (あまりの面白さにメモ取ってなかった)

    感想: tubolinksはみんな消してるんだなー、とか今の若い子は「Railsは業務で使うもの」だと思ってるとかなかなか刺激的な内容だった。正直、私はあまりサービス志向のプログラマじゃないので(社会人としてそれはどうなんだというのはさておき...)Rails使ってサービスを素早く立ち上げるって点はあまり興味ないかも。自分が楽しめる仕事をやっていきたいなーと思っております。

Speeding up Rails 4.2(Aaron Patterson)

  • ManageIQ
  • Rails no one commiter
  • Rackはもう終わり。楽じゃない
  • Rack 2.0
    • the_metalはrack2.0のプロジェクト
  • Rack 1.xの問題
    • hashのkey
    • ストリーミングの制御がめんどくさい
  • Adequate Record
  • URL PATHは短いほうが速い
    • 配列的な構造を定数に変換することでスピードアップ

感想: たこ焼き仮面ことAaronの日本語での発表はとても楽しく聞くことができた。特にスライド内のジョークを日本人のセンスに合わせているところがGood! 発表内容としてはAaronさんの地道なRails高速化についてのお話がメイン。長く運用するシステムでは長期的に見ると細かい点が積み重なり問題を引き起こすことがあるので、このような改善はとてもありがたい。「存在しないコードが一番速い」というのは名言だと思った。

Everything is Broken: A Story of Hope(Jonan Scheffler)

感想: あまりRubyに関係がある内容では無かったが、公開鍵暗号の仕組みを色の混ぜあわせで解説する方法はとてもわかりやすかった。私も他人に説明するときは使わせてもらおう。

以上が3日間でビビッときた発表でした。 RubyKaigiはいつもネット上でしか交わらない方とリアルでお話することができる素晴らしいイベントです。この3日間の熱を冷まさないように、岡山での活動につなげていかねばっ!と思いました。

RubyKaigi2014に参加してきた(1日目)

f:id:tech-kazuhisa:20140920094741j:plain

▲3日目 おはよう Railsの様子

9月18-20日にタワーホール船堀にて開催されたRubyKaigi2014に参加してきました。 簡単ですが気になった発表について、感想を交えてレポートを書いておきます。

1日目

CRuby Commiters(Tomoyuki Chikanaga)

  • CRubyのコミッタは80アカウント、実質50人ぐらいのアクティブなコミッタがいる
  • RubyKaigiでスピーカーになっているのは15人
    • ko1
      • 笹田さん
      • Herokuでフルタイムコミッタ
      • 現行RubyVMの開発者
      • Ruby2.2からIncremental GCが使える
        • GCの停止時間を短くする
    • nari
      • Mr.GC
      • Lazy Sweep/Bitmap Marking
      • Symbol GCという新機能を開発
    • matz
      • Rubyの作者
      • mrubyの作者でもある
    • kazu
      • Kazuhiro NISHIYAMA
      • Mr. ‘fix typo
      • typoを修正する
    • hsbt
      • ruby-lang.orgの管理者
      • 最新のRubyでライブラリをチェックしてくれている
      • 最新のRubyRailsが動くのはこの人のおかげ
    • sorah
      • Shota Fukumori
      • Rubyのテストを並列実行するツールの開発で有名
    • kouji
    • ktsj
      • Kazuki Tsujimoto
      • RubyVMの不具合修正
    • tenderlove
      • Aaron Patterson
      • psych/dl/fiddleのメンテナ
      • AT&TからRedHatへ転職
      • Nokogiriの開発
    • keiju
      • Keiju Ishitsuka
      • Rubyの名付け親
      • irbの作者
      • 古くからある標準添付ライブラリの作者
    • seki
      • dRuby/rinda/erbの作者
    • zzak
      • Document maintainer
      • rubygems, rake, rdoc の開発者
      • カンファレンスフリーク
        • 全世界のカンファレンスに参加
    • kou
    • tmm1
      • Aman Gupta
      • Githubで働いている

感想: ネット上やRubyKaigi会場で時々お見かけする方々が、どんな分野を担当してるか分かってよかった。

Building the Ruby interpreter -- What is easy and what is difficult?(Koichi Sasada)

  • 10周年
  • Rubyの開発は何が簡単で何が難しいかという話
  • 何をやってきたか
    • アンダースタンディングコンピュテーション(本)
    • YARV (Ruby1.9)
    • Fiber
      • 同期的マルチスレッド
    • Ruby2.0ではメソッドキャッシュを高速化
    • Ruby2.1で世代別GCを導入
  • 本題
    • Rubyコミッタの責務は品質を高めること
    • 高速化
    • トレードオフとは
    • Ruby’s Performance
      • 簡単
        • VMJITをシンプルに作るのは難しくない
      • 難しい
        • 人間が管理可能な状態にする
        • VMのコードが爆発しないようにする
          • 同じようなコードに記述はコード生成を行った
        • 脱最適化
          • メソッドの再定義やevalによるローカル変数のアクセスが行われたら最適化を再定義する
    • 並列実行
      • 簡単
        • 並列実行を提供するだけなら簡単
      • 難しい
        • スレッドプログラミングは難しい
          • Programming model
          • Debugger
          • なんで難しいか?
            • 情報のシェア
          • 使いやすいデバッガを提供
          • forkしてプロセスを分ける

感想: 「なんとなく思いついたアイデアを実装するのは簡単。でも、まともに使えるようにするためには苦労が必要」という部分は、レイヤーは違えどどんなエンジニアにも共通なんだなと思った。私の仕事だとRubyで大量のデータを集計するバッチ処理を書くことが多くて、GCの遅さには悩まされてる。これが新バージョンのRubyで少しでも軽減されると助かる。

Controller Testing: You’re Doing It Wrong( Jonathan Mukai-Heidt)

  • controllers
    • bing action
    • small details
  • controllerはno logicであるべき
    • テストが必要なロジックはコントローラに書くな
  • before_filterを使う
  • Little to no logic in controllers.
  • shared examples cover the small details.
    • 認証テストをまとめる
    • 使いすぎるとどこでコケてるかわからなくなる
  • テストはチェックリストのように
  • 命令文ではなく平叙文的にテストをかけ

感想:「うーん。まぁそうだよね」と思う内容だった。shared examplesを使ってテストをまとめるとしても、やり過ぎるとテストが追いづらくなるし、可読性を求めて一箇所に書いてしまうとDRYじゃなくなりメンテしづらいしバランスが大切ということかな。「テストはバランスが大切」という話は3年ほど前からよく聞いてるし自分でも感じてるんだけど、これといって決定打が無いなとも思ってる。

Introduce Oracle enhanced adapter for ActiveRecord, another choice for your Rails database.(Yasuo Honda)

  • Oracle enhanced adapter maintainer
  • Oracle enhanced adapter
  • 標準にない機能
    • Rubyの型とのマッチング
  • 既存のテーブル設計をRailsに合わせるユースケースが多い
    • 7つほど専用の命令が用意されている
  • Oracleを使うことで何が良いか?
  • Oracle11g
    • 1つのプリペアードステートメント複数の実行計画を持つことができる
      • User.where(:database => ‘oracle’).last.id
        • ActiveRecord
          • そのまま
        • Oracle modified SQL
          • 素のSQLではなく最適化されてる
            • where文が書き換えられてる
            • 実行計画を動的に変えてくれる
              • where文で指定された列に該当する値が多ければフルスキャン
              • そうでなければindexを使ってくれる
            • 実行計画がメモリに蓄えられてシェアされる
    • 問題点
      • いくつかテストがコケる
        • Empty string as NULL
          • 長さ0の文字がNULLとして扱われる
        • Identifier length <= 30 byte
          • オブジェクト名は最大30文字
        • “id” needs to set explicitly
          • Oracleは明示的にidに入る値を書かなくてはならない
        • No limit in sub queries
          • limit句がサブクエリ内で書けない
    • Rails4.2
      • Adequate Record
        • パフォーマンス改善
    • Oracleとしての新しい機能
      • 12cが最新機能
        • 徐々に標準に近づけようとしている
        • JSON Datatypeのサポート
        • Better Top-N query support
          • これのおかげでページネーションがまともに動くようになった。
            • order_hacksというダーティーな処理を削除
    • 環境作るのが大変だよね

感想:発表前の会場挙手で意外とRailsMySQLを使っている人が多かった。Oracleは普段使ってないけど、MySQLPostgreSQLと比較して独特の仕様が多いように思う。その反面「Oracle modified SQL」で適切なSQLに書き換えれば高速に動作するところが素晴らしい。単に「ActiveRecordOracleに対応させましたよ」というだけでなくOracleの旨味を引き出していた。メインで利用するDBとしての選択ではなく、外部システムとのやりとりで接続することを想定してActiveRecordに追加命令があるのもありがたい。複雑になりがちなRailsでの複数DB接続に希望が持てた。

Hypermedia: the Missing Element to Building Adaptable Web APIs in Rails(Toru Kawamura)

  • Sendagaya.rb
  • Web APIの話
  • 蜘蛛の巣のようなAPI
    • public
    • どう使われるか分からない
  • 蜘蛛の糸のようなAPI
    • private
    • どう使われるか分かってる
  • APIをRestfulにするかどうかは要件次第
    • 要件にあったAPI
  • 今回は蜘蛛の巣のようなAPIをどう作るかという話
  • Breaking Changes are Harmful
    • 壊す変更は有害
    • クライアントがiOSアプリだと変更に時間が掛かる
  • 人間が読めるドキュメントから作られるサービスがたくさんある
  • 機械が読める説明書から作られるクライアントもある
    • JSONで仕様を提供してコードを自動生成する
  • APIの変更がクライアントに反映されるべき
  • APIの説明を分割して各レスポンスに埋め込むのが良い
  • 疎結合が良い
  • APIコールのメタファーが危険
    • クライアントが次に何をするかはAPIから返ってくるリンクをたどる。=HYPERMEDIA
    • 普通のWebと一緒
      • ワークフローがあるから破綻しない
      • 人間は画面に表示される内容を目で見て判断して処理を行っている
  • HTMLクローラー
    • リンクをたどって情報を取りに行く
      • SEO用のMicrodata(htmlのタグ)を使ってる
        • ドキュメントの中に構造化データを埋め込んでいる
    • HTMLはAPIのデータ提供形式として利用できる
      • クライアント的には大変。JSON使いたい。
  • hypermicrodata gem
    • HTMLをサーバーサイドでJSONに変換
    • 状態遷移図を作って設定
      • ブラウザと同じイメージで作ること
  • HTMLじゃなくてJSONを書くときの注意
    • 状態遷移図を使うこと
    • 疎結合のためmodel.to_jsonはやめること
    • リンクとフォームを持ったJSONテンプレートを使うこと
  • まとめ
    • Web APIはHTML Webアプリと同じように設計しよう
    • RESTの制約・原則を意識するともっとうまくできる

感想:API設計で問題となる仕様変更についてのスマートな解決方法を学ぶことができた。クライアントが「次に読むべきURI」をアドレスではなくHTML内の文字で示すという考え方は面白い。「え?それってスクレイピングじゃ...?」という疑問に対しても「hypermicrodata.gem」という解決方法を準備してくれているのも素晴らしい。期限を設けてv1,v2...とバージョン番号で区切るしか無いと思っていたAPI仕様変更に対する問題に光明が差した気がした。

2日目に続く...

RubyistはWindowsに帰っておいで -Vagrantを使ったWindows開発環境-

Windowsマシンを組み立てたった!

ASP.NETに興味が出てきたので久々にWindowsPCをアップグレードした。CPUはCore2QuadからCorei5(4590)に、OSはVistaからWindows8.1に変わった。特に大きなハマリも無くすんなりアップグレード完了。最近のマシンの起動は本当に速い。昔はBIOSでいろいろチェックしたのち立ち上がってたのに時代は変わったなぁ。

なぜRailsプログラマMac OSを使うのか?

多くのRailsプログラマがなぜMacを使うか?それは「Unixのような環境」を使いたいためだと思う。HerokuやAWS Elastic BeanstalkのようなPaaSサービスが人気なのは確かだがデプロイされる先はUnix系OSであることに変わりはない。開発環境をデプロイ環境と揃えておくことは開発者としてごく自然の考えだし、デプロイ時のトラブルも少ない。もちろん私も4年以上MacRails開発を行っている。

時代は変わった

本番環境と親和性の高いMacOSだが、最近は開発環境の複雑さによって環境を仮想化し、場合によって切り分ける動きが出てきた。

こんな状況で一台のMacに色々なアプリケーションをインストールして、プロジェクトに応じて起動したり停止したりするのはうんざりだ。今であれば普通にVagrantによる仮想環境で解決しようと思うはずだ。

ならWindowsでいいんじゃない?

はい。Windowsでいけちゃいます。

ポイントは次の通り。

Windows環境はできることが多い

私の場合、Windowsだと幸せが多い

  • DMMでダウンロードした動画(察して)

    なんと、WindowsMediaPlayerとゆー、標準プレイヤーで観ることができる!先行き不安なSilverLightプレイヤーを使わなくていいのはありがたい。

  • RAW現像ソフトSilkypix Developer Studioの動作が爆速

    「爆速」というか単純にMac版が遅すぎるって話なんだけどね...

  • ゲームができる

    バナー広告でよく見かけるWorld of Tanksとかで遊べてしまう。

  • Visual Studioで.NETができる

    あたりまえ。

  • IEで動作確認できる

    マシンを2台用意しなくても、IERailsプロジェクトの動作確認ができるのは大きいと思う。

まとめ

MacVagrantを使って開発環境を切り替えつつRailsやってる人は、Windowsに戻ってきてもいいかもしれない。Windows8.1は表示もシンプルで動作も恐ろしく速く、OS自体のデキはMacOSと比較してとても良いと思う。この夏はぜひWindowsで視野を広げてみよう。

*1:File.exists("config/locales.")のような存在しないファイル/ディレクトリが存在することとして判断されてしまう

Railsのバッチ処理のコツ

はじめに

Railsでギョーミーな仕事を行う上で欠かせないのがバッチ処理です。 日々上位システムから送られてくる膨大なデータを迅速に取り込み、集計処理を行いDBに格納する。上位システムは何層も構成されており、我々が集計処理に使える時間はエンドユーザーが出社してくるまでの数時間... みたいなシチュエーション無いですか?

今回はバッチ処理を行うコツについて書いてみようと思います。

  • 想定される処理

    1. CSVファイルの取り込み
    2. 集計処理
    3. 集計結果をDBに格納

    普通にrake taskを書いて処理できてれば今回の記事は必要ありません。そっとブラウザを閉じて下さい。そうでない場合、多くの人が直面する問題は次のようなものが考えられます。

    1. IDのオーバーフロー
    2. メモリが食いつぶされてバッチ処理が停止

    それでは順番に説明します。

IDのオーバーフロー

大量のデータを日々のバッチで取り込んでいる場合、IDがオーバーフローしてしまう可能性があります。IDの最大値はINT型で2147483647もあるので通常利用している範囲ではオーバーフローすることは考えなくても(※1)大丈夫です。しかし、データの取り込みは追記だけとは限りません。何かの条件でDELETE & INSERTする場合、ID列の寿命は思っていたより早く尽きてしまうでしょう。

※1 毎日10万件のデータを取り込んだとして58年持つ計算。

そんな場合は思い切ってID列を削除してしまいましょう。

# migrationの定義
create_table :sales, :id => false do |t|
  t.references :customer
  t.date :sales_date
  t.decimal :total_sales
end
add_index :sales, [:customer_id, :sales_date], unique: true

IDを削除することの弊害

IDを削除することで、IDのオーバーフローに怯える必要は無くなりました。ActiveRecord::Baseのwhereメソッドによる検索も普通に使えます。findメソッドによるID検索が使えないだけだと思っていると、大きな落とし穴が待ち構えています。それはUpdateができないことです。 この問題を解決するためにはcomposite_primary_keysというgemを利用しましょう。 Modelに次のようにキーを定義することでUpdateが可能になります。

class Sales < ActiveRecord::Base
    self.primary_keys = :customer_id, :sales_date
end

メモリが食いつぶされてバッチ処理が停止

初めは快調に処理が進んでいたのに、だんだん遅くなって停止してしまう。こんな経験はないでしょうか?

f:id:tech-kazuhisa:20140609210754j:plain

▲こうなるともうお手上げ

メモリの消費をチェック

Linuxであればfreeコマンドでメモリの消費をチェックしてみましょう。

$ watch free -m

             total       used       free     shared    buffers     cached
Mem:          8000       6998       1001          0        340       2346
-/+ buffers/cache:       4311       3688
Swap:        10063        414       9649

バッチ実行中にbuffers/cacheのfreeの値がどんどん減っていくようであれば、あなたのバッチ処理は何かがおかしいです。

大きなselectを行わない

Sale.all.each do |sale|
  # 略
end

全てのデータを一気に取得して処理するのではなく、可能であれば小さい単位に分割しましょう。

Shop.all.each do |shop|
  Sale.where(shop_id: shop.id).each do |sale|
    #略
  end
end

適切な粒度でバルクインサートを行う

このような処理はメモリを食いつぶす原因となります。

Sale.all.each do |sale|
  OtherSale.create!(total_sales: sale.total_sales, ...)
end

ActiveRecord.importを利用してバルクインサートを行いましょう。その際に、全てのレコードをインサートするのではなく適切な粒度になるよう気をつけましょう。

Sale.find_in_batches do |sales| # 1,000件ずつ取り出す
  list = []
  sales.each do |sale|
    list << OtherSale.new(total_sales: sale.total_sales, ...)
  end
  OtherSale.import list
end

最後に

バッチ実行中にだんだん遅くなっていく現象は、テスト段階では気づきにくいものです。本番運用が始まる前にかならずダミーデータを作成して検証を行うようにしましょう。

Jenkinsでmaster-slave間の通信が不安定なときはslave.jarの起動オプションを疑え

現在、awsのspot instanceを利用してRailsプロジェクトのテストを並列実行しようと試行錯誤しています。

なぜだかmaster-slave間の通信が不安定で困っていたのですが、ようやく打開策を見つけました。

  • 症状

    • slave側のテストの状況がモニタリングできなくなる
    • slaveの処理が止まっているわけではないみたい
    • nodeの接続がすぐに切れるわけではないが、しばらくすると切れてしまう
  • ログの状況

    • 不安定なときのnodeのログは次のようになっていました。
[04/24/14 20:29:44] [SSH] ip-172-16-2-101.ec2.internal:22とのSSHコネクションをオープン
[04/24/14 20:29:44] [SSH] 認証成功
[04/24/14 20:29:45] [SSH] リモートユーザーの環境:
AWS_AUTO_SCALING_HOME=/opt/aws/apitools/as
AWS_CLOUDWATCH_HOME=/opt/aws/apitools/mon
AWS_ELB_HOME=/opt/aws/apitools/elb
AWS_IAM_HOME=/opt/aws/apitools/iam

(略)

[04/24/14 20:29:45] [SSH] javaのJavaバージョンをチェック
[04/24/14 20:29:45] [SSH] java -version returned 1.7.0_55.
[04/24/14 20:29:45] [SSH] sftpクライアントの開始
[04/24/14 20:29:45] [SSH] 最新のslave.jarをコピー中...
[04/24/14 20:29:45] [SSH] 404,201 バイトコピー.
Expanded the channel window size to 4MB
[04/24/14 20:29:45] [SSH] スレーブのプロセスを開始: cd "/media/ephemeral0/jenkins" && java  -jar slave.jar
<===[JENKINS REMOTING CAPACITY]===>channel started
Slave.jar version: 2.39
これはUnixのスレーブです。
Effective SlaveRestarter on ip-172-16-2-101.ec2.internal: null
Slave successfully connected and online


Apr 24, 2014 9:28:47 PM hudson.slaves.ChannelPinger$1 onDead
INFO: Ping failed. Terminating the channel.
java.util.concurrent.TimeoutException: Ping started on 1398342287626 hasn't completed at 1398342527626
        at hudson.remoting.PingThread.ping(PingThread.java:120)
        at hudson.remoting.PingThread.run(PingThread.java:81)

Ping failed.だそうです。

  • 解決方法
    • slave.jarの起動オプションに-textをつける。具体的には[Jenkinsの管理] - [ノードの管理] - (ノードを選択) - [設定] でSuffix Start Slave Command-textをつける。頭にスペースを入れること!

f:id:tech-kazuhisa:20140426193629j:plain

  • Distributed builds - 日本語 - Jenkins Wiki によると

    スレーブ起動のために、telnetのような (バイナリデータを直接扱えない) binary-unsafe なリモート操作用のメカニズムを使っているなら、 slave.jar の実行時に -text オプションを追加して下さい。

とあります。うーん。Macでmaster-slave構成を組んでいた時は何も問題が無かったんだけどな。ともあれ、slaveとの通信が不安定なときはtextモードを試してみましょう。

xip.ioの便利さに気づく

docker - Vagrantでdokkuを動かす - Qiita この記事の中に出てくるxipってのがよく分からなかった。 ググってもこんな人達がたくさん出てきて意味不明。

しかし、しばらくいじってみると使い方がだんだん分かってきた。IPアドレスサブドメインとして指定すると、IPアドレスを返してくれるサービスらしい。

$ ifconfig
(略)
inet 192.168.68.9 netmask 0xffffff00 broadcast 192.168.68.255
(略)

$ ping 192.168.68.9.xip.io
PING 2kkse8.xip.io (192.168.68.9): 56 data bytes
64 bytes from 192.168.68.9: icmp_seq=0 ttl=64 time=0.054 ms
64 bytes from 192.168.68.9: icmp_seq=1 ttl=64 time=0.034 ms
64 bytes from 192.168.68.9: icmp_seq=2 ttl=64 time=0.100 ms

$ ping konami.192.168.68.9.xip.io #頭に文字を付けてもよし
PING konami.2kkse8.xip.io (192.168.68.9): 56 data bytes
64 bytes from 192.168.68.9: icmp_seq=0 ttl=64 time=0.059 ms
64 bytes from 192.168.68.9: icmp_seq=1 ttl=64 time=0.079 ms
64 bytes from 192.168.68.9: icmp_seq=2 ttl=64 time=0.079 ms

手元でVirtualHostによるアプリ切り替えが便利そう。 って、ここまで書いて思い出したけど昔Powを使ってた時にちらっと見たような気もするな〜。