mysqlでのdbのマスタースレーブに対応するのは厳しいねぇ。
先にいうと、あることはあるけど
メンテされてなくて最新のrailsでは動きませんでし。
そのうち使えるようになるだろうと信じてのメモ書きです。
急いで使うなら自分で作るか、改良する必要になります。
magic multi connections
findする際にモデルの頭に接続名を指定する形。
Master::User.find(:first) Slave1::User.find(:first) Slave2::User.find(:first)
複数のDBコネクションを自由に選択できる柔軟性があるが、単純なマスタースレーブ構成にするにはスレーブをまとめるための一工夫が必要になる。
メジャーなのがこれっぽいが、rails2.1で動かなかった。。
ので使えない。
http://magicmodels.rubyforge.org/magic_multi_connections/
mysql replication adapter
findの引数にスレーブ使うよとオプションを渡すスタイル
マスタースレーブ構成に一番適したスタイルだと思う。
User.find(:first, :use_slave => true)
rails2系では使えないっぽいがバグトラッカーに
rails2系で使えるようにしたパッチがありました。
http://rubyforge.org/tracker/index.php?func=detail&aid=20068&group_id=4116&atid=15778
一応動作したのですが、本番環境で1日おきに例外が。。
ActiveRecord::ConnectionAdapters::CannotWriteToSlave (You attempted to perform a write operation inside a slave-balanced read block.): [FATAL] /vendor/plugins/mysql_replication_adapter/lib/active_record/connection_adapters/mysql_replication_adapter.rb:91:in `ensure_master'
恐らくdbが切断されたときの再接続で失敗する時があるくさい。
開発環境でdb接続を強制切断して何回か試してたまに再現できました。
というわけで使えない。
thinでswfを扱う場合
前書き
publicフォルダにswfをおいた場合に
thinだとcontent-typeがtextになってしまうようです。
これだと携帯でのflash表示が失敗するので(mimeが違うとau,softbankは見れないっぽい。docomoは無視して表示するみたいだが)
そのためflashのmimeをきちんと返すようにする必要があります。
(ちなみにmongrelはswf対応してました)
やり方
thinはRackというWebサーバーを作るフレームワークを使用していて
そこに静的ファイルの扱いをまかせてるっぽいです。
RackのクラスにMime定義のHashがあったので、
そこにswfのmime定義を追加することで解決できました。
(Rackは勉強してないんで、もっといいやり方があるかもしれません。。)
environment.rb
#mongrelだとエラーでたのでif文きりわけ if defined? Rack::File::MIME_TYPES Rack::File::MIME_TYPES["swf"] = "application/x-shockwave-flash" Rack::Directory::MIME_TYPES["swf"] = "application/x-shockwave-flash" end
セッションの自動延長
前書き
セッションはご存知のとおりリクエストがないと一定時間で消えてしまいます。
けどページによってはタイムアウトの時間をとても長くしたい場合があります。
例えばお絵かきツールで大作を描いたり。。メール文面入力ページで緻密に計算されたラブレターを書いていたり。。などなど。(消えちゃったら発狂しますね)
なのでそのページだけはタイムアウトをなくしたいです。
やり方
ajaxで定期的に裏でリクエストを発行すれOKです。
リクエストのたびにセッションの有効期限が延長されます。
util_controller.rb class UtilController < ApplicationController def extend_session_expire # 特になにもしない。 render :text=>"ok" end end
自動延長したいview
<%-- javaスクのライブラリロード --%> <%= javascript_include_tag :defaults %> <%-- 特定のurlを定期的にたたくコード。この場合10分間隔。 --%> <%= periodically_call_remote :url=>{:controller=>"/util", :action=>"extend_session_expire"}, :frequency => 10.minute %>
cache_fuのconfについて。memcached.yml
(ちなみに全部の説明はありません。適当にピックアップしました。)
#trueにするとsessionの格納先がmemcacheになります。 sessions: trueかfalse #セッションのmemcacheサーバーを別にしたい場合は指定する。 #一緒でいい場合はfalseを指定(デフォルト) session_servers: 192.168.xxx.xxx:11211 #フラグメントキャッシュの格納先をmemcacheに切り替える。 fragments: trueかfalse #trueにすると早くなるっぽい。 #その代わりruby以外のクライアントとの互換性がなくなるっぽい。 #hashの実装を変更して実現してるみたい。 fast_hash: falseかfalse #trueにするとfast_hashするより早くなるっぽい。 #その代わりfast_hashより互換性の条件が悪くなり、 #同じruby同士でもos等のアーキテクチャが違うってもだめっぽい。 #hashの実装を単純なrubyのhashにしているみたい。 #ってことは恐らくアーキテクチャによってhashの実装が違うんでしょう。 #他アプリと連携しないで複数サーバーも同じOSを使うならこれはonにして #よいんじゃないでしょうか。 fastest_hash: trueかfalse
sessionsをtrueにした場合は下記を適用しましょう。
- application.rbのprotect_from_forgeryの:secretのコメントを外す
- deveropment.rbで有効期限を設定
- ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.merge!-({'expires' => 30.minute })
ちなみにデフォルトで用意されてるmemcached.ymlは
:defaultsとdevelopment:の両方でsessionとfragmentsをfalseにしてあるので
:defaultsだけtrueにしても反映されません。(動かねーじゃんと一度やっちゃいました)
セッションの格納先をmemcacheにする。
やり方
memcache-clientのgemをインストール(追記あり)
gem install memcache-client
追記(2008/11/20)
rails2.1からはmemcache-clientが同梱されていました。(rails2.0にはなかったです)
なのでgemのインストールは不要になりました。
activesupportの中にありますソース見た感じ一緒でした(ちょびっとリファクタしてるっぽかったですが)。
ruby_lib\gems\1.8\gems\activesupport-2.1.2\lib\active_support\vendor\memcache-client-1.5.0
enviroment.rb
(省略) Rails::Initializer.run do |config| (省略) config.action_controller.session = { :session_key => '_アプリ名_session', :secret => 'セキュアな文字列(ランダムな文字列等)' } config.action_controller.session_store = :mem_cache_store (省略) end memcache_options = { :namespace => "アプリ名-session-#{ENV['RAILS_ENV']}", :readonly => false } SESSION_CACHE = MemCache.new([ APP_CONF_SESSION_MEMCACHE_HOST ], memcache_options) ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.merge!({ 'cache' => SESSION_CACHE, 'expires' => 30.minute })
memcache_optionsに渡せるoptionは3つらしい(ソース見た感じ)
:namespace、:readonly、:multithread
(rails1.2 までは別のライブラリRuby-MemCacheというのを使っていたので引数が少なくなってるらしい
昔は:compression、:debug、:urlencodeがあった。
)
CookieStoreから変更したので
application.rbのprotect_from_forgeryの:secretのコメントを外す。
class ApplicationController < ActionController::Base helper :all # include all helpers, all the time # See ActionController::RequestForgeryProtection for details # Uncomment the :secret if you're not using the cookie session store protect_from_forgery :secret => 'セキュアな文字列(ランダムな文字列等)'
以上で完了
いろいろググって調べたつもりだけど
大抵下記のオフィシャル情報をみんな見てやってるらしい。
http://wiki.rubyonrails.org/rails/pages/HowtoChangeSessionStore
けどこれだとtimeoutのexpiresが指定されていなく、デフォルトの0秒が使われてしまう。
なんか1日たってもログアウトしないなーと思ってたら永遠の設定らしい。。(よくあるデフォルト値が30分とかではなかった。。)
ググってもわからなかったのでソースを見たら
DEFAULT_SESSION_OPTIONSにexpiresという引数があったので、それを指定したらうまくいった!
expiresのために参照したソース
\ruby_lib\gems\1.8\gems\actionpack-2.1.2\lib\action_controller\session\mem_cache_store.rb
acts_as_paranoidで関連を扱う場合
acts_as_paranoidとはモデルを論理削除できるようにするrailsプラグインです。
簡単な使用では問題ないのですが
関連を使った場合には消したデータを見てしまう可能性がありました。
やりたいこと
例として学校クラスと生徒クラスがあったとして
学校を削除できたとする。(過疎化、少子化のせいですかねぇー)
この場合に生徒一覧を取得する、但し削除した学校の生徒は出さない
といったことをする
クラス
class School < ActiveRecord::Base acts_as_paranoid has_many :students end class Student < ActiveRecord::Base belongs_to :school end
方法と結果
1番
School.students.find(:all)
OK.問題ない
2番
Student.find(:all, :include=>:school, :condition=>"school.created_at > '2001/1/1'")
NG.削除した学校の生徒も取得してしまう
3番
Student.find(:all, :include=>:school)
OK.これは大丈夫
説明
このプラグインはacts_as_paranoidと定義してあるモデルからfindした場合にしか
発動しないらしい。(なんちゃってソース見で)
そのため2番目のがNGになる。
(Studentにはacts_as_paranoidを定義していないせい)
では、3番目のがOKになるのは何故か?
それは恐らくrails2.1だからだろう。
rails2.1から単純な結合はjoinを使った1回のsqlではなく
各モデルに対する2回のsqlに分けるようになったためだ。
動作としてStudentを取得するsqlを発行後に、Schoolを取得するsqlを発行する。
ということでShoolに対してfindしてるのでacts_as_paranoidの対象となる。
じゃあ、何故2番目の例がNGになるかというと
conditionに結合先の条件が入っているためだ。この場合はrails2.0以前のものと動作が同じになり
joinする1回のsqlになる。
2番目の場合の回避策としてはconditionに明示的にdeleted_at is nullとのチェック処理を入れることで
対応できる。(まぁ、あたりまえですねぇ。。自動で関連先も見る機能がほしいけどやっぱ複雑なんだろうなぁ。。)
実行環境
rails2.1.1
HPの激安サーバー&freenasで4TBのnasを安価に作る
家のIOデータの1.6T NASに容量と速度の面で限界を感じたので
作ってみました。
使ったもの
- PC
- HPの激安サーバー
- 14,800円(送料無料)
- HP-ProLiant-ML115 G5
- http://www26.atwiki.jp/ml115_g5/
- HDD
- 1TBのを4つ(WDの省エネなやつ)
- 11000円*4=44000円
- OS
- FreeNas 0円
- Nasに特化したフリーのOS(元はFreeBSD)
- ちなみに0.69b2で動作確認。
- 0.69b3、0.686.4はデフォルトでは起動せず(オプションいじればできるらしい?)。
- その後起動後のメニューからのファームウェアアップで0.69b4にアップして問題ないのを確認。
- なので0.69b4でもインストールできるかも。
- 参考URL
- 公式 DLはこちらから http://www.freenas.org/
- インストール等マニュアル http://www.freenas.org/index.php?option=com_openwiki&Itemid=30&id=sug:jp
- Think It 第4回:FreeNASでストレージ専用機の構築 http://www.thinkit.co.jp/article/80/4/
raid5を使いました。なので実質は3TB。安全性のため多少は仕方がない。
速度のほうは
今回作ったNAS
Sequential Read : 51.108 MB/s
Sequential Write : 62.798 MB/s
Random Read 512KB : 51.409 MB/s
Random Write 512KB : 31.290 MB/s
Random Read 4KB : 9.969 MB/s
Random Write 4KB : 1.672 MB/s
Test Size : 100 MB
今までのIOのNAS(遅っ)
Sequential Read : 9.048 MB/s
Sequential Write : 12.973 MB/s
Random Read 512KB : 9.533 MB/s
Random Write 512KB : 17.320 MB/s
Random Read 4KB : 2.631 MB/s
Random Write 4KB : 2.767 MB/s
Test Size : 100 MB
CrystalDiskMarkにて測定
http://crystalmark.info/software/CrystalDiskMark/
体感的速度的にも写真を見る速度があがったり、動画閲覧の速度が上がったり
速度アップのメリットを実感できました。
速度計るときの注意点
今回vistaで速度を計ったんですが、最初は10MB/s程度しかでなくてショック受けたんですが
vistaの落とし穴でした。
なんと音楽再生中は(winamp立ち上げてたんですが)ネットワークの速度が制限されるとのこと。
なので100MLANなら気がつかないですが、今日のギガLANの時代だと強制的に100MLANと同じ速度になるみたいです。
治し方
レジストリで
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Multimedia\SystemProfile
に、NetworkThrottlingIndexという名前のDWORD値を0xffffffffにする。
参考元
http://blogs.yahoo.co.jp/chototsu_moushinp/32348055.html
http://windowsvista.ms/index.php?FAQ#cde892fa
消費電力
まとめ
今までの売って4万になるみたいなので
追加2万でこんなにパワーアップするとは満足でした。
作ってよかったー!!