第2回 rsyncを用いたコンテンツの分散

内間 圭介
株式会社Cuon

2008/10/16

Rubyを使った大規模エンタープライズ開発が始まっている。Ruby on Railsでの開発において、インフラやアプリケーションアーキテクチャをどのように構成すべきかを考える(編集部)

 第1回「CGMサイト構築で悩む負荷対策と拡張性の確保」では、CGMサイト構築における負荷対策と拡張性の実例をいくつか紹介した。今回は予定を変更して、rsyncを用いたコンテンツの分散について述べる。

 ここではユーザー投稿画像などのデータを保存するのに、高価なストレージを導入するのではなく、安価なコンテンツ専用サーバをスケールアウトさせていく方法について説明する。

 ここに挙げる方法では、コンテンツサーバをWebアプリケーションサーバにマウントしない方針を採用している。これはRuby on Rails(RoR)が本来想定している環境と異なり、それなりのデメリットもあるが、スケールアウトの容易さを優先させた結果である。

 それでは、コンテンツサーバをWebアプリケーションサーバにマウントせず、rsyncを用いてコンテンツを転送する例を実際のコードを交えて示そう。

コンテンツサーバの分離

 第1回にも述べたが、弊社が開発したコミュニティサイト「ライフパレット」では、画像などを保存するコンテンツサーバをマウントしない方式を採用した。これはWebアプリケーションサーバやコンテンツサーバが増えた場合のマウントの手間を省き、単純なスケールアウトを実現するためである。

 Webアプリケーションサーバに加え、コンテンツサーバもスケールアウトすることを考えると、台数が増え、複数Webサーバ−コンテンツサーバ間で「たすき掛け」形式でマウントが実施された際の信頼性に対する不安がある。またマウントそのものの手間も増大する。

 そこで、より簡潔で単純なスケールアウトを実現するために、コンテンツサーバをマウントするのをやめ、rsyncでWebアプリケーションサーバからコンテンツサーバへ画像を転送することにする。

 コンテンツサーバの情報(サーバのIPやデータ保存先ディレクトリなど)はデータベースに格納し、Webアプリケーションサーバはデータ転送時にこれを参照する。コンテンツサーバが増えた場合には、データベースに新しいコンテンツサーバの情報を追記するだけでいい。なお、Webアプリケーションサーバが増えた場合には、コンテンツサーバに対する作業は発生しない。

 このようにすることで、Webアプリケーションサーバとコンテンツサーバは独立してスケールアウトできるようになる。

 またこの場合、コンテンツサーバに格納された画像は、Webアプリケーションサーバ(mongrel)からは配信されず、コンテンツサーバからロードバランサを通して配信される。

 画像へのURLにはコンテンツサーバの識別子が埋め込まれており、これを見てロードバランサは各コンテンツサーバに画像を要求し、コンテンツサーバに立てられたlighttpdが画像を返す。画像配信に関しては、Webアプリケーションサーバを介さないため、これはWebアプリケーションサーバの負荷分散にもなっている。

file_columnによる画像管理

 画像アップロードとサムネイル生成などのサイズ変更には、Railsでは一般的なfile_columnプラグインを利用している。file_columnプラグインは、アップロードされたファイルの情報を、対象モデルのテーブルカラムに格納する。例えば、記事モデルが画像を1枚持つ場合、以下のような指定をする。

# 記事モデル
class Article < ActiveRecord::Base
  # file_column用カラムの指定(カラム名は "image")
  file_column :image
end

 しかし、このままだと記事が持つ画像ファイルが増えるたびにカラムも追加しなければならない。Railsの場合、マイグレーションの追加・変更が生じてしまう。

 これを解決するため、画像カラムだけを別モデルとして分離する。分離された画像モデルは、記事だけでなく複数の親モデルから参照されることが期待されるので(記事画像、ユーザー画像、コミュニティ画像など)、親モデルとの関連にはポリモーフィック関連を利用する。

 画像モデルを別モデルに分離した場合のコードは、以下のようになる。このコードでは、file_columnのオプションで、画像ファイル保存先の指定やサムネイル生成などをしている。

# 記事(親モデル)
class Article < ActiveRecord::Base
  # 記事は複数画像を持つ(ポリモーフィック関連の関連名は、:parent)
  has_many :images, :as => :parent
end

# 画像モデル
class Image < ActiveRecord::Base
  # 親モデルとの関連(ポリモーフィック関連の関連名は、:parent)
  belongs_to :parent, :polymorphic => true

  # file_column用の指定
  file_column :picture, # カラム名
              :root_path => "#{RAILS_ROOT}/public/store/", # 保存先ディレクトリ
              :web_root => "store/", # Webブラウザから見た保存先ディレクトリ
              :magick => { # サムネイル生成など画像変換

                :versions => {
                  :thumb => { :crop => "1:1", :size => 50x50" },
                  :middle => "240x240>",
                  :large => "640x640>"
                }
             }
end

 ここで説明するfile_columnの基本的な使い方として、上記のようにオプションで画像保存先が指定できることと、以下のように「オブジェクト.カラム名_dir」というメソッドで、画像保存先ディレクトリが取れることが分かっていれば十分である。

$ ruby script/console
>> i = Image.find :first
>> i.picture_dir # ← 画像オブジェクト.カラム名_dir
=> "script/../config/../config/../public/store/image/picture/1"
# ↑ 画像保存先ディレクトリが取れる

# そのほかのメソッドも画像オブジェクト.カラム名[タブ補完]で出てくる

 
1/3

Index
rsyncを用いたコンテンツの分散
Page1
コンテンツサーバの分離
file_columnによる画像管理
  Page2
画像保存先ディレクトリをどう指定するか
file_columnによる動的な画像保存先変更
  Page3
rsyncによる画像転送
実装コストを取るか、運用コストを取るか

RoRでCGMサイト構築虎の巻

 Ruby/Rails関連記事
プログラミングは人生だ
まつもと ゆきひろのコーディング天国
 ときにプログラミングはスポーツであり、ときにプログラミングは創造である。楽しいプログラミングは人生をより実りあるものにしてくれる
生産性を向上させるRuby向け統合開発環境カタログ
Ruby on Rails 2.0も強力サポート
 生産性が高いと評判のプログラミング言語「Ruby」。統合開発環境を整えることで、さらに効率的なプログラミングが可能になる
かんたんAjax開発をするためのRailsの基礎知識
Ruby on RailsのRJSでかんたんAjax開発(前編)
 実はAjaxアプリケーション開発はあなたが思うよりも簡単です。まずはRuby on Railsの基礎知識から学びましょう
Praggerとnetpbmで作る画像→AA変換ツール
Rubyを使って何か面白いものを作ってみよう!
 一般的な画像をアスキーアートに変換するツールを作ってみる。さらに出力にバリエーションを持たせてみよう
コードリーディングを始めよう
Railsコードリーディング〜scaffoldのその先へ〜(1)
 優れたプログラマはコードを書くのと同じくらい、読みこなす。優れたコードを読むことで自身のスキルも上達するのだ
  Coding Edgeフォーラムフィード  2.01.00.91


Coding Edge フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

>

Coding Edge 記事ランキング

本日 月間