2016先日「ボケて」サービス群の中でも「スタンプ」という機能を提供するアプリサーバがGo実装になりました。これが僕にとってほぼ初めての「Golang実戦投入」となります。Goの良さについては去年の10月に僕がやっているPodcast「wada.fm」でも言及していました。単純に良いからと言って、本番への導入となると既にユーザーを抱えているので、敷居が高いと感じます。そこで、工夫しつつ、じっくりと試して、現在に至りました。後述するようにハマりどころはありましたが、そのGoサーバは安定稼働していて、ユーザーへコンテンツを配信しています。そこで今回は新規にGoを導入する際の一つの事例として、今回、僕がやったボケてのスタンプサーバリプレースの経緯を紹介します。LL言語への「若干の」不満まず...そもそもなんでGolangが必要なの?ってところ。ボケてのアプリケーションはほぼ全てが以前からPerlで書かれていて、キレイに本番で不具合も無く動いてくれていました。Plack/PSGIが登場してもはや久しく、アプリケーションサーバが安定し、またApp::cpanminus/Cartonといったモジュールインストーラやライブラリ管理も賢くやってくれます。これはLL全般に言えることなんですが、型が無いんですよね。型がないってことは、サクッと書くときにはいいけど、堅牢にやりたい時に手間がかかります。PerlにはData::Validatorというライブラリがあるので、それを使ってメソッドへの引数のタイプチェックなどを追加で実装していました。ボケて内のlib/Bokete/Model/Boke.pmには以下のようなコードが記載されています。$rule->validate(@_);実装レベルでコードの中に出てくる「データ」もしくは「機能」それぞれに対して厳密にチェックしておきたい場合に、LLだと外部のライブラリを使う手間が生じたり、それが完璧に行われないケースがあるのです。逆に言えばそれがLLのいいところですが、使いドコロによってはより「strictに」やりたいアプリケーションもあるかと思うのです。Perlは素晴らしく書きやすい言語だと思ってはいますが、他の違う言語も習得しておくと後々武器になって、楽しいんじゃないかなーって感じ、Goに手を出したという経緯になります。Goの魅力Golangを触ってみて良いなーって感じたことは前述した通り、wada.fmで話しております。興味のある方は聴いて下さい!www.wada.fmただ簡単に列挙するならば...静的型付け言語だけどスクリプトっぽくかけてとっつきやすい構造体にメソッド生やして「クラスのようなもの」を実現するとか「素朴」で良いコードを簡潔にするという方針などが現れた「ツンデレ」なコンパイラgoroutine便利だし使いドコロが結構あるWebサーバで負荷テストした時にCPUリソースをキッチリ使いきってくれて消費メモリも既存アプリと比べて少ない言語仕様的にもミニマムで「組み合わせでなんとかする」って点がPerlっぽい優良なライブラリもどんどん出てるなどなど、でしょうかね。触ってみて、スッとコードを書き始めることが出来たのがよかったです。Goをスクリプト的に利用する実は今回紹介するスタンプサーバ以前にボケてではGoを使っていました。プロダクトとしていつも動くサーバやバッチ、という形では無く、書捨ての「スクリプトっぽい」コードを利用してたのです。RDBMSのとあるテーブルの構造を変えて、データ移行したい場合においてです。なんでGolangをそこで使うのか?というとgoroutineがあるからです。Goだとgoというキーワードだけで並行処理が走り、かつデータベース接続もロックせずよしなにやってくれるので、MySQLサーバの負荷の様子を見ながら並行数を調整することで「ある程度の負荷をかけながら」素早くデータ移行が出来て便利でした。以下のようにsync.WaitGroupでそのgoroutineで平行に走らせる処理数を調整しています。wg.Wait()}このように最初はスクリプト的にGoを使ってみて感触を掴んでみました。どこからGolang化していくか?さて、Goのパフォーマンス性能を活かせて、かつ、現行で走っているサービスに影響がなければ、Golang化したいところ。移行のコストとかも考えると全てをGoにするのは大変だし、Perlの方が得意なところもあるのでその辺は見極めなくてはいけません。ボケてではMicroservicesという言葉が流行る以前から、ある程度サービスをHTTPレイヤーで切ったコンポーネント化を進めておりました。そこで、大きな部分を一気に変更する、のではなく、小さな一部分だけを違う実装に変えるということが容易です。そこで、目をつけたのがスタンプサーバです。ボケてではボケのコンテンツを画像として保存したりLINEで送る機能があります。「スタンプ」と呼んでいるのはまさに「LINEスタンプ」からインスプレーションを受けています。APIサーバから引っ張り、画像生成して、配信する機能が実装されています。試しに新しいGolang実装のサーバから配信されているスタンプ画像を直で貼り付けてみるとこのような画像です。このサービスはボケてのアプリの中でも「フロントエンドの1機能」としてPerlでつくられていましたが、ホストも違うし動かすサーバも違う。APIから取得してくればOK!と、切り離しやすい箇所だったので、まさにここからGolang化を試してみようとなりました。スニペットを集めると言っても、いきなり画像処理や文字列の改行計算を含んだ「ひとつの」アプリケーションを書き始めるのはニュービーにとって漠然としすぎてて、ムリゲです。スタンプサーバの実装要件をピックアップし、それごとに小さなGoコードの塊=コードスニペットをたくさん書いていきました。スニペットが集まっているレポジトリから選んでみると...ローカルの画像をリサイズして書き出すHTTP上の画像を取得して書き出すローカルの画像をWebで配信するテキストを描画して画像として書き出す改行を含んだテキストを処理する日本語を含んだ文字列改行の禁則処理をするなどです。書いたコードはこんなものでした。リサイズ処理にgithub.com/disintegration/imagingを使っています。dstImg.SubImage(dstImg.Rect)}このようにスニペットを充実させていく作業をするとお、これは本番用のアプリも実装出来そうだぞ!と自信がついてきます。画像生成サーバの実装と運用そこでいよいよスタンプサーバの実装です。処理部分のスニペットがあるので、いかに個別のファイルにまとめてテストを書いて構造化するか?を考えればすんなりといけました。こんなファイル群でstamp_serverコマンドをつくっています。util_test.goデプロイはあまりベストプラクティスが共有されてない?っぽいので、少々悩みましたが、今まで通りAnsibleで以下の工程を自動化しています。shutdownにはうまく対応出来てない疑惑がありますが、画像配信サーバーですし、間に短いTTLを仕込んだCDNを挟んでますし、なんとかなります。Goだとパフォーマンス悪くなるのかな〜?なんて自体に陥りましたが、これは別段Golangのせいでは無く、僕が書いていた禁則処理のロジックで稀に無限ループをつくってしまうバグが潜んでいただけでした。「あるある〜!」そう言語が悪いんじゃないんです、自分が悪かったのです。そこが大きな躓きポイントなだけであとは十分パフォーマンス出てますし、不具合もなく快適なアプリになりました!まとめボケてにおいてスタンプサーバをGo実装で書き直して、Go本番童貞を捨てた話を書きました。本番化しないと分からないことも結構あったので、やってよかったと思います。