今までRDBMSで動いてたRailsアプリをMongoDBにマイグレーションする~的な 話が出てきたので、検証を兼ねて、VirtualBoxのUbuntuにRailsアプリをインストールして、 ActiveRecordとMongoidを両方動かしてみる事にしました。 ■ 環境周り またいつものように環境設定にゴタゴタしまして、、、 ・Rails立ち上げようとしたら、Could not find a JavaScript runtime~とか言われて、 エイヤってapt-get install nodejsとかやっちゃったのですがこちらの記事がドンピシャでした。 ・vimで作業する時にFuzzyFinder使って検索したいな~って思って入れたら動かなくて、 vundlerの定義にL9というのが必要だったりとか。
Bundle 'tpope/vim-rails' Bundle 'The-NERD-tree' Bundle 'quickrun' Bundle 'vim-ruby/vim-ruby' Bundle 'Shougo/neocomplcache' Bundle 'L9' Bundle 'FuzzyFinder'
んま、他にもちょいちょいありましたが、その辺は端折る感じで。。 ■ 使用するデータ データはFluentdを使ってお手軽に集める事にしました。 今回はsquid3をプロキシサーバー(ポートは8888)にしました。
# Squid normally listens to port 3128 http_port 8888
んで、/var/log/squid3/access.logをtailプラグインで集めてきます、と。 なんでSquidのaccess.logにしたかっていうと、たまたま見かけた ↓のブログにグッときてしまったから、、っていう話なのですが。。 fluentdのformat(正規表現)の作り方について試行錯誤中 #fluentd - Glide Note - グライドノート ■ Fluentdのプラグイン fluentdはmongoとmysql用の両方のプラグインがあるので、 ・https://github.com/fluent/fluent-plugin-mongo ・https://github.com/tagomoris/fluent-plugin-mysql それらを使うだけなのですが、特にMongoDBに突っ込むのは設定もチョーお手軽でした。 Fluentd本体もプラグインもgemでサクっと入ります。
# gem install fluentd Fetching: msgpack-0.4.7.gem (100%) Building native extensions. This could take a while...
# gem install fluent-plugin-mysql Fetching: mysql2-cs-bind-0.0.5.gem (100%) Fetching: fluent-plugin-mysql-0.0.2.gem (100%) Successfully installed mysql2-cs-bind-0.0.5 Successfully installed fluent-plugin-mysql-0.0.2 2 gems installed
続いてMongoDB用のプラグイン
# gem install fluent-plugin-mongo Fetching: bson-1.6.4.gem (100%) Fetching: mongo-1.6.4.gem (100%) Fetching: fluent-plugin-mongo-0.6.11.gem (100%) Successfully installed bson-1.6.4 Successfully installed mongo-1.6.4 Successfully installed fluent-plugin-mongo-0.6.11 3 gems installed
データを入れ込むFluentdの設定 ・MySQL(Insert文を書く感じ)
<source> type tail path /var/log/squid3/access.log tag mysql format /^(?<date>[^ ]+)s+(?<duration>.*) (?<address>.*) (?<result>.*) (?<bytes>.*) (?<method>.*) (?<url>.*) (?<rfc931>.*) (?<hierarchy>.*) (?<contenttype>.*)$/ pos_file /root/hoge/fluent/acceess_log_pos_mysql.log </source> <match mysql.**> type mysql host 127.0.0.1 port 3306 database hoge username root password key_names date,duration,address,result,bytes,method,url,rfc931,hierarchy,contenttype sql INSERT INTO mysql_accesses (date,duration,address,result,bytes,method,url,rfc931,hierarchy,contenttype) VALUES (?,?,?,?,?,?,?,?,?,?) flush_intervals 5s </match>
当初は"contenttype"の所をただの"type"にしてたのですが、 ↓のように怒られたのでカラム名変えました。
This error is raised because the column 'type' is reserved for storing the class in case of inheritance
・MongoDB(えらくお手軽な感じ)
<source> type tail path /var/log/squid3/access.log tag squid format /^(?<date>[^ ]+)s+(?<duration>.*) (?<address>.*) (?<result>.*) (?<bytes>.*) (?<method>.*) (?<url>.*) (?<rfc931>.*) (?<hierarchy>.*) (?<contenttype>.*)$/ pos_file /root/hoge/fluent/acceess_log_pos_mongo.log </source> <match squid.**> type mongo database hoge collection mongo_accesses host 127.0.0.1 port 27017 </match>
それぞれFluentdのプロセスを起動して中身が入ってることを確認します。
# fluentd -c access_log_mongodb.conf 2012-12-20 11:56:53 +0900: starting fluentd-0.10.29 2012-12-20 11:56:53 +0900: reading config file path="access_log_mongodb.conf" 2012-12-20 11:56:53 +0900: adding source type="tail" 2012-12-20 11:56:53 +0900: adding match pattern="squid.**" type="mongo"
# fluentd -c access_log_mysql.conf 2012-12-20 11:56:51 +0900: starting fluentd-0.10.29 2012-12-20 11:56:51 +0900: reading config file path="access_log_mysql.conf" 2012-12-20 11:56:51 +0900: adding source type="tail" 2012-12-20 11:56:51 +0900: adding match pattern="mysql.**" type="mysql"
MySQLの件数
mysql> select count(*) from mysql_accesses; +----------+ | count(*) | +----------+ | 1197 | +----------+
MongoDBの件数
> db.mongo_accesses.count(); 1197
いやー、なんともお手軽ですこと。さすがFluentd…。 ■ Railsで使う用のgem gemでmysql2入れようとしたら怒られたから、、、
# gem install mysql2 Building native extensions. This could take a while... ERROR: Error installing mysql2: ERROR: Failed to build gem native extension. /usr/bin/ruby1.9.1 extconf.rb checking for rb_thread_blocking_region()... yes checking for rb_wait_for_single_fd()... yes checking for mysql_query() in -lmysqlclient... no checking for main() in -lm... yes checking for mysql_query() in -lmysqlclient... no checking for main() in -lz... no checking for mysql_query() in -lmysqlclient... no checking for main() in -lsocket... no checking for mysql_query() in -lmysqlclient... no checking for main() in -lnsl... yes checking for mysql_query() in -lmysqlclient... no checking for main() in -lmygcc... no checking for mysql_query() in -lmysqlclient... no *** extconf.rb failed ***
devなクライアントパッケージインストールして、、
# apt-get install libmysqlclient-dev Reading package lists... Done Building dependency tree Reading state information... Done The following extra packages will be installed: zlib1g-dev
ようやく、、、
# gem install mysql2 Building native extensions. This could take a while... Successfully installed mysql2-0.3.11 1 gem installed Installing ri documentation for mysql2-0.3.11... Installing RDoc documentation for mysql2-0.3.11...
でもって、、
# bundle update Fetching gem metadata from https://rubygems.org/........... Fetching gem metadata from https://rubygems.org/.. Using rake (10.0.2) ~略~ Using mongoid (3.0.14) Using mysql2 (0.3.11) ~略~
Railsアプリ内でMongoDBの設定は mongoid.yml というファイルで行いますが、 ↓こんな感じ。(rails.vimを使っています)
:Rgenerate mongoid:config
■ Railsアプリをジェネレート ・MongoDBの方でScaffold (invoke mongoidという感じになります)
:Rgenerate scaffold mongo_access date:string duration:string address:string result:string bytes:string method:string url:string rfc931:string hierarchy:string contenttype:string invoke mongoid create app/models/mongo_access.rb invoke test_unit create test/unit/mongo_access_test.rb create test/fixtures/mongo_accesses.yml invoke resource_route route resources :mongo_accesses invoke scaffold_controller create app/controllers/mongo_accesses_controller.rb
・MySQLの方はModelをActiveRecordでジェネレート(active_record:modelってする)してからScaffold ↓こちらのブログを参考にさせていただきました。 ActiveRecordとMongoidは共存できる | Aerialarts
:Rgenerate active_record:model mysql_access date:string duration:string address:string result:string bytes:string method:string url:string rfc931:string hierarchy:string contenttype:string create db/migrate/20121220015706_create_mysql_accesses.rb create app/models/mysql_access.rb invoke test_unit create test/unit/mysql_access_test.rb create test/fixtures/mysql_accesses.yml
Scaffoldではmongoidになってしまうのでモデルの上書きはSkip。
:Rgenerate scaffold mysql_access date:string duration:string address:string result:string bytes:string method:string url:string rfc931:string hierarchy:string contenttype:string conflict app/models/mysql_access.rb Overwrite /root/hoge/app/models/mysql_access.rb? (enter "h" for help) [Ynaqdh] n skip app/models/mysql_access.rb
#ってかscaffoldでactive_record:modelが自分が試したところ出来なかったのですが、 #ひょっとして出来たりするですかね、、、? ■ 画面からアクセスしてみると、、、 ソレっぽく見えてるーーヽ(´▽`)ノ ・MySQL ・MongoDB 業務的にも、こっちはでRDBMSでMongoDBで~とかって局面はありそうなので、 手応えが掴めてよかったです。 ■ せっかくなのでページネーション その昔、RailsアプリはScaffoldしただけでページネーションしてくれたものですが。 最近ではkaminari(https://github.com/amatsuda/kaminari)が流行ってるみたい。 Rails勉強会とかでお話伺った事ある人のなので使ってみよー、と。 Gemfile追加してbundleしてコントローラーとビューにチョコっとだけ手入れました。
# cat Gemfile | grep "kaminari" gem 'kaminari' # bundle update Fetching gem metadata from https://rubygems.org/........... ~略~ Installing kaminari (0.14.1) ~略~
・MySQL -Controller(mysql_accesses_controller)
@mysql_accesses = MysqlAccess.page(params[:page]).per(10)
-View(index.html.erb)
<%= paginate @mysql_accesses %>
-画面 ・MongoDB -Controller(mongo_accesses_controller)
@mongo_accesses = MongoAccess.page(params[:page]).per(10)
-View(index.html.erb)
<%= paginate @mongo_accesses %>
-画面 Orderしようとしたら、なんかMongoの方でメソッドがに無い~的なメッセージが 出てたのでscopeとか使ってソレっぽい書き方しなきゃかなーとかありますがとりあえず動きましたよ、と。 いやー、さすがRailsアツい…。