というお話です。
tr;dl
- 担当してるプロジェクトのRailsアプリがメモリ肥大化してるしレスポンス遅くて大変
- メンバーでどうしようかと話が出ている中で、「一部切り出して別プログラムにしてみては?」と提案されたよ
- そのときCrystalを推している人がいて、Rubyからコンバートしやすいんじゃね?という話からとりあえずやってみたよ
- やってみたらやはり厳しい箇所はある、がモノを選べば意外と苦戦はしなかった
- いろいろあって本番投入は見送ったけど、考え方としてはありだと思う
経緯
わたくし、ここでお仕事しておりますが、現在担当しているプロジェクトにおいて開発・保守をしているRailsアプリにおいて、以下のような問題がありまして、それはそれはメンバーを悩ませていました。
- レスポンスが遅い。
- 特にこのRailsアプリは数多くの帳票を出力することが求められていて、特に大量データ出すやつがつらい
- メモリめっちゃ食う
- 一回でかい帳票を作ると肥大化したままになって大変
上に書いた問題から誘発されてさらに問題が起こったりして、運用で非常に手のかかる子になっていたのでした。
そこでいくつか改善していく方策をうっていきました。そのうちの一つに、「帳票を作る箇所を別プロセスにすりゃいいのでは?」という提案があり、そこでメンバーでCrystalを推していた人がいたのでとりあえず使ってみましょう、という話になったのでした。やっぱり型がほしいのです。
ちなみに自分が担当したのは、Crystalは自分も興味があってちょっと触っていたので、そこで手を上げたというのが経緯です。
実際やってみたどうだったか
手を上げてみて取りかかったはよいものの、基本的にそのまま動くことはありえないと思っていて実際にその通りでした。ActiveRecordがバリバリ使われている箇所は非常に厳しい。こんがらがったscopeをひもといてCrystalで扱えるようなかたちに落とし込む必要がありました。
そのため、今回はSQLで直接データを取り出すかたちで作られていたRubyのコードをCrystalにコンバートするようにしました。さらにライブラリとしてはwaterlink/crystal-mysqlを使用しています。
元コードの設計としてはSqlLoader
クラスをベースクラスとして、それを継承したExsampleLoader
クラスを実装してそこでSQLでデータ取得、データの加工を行うようにしてたが、Crystalではデータ取得と加工を別クラスにわけました。おおよそで書くとこんな感じです。Rubyから簡単にConvertしたので型が書かれてなくて寂しい感じですね。
# coding: utf-8
require "mysql"
module Loader
class SqlLoader
def initialize
@conn = MySQL.connect("exsample.com", "user", "password", "db_name", 3306_u16, nil)
@conn.set_option(LibMySQL::MySQLOption::MYSQL_SET_CHARSET_NAME, "utf8")
@conn.query(%{SET NAMES utf8})
end
def datas
datas = @conn.query(sql)
if datas
datas
else
nil
end
end
private def sql
end
end
class ExsampleLoader
private def sql
# この中でSQLを書く、大変………
end
end
end
class Exsample
def initialize(loader)
@loader = loader
end
# この下に加工するメソッド書いたりする
end
上記Crystalで書いたものは一つのバイナリにして、Rails側から呼び出すかたちにしました。全体の実装自体はそれほど複雑ではなかったのですが、crystal-mysqlの挙動に悩まされたりして意図した動きになるのに2日ほどかかりました。
見送り理由
という感じで一通り実装してみたものの、2016/12/03時点では本番に投入していません。理由いくつかありますが、技術的な面で行くと
- Crystal自体がどんどん開発進んでいて、そこに追従していくコストが今は厳しい
- 現状は外部ライブラリの安定感とかそういうところが、プロダクションでは若干つらい
- 今はcapistranoでデプロイしてるけど、ビルドとかもどうせなら自動化したいしそういうことも考える必要があるけど、今はあんまり暇がない
というところですね。とはいえそこらあたりのコストを払えるのであれば、Ruby知ってる人は違いを押さえられれば他の言語覚えるより楽な感じもするし、投資する先の選択肢としてありな感じはします。