スタディサプリ on Quipper プラットフォームを支える技術
前置き
この記事を公開した当時はまだオープンにできなかったのですが、実はこの記事は2月25日にリリースされたスタディサプリ(受験サプリ)を Quipper のプラットフォームに載せ替えるという移行プロジェクトを前提として内容も含んでいました。
【公式】スタディサプリ|苦手克服・定期テスト対策~大学受験まで
無事にリリースできたので、このプロジェクトで変わったことや導入したソフトウェア、ツールについていくつかピックアップして書いていきたいと思います。
目次
- メンバーが増えた
- Infra as Code
- Deis
- AWS ECS + Docker + Locust による負荷テスト
- nginx (HTTP/2, ngx_mruby)
- 分析基盤
- 技術的課題
メンバーが増えた
前回の記事を書いた時はインフラ関連のエンジニア(Quipper では Engineering チームといいます)は私1人だったのですが、kamatama41 さん、lamanotrama さんが加わり、今は3人でちゃんとしたチームになりました。
メンバーが増えたことで、今まで手がつけられなかったことが大分できるようになりました。
Infra as Code
今回は AWS の環境から全て新規に構築するということで、Infra as Code 全開でやってみました。
- Terraform
- Roadworker
- Miam
- Ansible
- Ansible Tower
- ServerSpec
- Infrataster
Terraform と Roadworker/Miaml で AWS のリソースを定義し、Ansible でサーバーを Provisioning するという至ってオーソドックスな構成です。 全てのツールは CircleCI 上でテストから適用までできるようになっています。(Ansible に関しては、CircleCI から Ansible Tower の API を叩いて実行という構成になっています)
Playbook のテストは CircleCI 上で Docker で素の Ubuntu を起動し、そこに Playbook を適用し、ServerSpec, InfraTester でテストしています。 実際にやってみて、色々と気を付けなければいけない点はあり、初期はスピードが出なかったのですが、インフラの設計図が全てコードになっていて、暗黙知がなくなり、開発後半はスピードも安定性も出すことができたと思っています。
今後は、ここで得た知見を、今度はグローバルのプラットフォームにバックポートしていく予定です。
Deis
Deis は Docker/CoreOS/Fleet/Etcd/Golang/Python で構築された Private PaaS を実現するソフトウェアです。Deis の導入は今回のプロジェクトで一番難しかったことの1つでしょう。なにしろ、日本語はもちろん、英語でもプロダクションでどのように運用しているかという情報がなかったからです。公式からも AWS CloudFormation のテンプレートが提供されているのですが、正直あのままでは不安定すぎてプロダクションに投入できません。これについては長くなるので、別途 Qiita に書いてみたので、ご参照ください。日本でプロダクションに投入したのは初のはず。
Deis を AWS でプロダクションに投入するための Tips - Qiita
色々と大変ではあるのですが、半年以上検証した結果それなりに安定運用できています。 Deis の良い点は、とにかく Heroku Buildpack と互換性があるということです。
今回のスタディサプリのアプリケーションについてもコードは、海外で展開している Quipper School と同じコードを利用しています。そして、海外では Heroku でアプリケーションをホストして、並行して開発が進んでいます。 Deis は Heroku Buildpack と互換性があるため、デプロイの仕組みを別々に作らなくてもよく、git の push 先を Deis に切り替えるだけで、Heroku で動いしていたコードがそのまま動きます。
Heroku を使っているユーザは、行くのも戻るのも簡単なので移行の有力な選択肢になるのではないかと思います。ただし、それなりに手はかかるので、インフラにあまり手をかけられないという人は、Heroku Private Spaces も併せて検討することを忘れずに。
AWS ECS + Docker + Locust による負荷テスト
GKE + Docker + Locust による負荷テストを実施していましたが、今回、ネットワーク的に近いほうが負荷テストをし易いだろうということで、AWS ECS を利用して同じものを作ってみました。
https://github.com/hakobera/docker-locust-gke (これは GKE 版)
使い勝手はほぼ変わりませんが、ECS は利用する場合は幾つかメリットがあります。
- Docker Compose 互換の設定ファイルが使えるので、ローカルで構成をテストしてからそのまま持っていける
- Spot インスタンスが使えるので安い
ということで、負荷テストにお悩みの方は ECS + Dokcer + Locust も試してみると良いのではないでしょうか。 ECS版はソースを整理したら、公開したいと思います。とりあえず、Dockerfile だけ。Alpine はイメージサイズが小さくていいです。
FROM python:2.7-alpine RUN apk -U add ca-certificates python-dev build-base && \ pip install locustio pyzmq && \ apk del python-dev && \ rm -r /var/cache/apk/* && \ mkdir /locust WORKDIR /locust COPY locustfile.py /locust/locustfile.py RUN test -f requirements.txt && pip install -r requirements.txt; exit 0 EXPOSE 8089 5557 5558 ENTRYPOINT [ "/usr/local/bin/locust" ]
nginx (HTTP/2, ngx_mruby)
HTTP/2
https://studysapuri.jp/ にアクセスしてもらえればわかると思いますが、リバースプロキシは nginx かつ、プロトコルは HTTP/2 を利用しています。 HTTP/2 の恩恵で、画像がたくさんあるページなのですが、快適に表示することができていると思います。
今回、静的サイトに関してはアクセスされるのがほぼ日本のみということで、CDN をほぼ利用していませんが、HTTP/2 に対応していない CloudFront を利用するよりも配信が速かったです。
ngx_mruby
時代はプログラマブルなリバースプロキシだ、ということで、nginx 単体では難しい処理を ngx_mruby を利用して実装しています。具体的には、
- DoS 対策
- メンテナンス画面への切り替え処理
- TCP プロキシの backend サーバの動的 DNS Lookup (DNS resolve 機能、nginx+ にはあるけど、OSS にはないのです)
などです。nginx で上記のことができるようになったので、アプリケーション側で考慮することが減って実装や変更が楽になりました。
分析基盤
- fluentd
- embulk
- Kinesis + Lambda
- TreasureData
Quipper は BigQuery を利用していますが、今回のスタディサプリはリクルートマーケティングパートナーズとの合同プロジェクトでもあるので、彼らの分析基盤である TreasureData へデータ集約を行っています。fluentd で nginx のログを、embulk でマスタデータを、Kinesis + Lambda で Deis からのイベントデータを送信しています。
Kinesis + Lambda によるイベントデータ送信はあまり話を聞かないのですが、かなり便利なのでオススメです。fluentd の再送機能も良いのですが、障害対策のためにバッファをどれくらい取るかなどの設計が悩ましいですが、Kinesis + Lambda の組み合わせなら なら最大7日間イベントを保持、再送処理をしてくれるので、その辺をまるっと AWS にお任せできるので大変助かっています。サーバーレス万歳ですね。
https://github.com/hakobera/lambda-kinesis-bigquery
内部では上記の TreasureData 版を作って使っています。
技術的課題
モニタリングと通知をもっと効率的に
Quipper ではモニタリングに各種ツールを利用しており、
- Sentry
- Pingdog
- NewRelic
- Datadog
それぞれ便利なのですが、いくつか問題があります。リリースへ向けて、新規構築に重点を置いていたため、これからは監視、運用をどう効率化していくが解決するべき課題となっています。
- 見る場所が分散して、全体の状況を把握するするのが難しくなっている
- 一応、Datadog に集約して、Slack 通知という方針をとっているが、Integration がなくて集約しきれないものもあり悩み中
- アラートが来すぎる
- 領域がかぶっている監視が同時にアラートをあげて、重複して通知がくる
- 純粋にアラートが多すぎて、本当に重要なエラーを見逃しがち
Workflow エンジンを Luigi から自作の Ruby のやつに置き換える
Workflow エンジンについては引き続き、課題として認識中です。 Luigi 自体は素晴らしく、運用上も大きな問題はないのですが、
- Model が Ruby で書いてあるので、Ruby で書かれた Workflow エンジンがあると、そのコードが利用できて便利
- Python だとバッチ系のコードのメンテができる人が限られてしまう(どちらかというとこちらの方が問題)
という理由により、Ruby で書かれた Workflow エンジンを実装中です。 どんな感じになるのか興味がある方は、以下の連載記事をご覧ください。
http://qiita.com/hakobera/items/d7742cc0801a9c62ef72
そろそろ4回目書きます。 4回目書きました
Workflow Engine をつくろう! Part 4(Task の並列実行) - Qiita
負荷試験を CI に組み込む
ECS + Docker + Locust で負荷試験が簡単にできるようになったので、これを CI に組み込むことで定期的にパフォーマンスをチェックできるようになるといいなと思っていますが、まだできていません。
Ubuntu 16.04 LTS への乗り換え
upstart から systemd への変更が・・・ということでいつやるか悩み中。 Ansible が吸収してくれるようになったらかなとは思っている。
絶賛採用中です
Quipper ではここに書いてあるようなクラウドを積極的に活用したお仕事、技術的課題の解決に興味があるエンジニアを絶賛大募集しております。興味のある方は、以下の募集ページからご応募ください。ちなみに採用関係なく、情報交換もしていきたいので、もっと詳しく聞いてみたいという方は Twitter で @hakobera, @kamatama_41, @lamanotrama にメンション or DM をお気軽にどうぞ。