Browse Month: April 2011

“ソーシャル”なサイト構築のためのWeb API コーディングを一部執筆しました

2011年4月22日に発売された「ソーシャル”なサイト構築のためのWeb API コーディング 」という Web API に関する本を一部執筆しました。Twitter、Flickr、Amazon、YouTube、の Web API の入門編を執筆しました。特に Twitter は OAuth を含む認証手順をシンプルに解説していますので、Web API プログラミングに興味のある方はぜひご覧ください。

Rails 2.0 から 2.3 へバージョンアップしたときの話

仕事の Rails なアプリケーションが昔からあってバージョンが 2.0.2 くらいだったけれど、Rails3 も無事リリースされているし、そろそろ重い腰を上げてバージョンアップしないといかんと思って、まずは 2.3.11 へバージョンアップしてみたときの話。メジャーバージョンが 2 系のままなので、それほど大変ではなかったけれど、既存で使っている gem の差し替えがけっこう大変だった。

まずは、config/environment.rb を、次のように変更する。

RAILS_GEM_VERSION = '2.3.11' unless defined? RAILS_GEM_VERSION

Rails 2.3 から、bundler がサポートされているので、公式ページをみながら作業する。config/preinitializer.rb を作成して、RAILS_ROOT に Gemfile を作成する。Gemfile は、仕事の環境では自前の gem を含めた gem のミラーを作成してあるので、gem のインストール先を変更してあります。下記の URL は例です。

Gemfile

source 'http://rubygems.example.com/rubygems'
gem 'rails', '2.3.11'
gem 'mysql', '2.8.2'
gem 'nokogiri', '1.4.4'
gem 'rmagick', '2.13.1', :require => 'RMagick'
gem 'will_paginate', '2.3.15'

そして、RAILS_ROOT で bundle install するだけだけれど、mysql gem が mysql_config コマンドの場所が分からなくてエラーになってしまうので、事前に次のコマンドを実行する。


$ cd RAILS_ROOT
$ bundle config build.mysql --with-mysql-config=/usr/bin/mysql_config

これで bundle install すれば、Rails 2.3.11 がインストールされる。bundler を使えば、ちゃんと特定のバージョンの gem を使ってくれるし、RAILS_ROOT 以下に gem がインストールされるし、サーバ側で gem を管理しなくても済むので、とても便利です。(今まで一生懸命 puppet manifest に記述してあったので、ごそっと削除した。)サーバ側で管理する gem は、bundler と passenger くらいになった。

Rails アプリケーションをバージョンアップするのも忘れずに。

$ rake rails:update

次に、既存の gem を入れ替え作業にした。まずは、データベースまわりは仕事環境で 2 系統の mysql master – slave 構成になっているため、Rails 2.0 の頃は ActiveRecord cluster というのを使っていた。このライブラリはもうメンテナンスされていないので、探してみたところ data_fabric という gem を見つけた。この他にも 1 系統の master – slave 構成をサポートしている gem は見つかったけれど、2 系統の master – slave 構成をサポートしているのは data_fabric だけの様子だった。

data_fabric の使い方は、github のページに詳しく書かれているし、サンプルの Rails アプリケーションもあるので、すぐに使うことができると思う。まず、Gemfile に、data_fabric を使うように追加する。

gem 'data_fabric', '1.3.1'

database.yml は、次のようにする。次の例では、メイン系統のデータベース(master: 192.168.1.1, slave: 192.168.1.2)と cluster1 という系統のデータベース(master: 192.168.1.10, slave: 192.168.1.11)が、それぞれ master – slave 構成存在している場合の設定方法です。いくつか設定が重複しまうのは微妙だけれど、これは仕方がない。

development:
adapter: mysql
database: test_dev
host: localhost
username: root
password:
encoding: utf8
hoge_development:
adapter: mysql
database: test_dev
host: localhost
username: root
password:
encoding: utf8
production:
adapter: mysql
database: test_production
host: 192.168.1.1
username: hoge
password: hoge_password
encoding: utf8
production_master:
adapter: mysql
database: test_production
host: 192.168.1.1
username: hoge
password: hoge_password
encoding: utf8
production_slave:
adapter: mysql
database: test_production
host: 192.168.1.2
username: hoge
password: hoge_password
encoding: utf8
cluster1_production:
adapter: mysql
database: cluster1_production
host: 192.168.1.10
username: hoge
password: hoge_password
encoding: utf8
cluster1_production_master:
adapter: mysql
database: cluster1_production
host: 192.168.1.10
username: hoge
password: hoge_password
encoding: utf8
cluster1_production_slave:
adapter: mysql
database: cluster1_production
host: 192.168.1.11
username: hoge
password: hoge_password
encoding: utf8

