お久しぶりです、Webエンジニアの本間です。
去る2019年10月1日に自分が所属するチームで担当した「ルクミーフォト」のリニューアル版をリリースすることができました。
【プレスリリース】『ルクミーフォト』および ユニファコーポレートサイトリニューアル
今回、こちらのリニューアルで技術的にどのような変更があったのか、その変更はどういう意図を持って実施したのか、広く浅めに紹介したいと思います。
インフラ
EC2からECS & Fargateへの移行
リニューアル前のルクミーフォトは、必要な数分のEC2インスタンスを立てて動かしていました。
一方、リニューアル後のルクミーフォトはDockerコンテナをAmazon ECSとAWS Fargate(一部EC2インスタンス)で動かしています。 変更した理由は以下になります。
- 自動スケーリングを楽にやりたい(ルクミーフォトは、サーバーへの負荷が日にちや時間帯で大きく変わるため、コンテナ数を柔軟に変更したい)。
- stagingでテストしたものと同じものを本番にデプロイしたい。
- インフラを秘伝のタレ化させたくない。
上記の他に「追加のテスト環境を簡単に作れる」というメリットもありました。
一方、以下のデメリットもあることがわかりました。
- ビルドとデプロイに時間がかかる
- コンテナが落ちるとログが消えるので、Cloudwatchなどコンテナ外にログを残すよう工夫が必要。
- サクッとRailsコンソールが動かせない。
- Fargateで動かす場合、EBSをマウントできないなどいくつか制限がある。
「ビルドとデプロイに時間がかかる」以外は対策を入れていますが、「ビルドとデプロイに時間がかかる」に関しては今後対策を考えていきたいです。
ログもEC2からCloudwatchへ
Amazon ECSへ移行した影響で、ログの出力先もEC2からCloudWatchへ変更しました。 ログの形式もテキストからJSONに変更しています。詳細は下記エントリをご参照ください。
はじめはgrep検索の方がいいかも、と感じる時がありましたが、慣れてくると気にならなくなりました。 特に障害調査の際、特定のユーザーのログだけを抽出するということがやりやすくなっており、ログ調査の効率は上がったと感じています。
画像処理はLambdaへ
リニューアル前のルクミーフォトでは、サムネイル処理などの画像処理はEC2インスタンス内で行なっていました。
リニューアル後は、画像処理は全てAWS Lambdaへ移行しています。 変更の意図としては、以下になります。
- 画像処理はCPU使用率が高いので、自分たちのサーバーでやりたくない。
- 負荷に応じて自動でスケーリングしてほしい。
- ImageMagickをDockerイメージに含めたくない。
- 複雑な画像処理のコードを、本体から切り離しておきたい。
今のところ意図通りの運用ができており、移行してよかったと感じています。
サーバーサイド
Ruby&Railsの最新化
リニューアルを機に、QA開始時点で最新のRubyとRailsを使用するようにしました。
アップデートによって便利な機能追加やパフォーマンス改善など様々なメリットがありました。
ほぼAPIサーバー化
リニューアル後のルクミーフォトは、SPA(シングルページアプリケーション)になっています。 初回アクセス以降のサーバーアクセスはAPIを経由したJSONデータのやり取りになっており、サーバーサイドのアクションの多くはJSONデータを返すAPIとなっています。
サーバーサイドのViewに関する実装も、 ERBのHTMLテンプレートから、 ActiveModelSerializers を使ったJSONのシリアライズに変更されています。 Viewに関する実装が大幅に減ったため、サーバーサイドのコードとしては見通しがよくなりました。
非同期処理はResqueからActiveJob(Sidekiq)へ
Railsが新しくなったことで、ActiveJobが使えるようになりました。 これにより、非同期処理は全てActiveJobのサブクラスとして書き直しています。 ActiveJobにすることで、同期と非同期の切り替えやリトライ制御が容易にできるほか、ロギング、テストなどの機能がRailsと親和性が高く実装できています。
バックエンドをResqueからSidekiqに変えたのは、メモリとCPUの使用効率を考えてです。 ルクミーフォトの非同期処理の大半は、データベースや外部サービス呼び出しなどI/O待ちが多く、CPUをほとんど使用しません。 CPU使用率が低いのであれば、マルチスレッド型でGVLの制約があるSidekiqのデメリットが気にならないと考えました。 マルチスレッド型の方がメモリの使用効率がよいため、Sidekiqに変更しました。 今のところピークでもジョブが溜まることなく、高速に処理できています。
フロントエンド&デザイン
Vue.js, TypeScriptの導入
リニューアル前のフロントエンドでは、jQueryメインでゴリゴリと実装をしていました。
リニューアル後のフロントエンドでは、モダンフロントエンドの1つ Vue.js を導入しました。 またコードの大半でTypeScriptを使用しており、型チェックで不具合を事前に検知できるようにしています。
Vue.jsを使った実装は、初めは慣れず苦戦する部分もありましたが、慣れてくるとjQuery時代に戻れない生産性の高さ、可読性の高さがあります。 フロントエンドが複数ページあり、かつそれぞれのページでそこそこ複雑な動きをする場合、ReactやVue、Angularを使った方が良いと確信を持って言えます。
MPAからSPAへ
リニューアル前は、ページ遷移ごとにサーバーサイドでHTMLを生成するMPA(Multiple Page Application)でした。
リニューアル後では、初回アクセス時に全てのページの情報を取得し、それ以降サーバーとのデータのやり取りはAPIで行うSPA(Single Page Application)に変更しました。 これは、次に紹介するデザインフレームワークがSPAを前提とした作りになっていたことが大きいです。
また、ページ間で情報を共有しなければいけない機能(編集→確認→完了のような画面遷移とか、カート機能とか)は実装しやすくなりました。 初回アクセスは時間がかかりますが、それ以降はサーバーとのやり取りがAPI経由でのJSONデータとなりデータ量が減るため、パフォーマンスも改善しました。
一方で、状態の管理(Vuexやセッション)はMPAに比べて複雑になりました。 意図せず前のページの情報が残ってしまったり、ページをリフレッシュしてあるべき情報がなくてエラーになってしまったり、という不具合が発生しやすくなりました。 この辺りはなんらかの仕組みを導入して、不具合が残らないような仕組みを作っていきたいです。
OSSのデザインフレームワークの利用&カスタマイズ
リニューアル前のアプリケーションでは、保護者様向け画面は全て自前でstyleを定義、園・教室様向け画面はBootstrapをカスタマイズせずそのまま使用と両極端な使い方をしておりました。
一方、リニューアル後のアプリケーションでは、OSSのデザインフレームワークをサービスのトンマナに合わせてカスタマイズして使うようにしています。
OSSのデザインフレームワークを使うことで、1から作るより工数を大幅に削減しています。 ただ、そのままだとルクミーフォトのテーマに合わないため、細かいstyleを上書きして使用させていただいております。
今回使わせていただいているデザインフレームワークは、以下の2つになります。
効率的に開発ができた反面、今後のライブラリのアップデートには注意する必要がありそうです。
まとめ
今回、ルクミーフォトのリニューアルで技術的に変更したことの一覧を紹介しました。 今後の利用者数の増加や、スピード感のある開発に対応できるシステムができたと思っています。 これからはこのシステムを拡張、改善、メンテナンスしつつ、ユーザーの皆様にさらなる価値を届けていきたいです。
このエントリが何かの参考になれば幸いです。 あとリニューアル後のルクミーフォトで使っている技術一覧を見て、自分も開発してみたい!という方も募集中です。