Ruby on Rails4.2でMicrosoft Azure SQL Databaseに移行
開発中のWebサイト「合唱音源の新着情報.com」で、データベースにはSQLite(Webサーバ内のローカルファイル)を使っていました。 しかしスケーラビリティや耐障害性を考慮し、SQLiteを捨ててデータベースサーバを導入することにしました。 (Webサーバのログインパスワード忘れてどうしようも無くなったなんて言えない)
WebサーバにMicrosoft Azureの仮想マシンを使っていることもあり、データベースサーバには同じAzureのPaaSであるMicrosoft Azure SQL Databaseを選びました。
SQL Serverは一切触ったことがありませんが、クラウドなので簡単に移行することが出来ます。たぶん。
Microsoft Azure SQL Database 構築
現在のサービスではいわゆるトランザクションデータは未だ取り扱っていないので、データ量は数千行程度と大したことはありません。 2GBまでのBasicプランを選択します。
最小構成であるBasicプランは現状月額500円程度と、AWS RDSの最小構成に比べてもお手頃さが特徴、個人でも運用しやすいです。 (AWSには無料枠が1年分ありますが...)
後は適当にポチポチするだけでデータベースサーバを構築できます。 ここで入力したパスワードを忘れないように気をつけましょう。(実際に忘れて一度作り直しになりました...)
Rubu on Rails から Azure上の SQL Serverに接続
Azure SQL Databaseの中身はMicrosoft SQL Serverらしいです。 なので、普通にSQL Serverに繋ぐ時と同じような方法で接続できます。
…できるはずなのですが「普通にSQL Serverに繋ぐ」がなかなかうまく行かず…
https://github.com/rails/rails/issues/17693 によると、どうやらRails 4.1.x 系と相性が悪いらしく接続できないようです。(ちゃんと読んでない)
なのでRails 4.1.9から4.2.1にバージョンを上げました。
ついでに、このためにWebサーバをまるごと新調し
- CentOS 5.x→7.1
- Ruby on Rails 4.1.9→4.2.1
- Ruby 2.x→2.2.1
に変更しました。 (SSHできなくなったサーバを捨てるついでです)
あとは接続します。 ↓下記ブログに書いてある事と同じになりますが http://lab.heathrow.co.jp/2013/08/23/1721/
tiny_tdsというruby gemを入れる必要があります。 tiny_tdsのインストールにはfreetdsが必要です。 freetdsは、CentOSの場合EPELからインストールします。
$ sudo yum install epel-release $ sudo yum install freetds freetds-devel
Gemfileに下記記述してbundle install
します。
# Azure SQL Server gem 'tiny_tds' gem 'activerecord-sqlserver-adapter'
database.yml に下記記述します。
development: adapter: sqlserver mode: DBLIB port: ******** host: ******** database: ******** username: ******** password: ******** timeout: 10 azure: true
あとはrails s
で起動できたら成功です。
これで接続することができました。
なお、この後データベーススキーマを流す時に「rake db:drop」等でデータベースごと壊してしまうと「rake db:migrate」等では作り直せないので気をつけましょう。(実際に壊してしまい、Azure管理画面から作り直しになりました...)
SQLiteからSQL Serverへのデータ移行
現状のデータを(ログインできないサーバのローカルにある)SQLiteからAzure SQL Databaseへと移行しなければなりません。
たまたまrails_adminが入っていたので、データをCSVやJSON形式でエクスポートすることが出来ます。なおインポートは出来ません。
今回はこのRails Adminのエクスポート機能を使う事にしました。 (普通はyaml_dbなどを使えば簡単だと思います。たぶん)
データベーススキーマは下記記事で紹介したような多対多のリレーションになっています。
Rails AdminでJSONエクスポートしてtmp配下に配置し、rails console
で下記を実行することでデータを流し込む事ができました。
もう少しRailsらしくスマートに書けそうな気もしますが、一度しか使わないプログラムなので気にしないことにします。
$ rails c
JSON.parse( File.read("./tmp/tweet_2015-06-13_10h44m31.json", :encoding => Encoding::UTF_8) ).each { |elem| elem["tweet_details"].map!{ |e| d = TweetDetail.where({name: e["name"], value: e["value"]}).first d || d = TweetDetail.new(e) } s = Tweet.new(elem) s.save }
既に2週間ほど前から、 合唱音源の新着情報.com の本番環境でAzure SQL Databaseが動いています。 これでスケーラビリティや耐障害性のあるデータベースサーバが手に入りました。 ポイントインタイムリストアがあるので危険なスキーマ変更などもやりたい放題だと思います。たぶん。
応答速度について、さすがにローカルファイルだったSQLiteに比べれば通信のスループットがあるせいか若干重くなった感じはしましたが、インデックスを適切に貼ることで解消されました。 書いていて思いましたが それは通信のスループットの問題ではない ですね。
なやみごと:開発環境をどうするか
MacにSQL Serverは建てられません 。 また、SQL Serverと言えばVisual Studioという強力なGUIツールが特徴だと思うのですが、これもMac版はありません。
本案件はメインの開発環境がMacのローカルなため、ここで困ってしまいます。 本番と同じデータベースで開発…も嫌なので、もう500円払って開発用のデータベースを構築したいところです。 しかし現状は開発環境がSQLiteのまま、本番環境だけSQL Serverで進めています。
開発環境と本番環境でデータベースミドルウェアが異なっていても、Active Recordが何とかしてくれるので割と上手くいきます。 でもridgepoleのスキーマファイル出力結果が環境毎に一致せず開発環境で毎回謎のchange columnが走ったり、本番環境でRails Adminがよく分からないエラー(一部データ型を認識できない?らしい)で何度も落ちたり…細かい問題はあります。