application_controller.rb に、次のコードを追加する。

around_filter :select_shard
private
def select_shard(&block)
yield
end

開発環境のときは slave がないため、その設定を吸収する関数を定義しておく。

def get_replicated
(RAILS_ENV == 'production') ? true : false
end

あとはモデルを ActiveRecord Cluster を使った記述から data_fabric を使った記述に変更するだけとなる。
メイン系統のモデルは、次のようにする。

class Model1 < ActiveRecord::Base data_fabric :replicated => get_replicated
...
end

cluster1 系統のモデルは、次のようにする。prefix をつけるだけ。

class Model10 < ActiveRecord::Base data_fabric :prefix => 'cluster1', :replicated => get_replicated
end

そして、Passenger で動かすと「undefined method disconnect! at DataFabric::PoolProxy」というエラーが出てしまうということで作者の人に問い合わせてみたら、すぐにバージョンアップ(バージョン 1.3.1)にしてくれた。このバージョンで問題なく、Rails 2.3.11 + Passenger の環境で今でもちゃんと動いている。

次に gettext まわり、Rails 2.3 だと i18n という仕組みを使う方式に変更になっている。既存の gettext の仕組みを使う必要があったので、Gemfile に次の gem を追加した。

gem 'gettext', '2.1.0'
gem 'gettext_activerecord', '2.1.0'
gem 'gettext_rails', '2.1.0'
gem 'i18n', '0.5.0'
gem 'locale', '2.0.5'
gem 'locale_rails', '2.0.5'

さらに application_controller.rb に、次を追加した。

init_gettext "hoge"

before_filter :set_locale_info
def set_locale_info
set_locale("ja")
end

この他、最初に読み込まれる方法がかなり変わっていたので、config/environement.rb や config/initializers を整理した。

あと db の migrate ファイル名の形式が変わっているので、念のため既存の db migrate のファイル名を変更する即興プログラムを書いて対応した。もちろん、本番サーバでは db:migrate はリスクが大きすぎて実行はしていない。
あわせて、schema_info テーブルから schema_migrations テーブルに変わっているため、念のため本番サーバを修正しておく必要がある。
schema_migrations テーブルを作成する。

mysql> CREATE TABLE `schema_migrations` (`version` varchar(255) NOT NULL) ENGINE=InnoDB
drop table schema_info;

そして、また即興プログラムで db/migrate にあるファイル名を取得してバージョン情報を追加するプログラムを本番サーバで実行する。

こんな感じで、無事 Rails 2.0 系から Rails 2.3 系にバージョンアップすることができた。
次のターゲットは、Rails 2.3 系から 3.1 系へのバージョンアップを行う予定。

qpstudy LT 番外編のまとめ

qpstud LT 番外編が 4/9 に開催された。公式ページには、どのような LT が繰り広げられたか一部しか掲載されていないので、ustream からタイトルだけ引っ張ってきてまとめてみた。 あくまで usteam のアーカイブから調査したものなので、アーカイブは削除される可能性もありますのでご注意してください。

@iara : 開会の辞
@ar1: インフラエンジニアの春
@gogotea3: 仮想自宅サーバのすすめ(シングル構成編)
@ttkzw: ustream なし
@tmae: ustream なし
@ysaotome: @nifiy エンジニアサポートはじめました
@yuuitiro: 運用チームの情報共有どうしてます?
@H_Shinonome: きっかけはネットワーク #nwstudy の紹介
@ayakomuro: qpstudy LT 一周年記念LT大会!
@sechiro: 俺のZabbixがこんなに可愛いわけがない Lite
@petach: Thuderbirdアドオンつくりました
@minky0: インフラエンジニアのためのインフラネットワーク入門
@nagi2100: 自宅のITインフラ構築
@matsuu: 僕と契約してセキュアなインフラエンジニアになったよ 〜Gnukのすすめ〜
@zembutsu: これはMRTGですか?いいえ、munin です
@sho7650: 災対のお話
@fujiwara: OpenVP超入門
@kerotandesu: ustream なし
@mikeda: 擬○化
@mkouhei: Debianでできる簡単監視システム。
@togakushi: ドキュメント書いていますか?
@hebikuzure: ustream なし
@fujya: OpenVZで始めるDR
@nekoruri: 座席表システム
@ipv6labs: ustream なし
@riywo: qpstudy1周年記念LT
@laughsketch: ざびたんのデザインコメンタリー
@jmorimt: 暗号の2010年問題
@matsudaK: ケーブル
@tk0miya: ドキュメントの図について
@meryo2000: Nify Cloudについて
@yktko: 新人の方に贈るExcel方眼紙の簡単な説明
閉会の辞

 

