はじめに
これは Ruby on Rails Advent Calendar 2014 - Qiita の19日目です
18日目
@yancya さんの Rails でシングルじゃないテーブル継承 - Qiita でした
19日目:オレオレRailsアプリを支えるインフラの作り方
最近では Heroku などのPaaS*1 も普及してインフラのことを知らなくても簡単にアプリを公開することができるようになりました。
しかしトラブルシューティングやパフォーマンスチューニングなどを行うにはアプリケーションコードだけで完結することは少なく、全体像を把握する必要があります。Railsアプリケーションの裏でどんな構成で動いているかを知っておくかは重要なのでざっくりと紹介したいと思います。
書かないこと
Railsアプリのインフラ構成
モダンなRailsアプリに必要なミドルウェア
私はRailsの会社に入って約2年半になりますが、大小合わせて10個以上のRailsアプリをリリースしてきました。*3 Railsアプリを作る時にはだいたい同じようなミドルウェアをインストールしてるので一覧で挙げてみます。
データベース
- Railsだとだいたい MySQL か PostgreSQL の2択かと *4
- Rails本体でのPostgreSQLのサポートの手厚さは異常
- 弊社だと MySQLのForkである Percona Server を使ってます
Percona Serverの説明を社内wikiより引用
Perconaは機能・性能は本家より劣る部分は無く、 マルチコアCPU・同時アクセスI/Oといったハードを考慮した設計や、 効率的なバックアップ、その他細かい改善が施された、 一歩進んだMySQLサーバといったところです。
リリースも本家に1~2ヶ月程度の遅れで追随し、 マニュアルも整備されており、ご丁寧に各種OS用のパッケージも用意されています。
近年のハード環境においてDB運用を少しでも効率よくしたいならば 使うしか無いシロモノであります。
アプリケーションサーバ
Railsは基本的に複数リクエストを同時にさばけないので、アプリケーションサーバ側でworkerを複数たてるのが定番です。*5
- unicorn
- リクエストをうけるために複数のworkerプロセスをたてて、1つのmasterプロセスがそれらのworkerを管理するスタイル
- thin
- 同上
- puma
- プロセスの代わりにスレッドを複数立ててリクエストをさばく
- passenger
- ShellShockで「Passengerは全死亡」とまで言われてるのでもう誰も使ってないですよね・・・?
- ウェブアプリにおけるBash脆弱性の即死条件 #ShellShock - めもおきば 辺り *6
詳しい比較
Webサーバ
辺り
KVS (Key Value Store)
Q「KVSって何よ?」 A「Hashのすごい版」
- memcached
- 永続化しないので基本的にはいつ消えてもいいデータを入れる(キャッシュとか)
- 1つのkeyに1MBしか格納できないので注意
- Redis
- ディスクに永続化するし集合やトランザクションもあるので高機能
- カジュアルにデータ入れることができる反面、keyに有効期限をつけておかないとデータが増えすぎた時に消すのが大変になる
- TokyoTyrant (TT)
- KyotoTycoon (KT)
辺り
弊社でよくある構成
全体像(最大構成)
冗長化を考えたらだいたいこんな構成になるはず
用語の説明
- webサーバ
- adminサーバ
- 管理画面用。webサーバの台数が多くなると管理画面の修正だけでwebサーバ全台デプロイするのは大変なのでadminサーバが作られることが多い
- jobサーバ
- dbサーバ
- データベース
- 弊社だとmaster 1 : slave 1の構成
- 用途に応じて垂直・水平分割
- kvsサーバ
- cacheサーバ
- VIP
- Virtual IP Addressの略。複数のサーバを同一IPでアクセスすることができる。
- 例えば2台あるうちのDBサーバが片方死んだらアプリは動かなくなるが、VIPをつけていれば生きているサーバだけにアクセスがいくので片肺運転で生き延びる。(その間にサーバ復旧)
- Master / Slave
全体像(最小構成)
全部入りとかオールインワンとか言うこともある。冗長化考えなければこれでも十分
各種ミドルウェアのインストール手順
前述の最小構成(全部入り)で環境構築してみます。 chefで楽をしてもいいんだけど、基礎を学ぶために全部手動インストールしてみます。
検証環境:Debian Wheezy(CentOSは普段使ってないのでよく分かりません(´・ω・`))
最初にやること
$ sudo apt-get update
MySQL
インストール
$ apt-cache search mysql-server mysql-server - MySQL データベースサーバ (最新版に依存するメタパッケージ) mysql-server-5.5 - MySQL データベースサーババイナリおよびシステムデータベースの設定
どっちか入れればok
$ apt-cache show mysql-server | grep Version Version: 5.5.40-0+wheezy1 Version: 5.5.38-0+wheezy1 $ apt-cache show mysql-server-5.5 | grep Version Version: 5.5.40-0+wheezy1 Version: 5.5.38-0+wheezy1
と思ったけど、どっちも5.5系だw(5.6系はまだパッケージになってないだけ?)
おもむろにインストール
sudo apt-get install mysql-server
途中でrootのパスワード聞かれるので入れる
設定ファイルはこいつ
sueyoshi_go@sue445-advent-debian-01:/$ ls -l /etc/mysql/my.cnf -rw-r--r-- 1 root root 3504 12月 3 00:51 /etc/mysql/my.cnf
デフォルトで使ってもいいんだけど必要に応じてこの辺をいじっておく
データの保存場所。ボリュームのでかいところに変えた方がいい
datadir = /var/lib/mysql
スロークエリを出すかどうか。コメントアウトしたら2秒以上かかったクエリがログに出る
# Here you can see queries with especially long duration #log_slow_queries = /var/log/mysql/mysql-slow.log #long_query_time = 2 #log-queries-not-using-indexes
ついでなのでJenkinsでmysqlを設定する時の注意点
Jenkinsでのビルドの場合常にテストデータの作成と削除を繰り返すのでbinlogの保存期間(日数)は1日でいいと思います。(0だと無限に保存されてしまうので最小期間は1日)
expire_logs_days = 10 max_binlog_size = 100M
デーモンの起動方法
$ sudo /etc/init.d/mysql Usage: /etc/init.d/mysql start|stop|restart|reload|force-reload|status
他のミドルにも言えますが /etc/init.d/
辺りを探せば起動スクリプトが見つかります
設定を反映させるためにはrestartかreload
sudo /etc/init.d/mysql restart
nginx
$ apt-cache search nginx nginx - 小さくて強力で拡張性のあるウェブ/プロキシサーバ $ apt-cache show nginx | grep Version Version: 1.2.1-2.2+wheezy3 $ sudo apt-get install nginx
設定ファイルをいじる
$ ls -l /etc/nginx/sites-available/ 合計 4 -rw-r--r-- 1 root root 2765 9月 18 22:18 default
/etc/nginx/sites-available/default
を適当な名前でコピーして使う。
$ sudo cp /etc/nginx/sites-available/{default,example} $ sudo vi /etc/nginx/sites-available/example
最低限の設定ファイルはこんな感じ
upstream myapp.example.com { server 127.0.0.1:8080; } server { listen 80 default; server_name myapp.example.com; access_log /var/log/nginx/myapp_access.log combined ; error_log /var/log/nginx/myapp_error.log warn; location / { root /var/www/myapp/current/public; if (-f $request_filename) { access_log off; rewrite_log off; expires 1h; break; } if (!-f $request_filename) { proxy_pass myapp.example.com; break; } } location ~ /\.git { deny all; } }
設定を反映させるためにはrestartかreload
sudo /etc/init.d/nginx restart
redis
インストール
$ apt-cache search redis-server redis-server - ネットワークインターフェースを備えた永続的キーバリューデータベース $ sudo apt-get install redis-server
設定ファイル
$ ls -l /etc/redis/redis.conf -rw-r--r-- 1 root root 21162 6月 9 2012 /etc/redis/redis.conf
memcached
インストール
$ apt-cache search memcached memcached - 高性能のメモリオブジェクトキャッシングシステム $ sudo apt-get install memcached
まとめ
Heroku 使うのが一番楽
20日目
@youcune さん