2007-11-09 色々テスト中
とりあえず、rubyにmysqlのdbiを入れる
◆ [日記][FreeBSD] とりあえずmysqlにtDiaryテスト用のユーザとデータベースを作成してみる。
mysql -h IP -P port -p -u root
デフォルトポートで動かしてる時は-P portは省略可能
と、ここまでやって、rootはlocalhostからしかアクセス許可を出していない事に気づいて、dbサーバにログインしてmysql -p -u rootとしてログイン。
まずはデータベースを作成。tdiary_blog_testというDBを作成する。
create database tdiary_blog_test;
次に、こんな感じでユーザ(tdiary_testuser)を追加
grant select,insert,delete,update,create,drop,
alter,index on tdiary_blog_test.* to tdiary_testuser@アクセス元IP
identified by 'パスワード';
flush privileges;
これで、特定のIPからログインできるtdiary_blog_testuserができあがる。
ちなみに、ユーザを消す時は
drop user ユーザ名
データベースを消す時は、
drop database データベース名
らしい。
んでもって、新しく作ったユーザでログインできる事を確認。
mysql -h IP -P PORT -p -u tdiary_testuser
んでもってtDiary:dbi_ioに従って必要そうなテーブルを作る。
use tdiary_blog_test;
CREATE TABLE DiaryData (
diary_id varchar(8) NOT NULL,
year varchar(4) NOT NULL,
month varchar(2) NOT NULL,
day varchar(2) NOT NULL,
title LONGTEXT,
last_modified BIGINT NOT NULL,
visible BOOLEAN NOT NULL,
body LONGTEXT NOT NULL,
author LONGTEXT,
style LONGTEXT,
CONSTRAINT DiaryData_pkey PRIMARY KEY (diary_id)
);
CREATE INDEX diary_id_DiaryData_key ON DiaryData (diary_id);
CREATE TABLE CommentData (
diary_id varchar(8) NOT NULL,
name LONGTEXT,
mail LONGTEXT,
last_modified BIGINT NOT NULL,
visible BOOLEAN NOT NULL,
no BIGINT NOT NULL,
author LONGTEXT,
comment LONGTEXT
);
CREATE INDEX diary_id_CommentData_key ON CommentData (diary_id);
CREATE TABLE RefererData (
diary_id varchar(8) NOT NULL,
count BIGINT NOT NULL,
ref LONGTEXT NOT NULL,
no BIGINT NOT NULL,
author LONGTEXT
);
CREATE INDEX diary_id_RefererData_key ON RefererData (diary_id);
と、一気に作った。PostgreSQLと違って、テーブル名の所には"がいらないとか、varcharは短すぎるだろう(最大256文字ってどうよ)ということでLONGTEXT(Max 4G)にしてみたり、bool型が無くてboolean型にしてみたり、int8じゃなくてBIGINTにしてみたり位のいじり方で出来たっぽい。
というわけで、tDiary:dbi_ioにあるソースコードもテーブル名を囲っている\"を片っ端から外した。
んでもって、変更後のdbi_io.rb(勝手に_を付けた)を~/tdiary/の中へ放り込む。ちなみにdefaultio.rbとかがあるディレクトリーな。
んで、~/tdiary.confにこんな行を追加。
require 'tdiary/dbi_io'
@io_class = TDiary::DbiIO
@pgsql_driver_url = 'dbi:mysql:database=tdiary_blog_test;socket=inet;host=IP;port=PORT'
@pgsql_user = 'ユーザ名'
@pgsql_passwd = 'パスワード'
最初、socket=inetを指定してなかったり(違うサーバに読みに行くからunix socketじゃダメなんです)、IPを間違えたりしながらも、何とか動く。
ここまでやって'mysql' (DBI::InterfaceError)となる事に気づく。むむっ。
/usr/ports/databases/ruby-dbd_mysqlでもmake installが必要な様だ。
あと、テーブル作成の時に、ほっとくとMyISAMになるので、type=InnoDB;と最後に付け加えるか、alter table テーブル名 type=InnoDB;をやるとInnoDBが使える様になる。今回はめんどくさいのでMyISAMのままで。
ここまでやって、トップページが表示できる事を確認。
よしよし。
次の課題は、現在のファイルからDBへの移行だ(笑)
その前に、適当にテスト文章を入力してみた。
Plugin Error
Plugin error in '01sp.rb'.
Plugin error in 'misc/plugin/title-navi.rb'.
なぬん。
トップページを表示
argument out of range (ArgumentError)
./tdiary.rb:1693:in `local'
./tdiary.rb:1693:in `initialize'
index.rb:63:in `new'
index.rb:63
なぬん!?
……とりあえず、contribにマージされてる様なので、そっちを使う事にする。
dbi_io.dbを~/tdiary/に上書き、~/pluginにrefererDbiIO.rbを放り込む。
何かテーブル構造も変わってる(笑)ので修正。
例によってmysqlで通らないところはちまちまと書き換えた。
TEXTが通らないのでLONGTEXTに。INTEGERじゃなくBIGINTに。
CONSTRAINT diarydata_pkey PRIMARY KEY (author,diary_id)が通らないので、CONSTRAINT diarydata_pkey PRIMARY KEY (diary_id)に(いいのか?と思うが、一人でしか使わないのでおそらく問題は無かろう。)
ついでにCREATE INDEX diary_id_diarydata_key ON diarydata (diary_id);を追加。
以下同様の変更で3テーブル作った。
んでもって何かtdiary.confも書き換えが必要らしいので
@dbi_driver_url = 'dbi:mysql:database=tdiary_blog_test;socket=inet;host=IP;port=PORT'
@dbi_user = 'ユーザ名'
@dbi_passwd = 'パスワード'
@dbi_author = 'ituki'
今度は違うエラーが出た。
Table 'tdiary_blog_test.DiaryData' doesn't exist (DBI::DatabaseError)
ぉぃ!
というわけで、ソースコードを追いかけたらDiaryDataと大文字になってるところを発見したので、小文字に変更。
お、今度こそ動いたー。
早速負荷をかけてみる。
Too many connections
orz
とりあえず、DBサーバのmysqldの項目にmax_connections = 500とか書き込んでmysqlをリスタート。んで、再度負荷をかけてみる。
300秒で4105回OK。
はやっ!
このレベルになると、プロセスのforkにかかる時間も馬鹿にならなくなってくる事が分かった。
とりあえず、DB移行するために現在の日記データをDBに喰わせてみる。
スクリプトを作ろうと思ったがめんどくさいので(笑)何か手段はないか探してみる。
misc/convert2.rbのPStoreIOの部分をDeaultIOにすればいけそうだね
と言うのを発見。早速試してみる。
require 'tdiary/defaultio'をrequire 'tdiary/dbi_io'に書き換え、DefaultIO::newをDbiIO::newに書き換え。
~tdiaryでruby misc/convert2.rb
……あー。まちごーた。
require "#{PATH}/tdiary/pstoreio"をrequire "tdiary/defaultio"に書き換え、PStoreIO::newをDefaultIO::newに書き換えて再トライ
お、動いてるっぽい挙動をした(笑)
うむ、うまくいったようだ。
というわけで、一番重いページでテストしてみる事にした。20060615.htmlな(笑)
結果、300秒で3329回。おぉ、かなりいい感じな速度になってる。
fork & execの時間を減らす為にFastCGIを使ってみることにする。
/usr/ports/www/mod_fastcgiでmake install。/usr/local/etc/apache2/httpd.confに#LoadModule fastcgi_module libexec/apache2/mod_fastcgi.soという行が追加されているので先頭の#を外す。で、apachectl restart
んでもって、nemuiDoc: 既存のCGIを変更無しでFastCGIに当たりを読んで、index.fcgiを作る。
内容はこんな感じ
index.fcgi
#!/usr/bin/env ruby
require 'fcgiwrap'
FCGIWrap.each {
load '~tdiary/index.rb'
}
で、RubyForge: FastCGI for Ruby: ファイルリストから、fcgiwrap-0.1.5.tgzをDLしてきて、中のrbファイルを~tdiary/に置く。
portsにあったので、それを使う。/usr/ports/www/ruby-fcgiwrapでmake installするとかってにfcgiも入る。
んでもって、.htaccessにこんな行を追加
<Files "index.fcgi">
SetHandler fastcgi-script
</Files>
一回試してみる。
ついでに、普通にアクセスしたときにindex.rbではなくindex.cgiを読み込みに行くように変更。実は最初はindex.fcgiではなくfindex.rbだったのだが、拡張子が.cgiと.rbはスクリプトとして実行されるため、おとなしくindex.fcgiになおした(笑)
で、アクセスしてみた。
考え込んだ後Internal Server Errorになる(汗
ちなみに
server "~tdiary/index.fcgi"has failed to remain running for 30 seconds given 3 attempts, its restart interval has been backed off to 600 seconds
FastCGI: comm with (dynamic) server "~tdiary/index.fcgi" aborted: (first read) idle timeout (30 sec)
とか言われる。何か間違っているらしい。
色々調べた結果、ほっとくとsuexecを使わずに動くらしい。なめんな!
というわけで、その設定を探しに行く。
FastCGI 化というページに回避策(?)がのっていた。
FastCgiWrapper /usr/local/sbin/suexec
こんな記述が(多分httpd.confに)必要らしい。というわけで/usr/local/etc/apache2/httpd.confに追加。
<IfModule mod_fastcgi.c>
FastCgiWrapper /usr/local/sbin/suexec
</IfModule>
これで動くようになった。
早速、mod_rewriteの設定を書き換えてみる。
RewriteRule ^([0-9]+)\.html$ index.fcgi?date=$1
RewriteRule ^$ index.fcgi
RewriteRule ^index\.html$ index.fcgi
んでちゃんと走ることを確認。
よしベンチマークだ!
300秒で……1765回?
……遅くなってる(汗
何が原因だー と思って調べると、rubyが最大で10個しか立ち上がってない。多分これだー!(笑)
FastCgiConfigを読んで、多分こんなんだろうなー、って設定をhttpd.confに追加
FastCgiConfig -minProcesses 1
FastCgiConfig -maxProcesses 50
FastCgiConfig -maxClassProcesses 20
当然、<IfModule mod_fastcgi.c>の中ね。
300秒で4358回になった。
maxClassProcessesは増やしすぎても減らしすぎてもダメッポイ。
さて、今度はシステム側のCPU利用率が異様に高くなったわけだが(汗
→システムログを吐かないようにしたら5%ほど落ちた(が、なぜか読み込み成功回数も減った)
後考えられるとしたらネットワーク周り……か。
ちょっと試験的にmysqlとの接続をunix socket使ってやってみる。ぐあ、jailまたぎだとエラーになるのねorz
良い方法を模索中。無い。
諦め。
秒間10アクセスを超えるようになったら考えよう。うん(笑)
→サーバ再起動して、デフォルト設定のwwwは10Mbit/sまでねー、という状態にしたら4390回になった(笑)微妙にあがっとるがな。
→さらに、ローカルのmysqlに投げるパケットに対し、ipfwによるフィルタリングを優先的に実行させると、システム側のCPU使用率が多少減った。これで4400回まで増えた。
ストアドプロシジャーを、とか一瞬思ったが、複雑になるため却下。
重いのはlockf処理か? と解析しながら思ったのでちょっと試してみる。
FastCgiConfig -maxClassProcesses 8
3040回。lockfが重い以上に同時アクセス不可だと遅いっぽい。
20に戻した。
何が重いんだろう……
とりあえず、無理矢理unix domain socketを使おうとして、mount_nullfsやったらエラーになりあがるであんの。
しょうがないので、ちょっとjail環境のマウント先を変更して、jailデータベースのディレクトリ内にwebサーバを入れてベンチマークを取ってみる。
相変わらずsysが多い。
実行結果=2603回……おやぁー?
tcp/ipとあんまりかわらんのぉ(謎
というわけで、環境を書き戻す。むーん。何がネックなんだろうか。
ここまでやって気づいた。
なぜにカウンターは更新されないか(笑)