Twitter IDが違っていたらごめんなさい><

あと、実際にブログなどで資料を公開されている人がいますので、詳細は Twitter を検索するか、qpstudy の公式ツイッターアカウントや公式ブログをチェックするといいと思います。

そういうことで、僕もなぜか1度も LT をしたことがない><、次回あたり機会があれば qpstudy でエロい LT をやりたいと思いますっ(キリッ

 

Velocity カンファレンス 2011

今年も Velocity カンファレンス 2011 が開催されます!公式ページは、こちら(英語)。

Velocity カンファレンスというのは、オライリー主催のおもにウェブサービスにおけるインフラ周りのカンファレンスです。

僕は、2009年に参加しました。そのときのレポートはこちらこちらこちらこちらこちら

まず、Velocity カンファレンス 2011 は、次の日程で開催されます。

日時: 2011年6月14日(火)から16日(木)(アメリカ西海岸時間です)

場所: サンタクララのハイアットホテル(案内はこちら

参加費用: 共通オールパス $1695 から 展示会のみ $25、詳しくはこちら

開催されるホテルは超高級ホテル(上記日程で空き部屋を検索してみたのですが空いていませんでした)なので、自腹でいく場合近場のホテルを Google マップなどで検索して、宿泊するといいと思います。

参加費用は非常に高いので会社負担が普通かと思いますが、自腹でいくとテンションが思いっきり変わりますのでお勧めです!
ちなみに僕のように一度参加したことがある人は %25 引きになります。その他にも学生割引が政府関係者の割引などがあります。

今回の Velocity 2011 のテーマは、次のとおりです。

  • 自動化戦略: Automation  strategies
  • モバイル向けサービスのパフォーマンスの最適化: Optimizing mobile performance
  • クラウドコンピューティング Cloud computing: the good bits
  • JavaScript の高速化 JavaScript speedups
  • 巨大なデータの蓄積と管理 NoSQL や Hadoop Storing and managing big data: NoSQL, Hadoop
  • メトリックスとモニタリング Metrics and monitoring
  • ビジネス面での構築やサポート Building and supporting the business case

カンファレンスのおもな日程は、14日(火)はワークショップ、15(水)・16(木)はセッション、となっています。

ワークショップの中でも、個人的には、Chef の話が興味にあります。

セッションは、モバイルや MCollective や NoSQL やクラウドや HTML5 やスマフォなどの話題が満載です。かなり豪華なセッションになっています。同時に複数のセッションがありますので、事前にどのセッションに行くか決めておく必要があります。事前予約は必須ではないですが、人気のあるセッションの場合は立ち見などもあるかと思います。Velocity 2009 のときは、Facebook のセッションはどれも立ち見でしたね。

この他にも展示会や、BOF などのイベントがあります。

Velocity の魅力はなんといっても、おもにアメリカ現地の Twitter や Facebook や Google のインフラ周りの人と直接あえることだと思います。たとえ、ネイティブのように立派な英語を話すことができなくても、共通の技術に興味を持っているもの人同士だとつたない英語でもちゃんと話を聞いてくれます。
毎年あるキーノートは、今のところ情報が公開されていないので調整中だと思いますが、きっと豪華なキーノートになると思います。

ということで、今年は参加するという人は、ここのブログパーツを貼り付けておくといいでしょう。そして、行った人はぜひブログなどでレポートを書きましょう!

あと、Velocity の公式 Twitter アカウントは @velocityconf になります。

僕は行けるかどうか分かりませんが、もし行くことになったらレポートを書こうと思います。さすがに今年は日本から多くの人が参加されると思いますが。。。個人的には Lisa に行く可能性が高いかもしれないです。


O'Reilly Velocity Conference 2011

Ruby Garbage Collector Performance Tuning

Ruby のガベレージコレクションのパフォーマンスチューニングをする方法に環境変数を指定する方法があります。Ruby Enterprise Edition でも同様の設定が可能なので、パフォーマンスチューニングできるか試してみました。

以下、それぞれの環境変数の意訳です。

  • RUBY_HEAP_MIN_SLOTS: 最初のヒープスロット数です。デフォルトは、10000 です。
  • RUBY_HEAP_SLOTS_INCREMENT: Ruby が最初に新しいヒープを確保するときに必要な確保するために追加するヒープスロットの数です。デフォルトは、10000 です。例えば、デフォルトの GC 設定のとき、ヒープ上に 10000 の Ruby オブジェクトが存在しています。プログラムは他のオブジェクトを生成するとき、Ruby はそこに 10000 ヒープスロットで新しいヒープを確保するでしょう。合計で 20000 ヒープスロットがあると、10001 は使われて 9999 は使われていません。
  • RUBY_HEAP_SLOTS_GROWTH_FACTOR: マルチプリケーターが Ruby が新しいヒープスロットを必要としたときに次回に確保される新しいヒープスロットの数の計算に使われます。デフォルトは、1.8 です。プログラムを例にとると、プログラムは 10000 以上のオブジェクトを生成します。そして 10000 番目のオブジェクトは、Ruby は他のヒープを確保することが必要になります。このヒープは、10000 * 1.8 = 18000 ヒープスロットを持っているでしょう。合計で 20000 + 18000 = 38000 ヒープスロットがあるとき、20001 は使われて 17999 は使われません。次回 Ruby が新しいヒープを確保するとき、18000 * 1.8 = 32400 ヒープスロットはあるでしょう。
  • RUBY_GC_MALLOC_LIMIT: ガベレージコレクションのトリガーなしで確保することができる C データ構造体の量です。もしこの値が低すぎると、ガベレージコレクターは利用可能な空のヒープスロットさえ持って開始されます。デフォルト値は、8000000 です。
  • RUBY_HEAP_FREE_MIN: ガベレージコレクターが実行された後に利用可能であるべきヒープスロットの数です。もし、より少ないヒープスロットが利用可能なとき、Ruby は RUBY_HEAP_SLOTS_INCREMENT と RUBY_HEAP_SLOTS_GROWTH_FACTER パラメータにしたがって新しいヒープを確保します。デフォルト値は、4096 です。

アプリケーションからアプリケーションへベストな設定があります。さまざまに値を計測して実験するべきです。

37signals では、本番環境で次の値になっています。

RUBY_HEAP_MIN_SLOTS=600000
RUBY_GC_MALLOC_LIMIT=59000000
RUBY_HEAP_FREE_MIN=100000

Twitter では、本番環境で次の値になっています。

RUBY_HEAP_MIN_SLOTS=500000
RUBY_HEAP_SLOTS_INCREMENT=250000
RUBY_HEAP_SLOTS_GROWTH_FACTOR=1
RUBY_GC_MALLOC_LIMIT=50000000

Twitter の設定は、次のことを意味しています。

  • アプリケーションを確保するための十分なメモリーを持って開始している
  • 必要な分だけリニアに増やす
  • ガベレージコレクターのみ、毎回 50 百万回 の malloc を呼んでいる

Twitter はこれらの設定を改善して、もっとも多くのメモリを使っているときのピーク時のメモリ使用量を、平均して 20% から 40% 程度のパフォーマンス向上することができた。

この設定を Passenger で変更するには、ここにあるとおり専用のラッパースクリプトを作って PassengerRuby に設定するだけです。

37signals と twitter の設定例をみてみると、多めのヒープスロットを確保している傾向にありますね。

Twitter の最新の設定は、Qcon の資料では次のようになっています。

RUBY_HEAP_MIN_SLOTS=500000
RUBY_HEAP_SLOTS_INCREMENT=250000
RUBY_HEAP_SLOTS_GROWTH_FACTOR=1
RUBY_GP_MALLOC_LIMIT=50000000
RUBY_HEAP_FREE_MIN=4096

ということで調査はここまでにして、自分の Ruby アプリケーションをチューニングしていきたいと思います。