RailsアプリでActiveRecordとMongoidを両方使ってみる

今までRDBMSで動いてたRailsアプリをMongoDBにマイグレーションする~的な 話が出てきたので、検証を兼ねて、VirtualBoxUbuntuRailsアプリをインストールして、 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プラグインで集めてきます、と。 なんでSquidaccess.logにしたかっていうと、たまたま見かけた ↓のブログにグッときてしまったから、、っていう話なのですが。。 fluentdのformat(正規表現)の作り方について試行錯誤中 #fluentd - Glide Note - グライドノート   ■ Fluentdのプラグイン fluentdはmongoとmysql用の両方のプラグインがあるので、 ・https://github.com/fluent/fluent-plugin-mongohttps://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...

次にMySQLプラグイン

# 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アツい…。   

MongoDBイン・アクション
Kyle Banker
オライリージャパン
売り上げランキング: 10800