nginx Rails Mysql の構成で、アクセス負荷に耐えるためとりあえずやっておくこと

Too many open files

nginx (/etc/nginx/nginx.conf)

# CPU と同じ数
worker_processes  8;

# worker_connections の 4倍程度
# failed (24: Too many open files)  に対処できる。
worker_rlimit_nofile  40960;

events {
  # とりあえずこの値
  worker_connections 10240;
}
open file が増えているかを確認
# これでpid を確認し、
$ ps ax | grep nginx | grep worker
# 数字に、pid を入れる。
$ cat /proc/5618/limits

Resource temporarily unavailable

net.core.somaxconn (/etc/sysctl.conf)

こちらも処理するキューに貯められる最大値。backlog と小さいほうが優先される。

# デフォルトは 1024。とりあえずこの値にする。
# failed (11: Resource temporarily unavailable) に対処できる。
net.core.somaxconn = 65535

再読み込み

sysctl -p

MySQLでtoo many connections

Rails (unicorn.rb)

worker が1増えると、db への connection が1増えるため、max_connection の値には注意する。
DBのpool は、DBの接続数にあまり意味が無い。

DB の connection 数を確認する

worker にアクセスがなければ、unicorn が起動していても connection が増えない場合もあるので注意する。

show status like 'Threads_connected';
DB の max_connection 数を確認する

この値を超えてしまった場合は、DBへ接続できないということになる。ただし、単純にDBのmax_connection を増やしてしまうと、DB 側のメモリ消費が増えてしまう。

show variables like 'max_connections';
# メモリを最大限消費する数にする。多すぎると、swapが発生し、遅すぎて処理ができなくなる。実際にworker へアクセスされた時にメモリ消費が増えるため、起動した時の値だけで判断してはいけない。
# failed (110: Connection timed out) に対処するための一つの要素。
worker_processes 10

# backlog に、キューに積み上げられる最大数を設定する。
# failed (11: Resource temporarily unavailable) に対処できる。
listen "/var/sample.sock", backlog: 8192

Whenever の schedule.rb 内の設定を環境ごとに変える

$ bundle exec whenever --update-crontab appname --set environment=production

このように処理を実行した時、schedule.rb の中では、ENV['RAILS_ENV'] で取得できない。

$ config/schedule.rb

require File.expand_path(File.dirname(__FILE__) + "/environment")
require "yaml"

RAILS_ROOT = File.expand_path(File.dirname(__FILE__) + "/..") unless defined?(RAILS_ROOT)
CONFIG = YAML.load_file(RAILS_ROOT + "/config/schedule.yml")[@environment]

set :output, 'log/cron.log'

every 1.minute do
  command "curl #{CONFIG['value']} --tlsv1.0 -k"
end

$ config/schedule.yml

development:
    request: "http://batch/push"

test:
    value: "http://batch/push/hoge"

staging:
    value: "http://batch/push"

production:
    value: "http://aa/batch/push"

Capistrano3 でRailsをデプロイするとき、current_path, shared_path などを正しく取得する

$ config/deploy.rb

# config valid only for current version of Capistrano
lock '3.4.0'

set :application, 'hoge'
set :repo_url, 'git@bitbucket.org:hoge/hoge.git'

# Default value for :scm is :git
set :scm, :git

#
set :rbenv_ruby, '2.2.1'

# Default value for :pty is false
set :pty, true

# Default value for linked_dirs is []
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')

# Default value for default_env is {}
set :default_env, { rbenv_root: "$HOME/.rbenv/bin/rbenv", path: "$HOME/.rbenv/shims:$HOME/.rbenv/bin:$PATH" }

# Default value for keep_releases is 5
set :keep_releases, 4

# ここ!lambda を使う!
set :unicorn_config_path, -> {"#{current_path}/config/unicorn.rb"}

# ここ!lambda を使う!
set :unicorn_pid, -> {"#{shared_path}/tmp/pids/unicorn.pid"}

$ config/deploy/production.rb

set :stage,            :production
set :rails_env,        :production
set :unicorn_rack_env, :production

# Default deploy_to directory is /var/www/my_app_name
set :deploy_to, '/var/www/html/hoge'

server 'localhost', user: 'app', roles: %w{web app db

$ Capfile

# Load DSL and set up stages
require 'capistrano/setup'

# Include default deployment tasks
require 'capistrano/deploy'

#
require 'capistrano/rbenv'
require 'capistrano/bundler'
#require 'capistrano/rails/assets' # asset_sync を使うため外している
require 'capistrano/rails/migrations'
require 'capistrano3/unicorn'

# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }

heroku の Postgres のデータを、独自サーバーの mysql へ転送する

アップロード先 mysqlのサーバー起動

$ gem install taps
$ gem install mysql
$ taps server mysql://root@localhost/releasenote_stg?encoding=utf8 <basic認証名前> <basic認証パスワード>

5000 番ポートでサーバーが立ち上がります。
サーバーIP アドレスを確認しておく。

コピー元のheroku を操作する

$ gem install taps
$ gem install pg
$ gem install sqlite3
$ heroku config

HEROKU_POSTGRESQL_BRONZE_URL ここの値をコピーしておく。
仮に、postgres://dyzpnfomdzrvtv:HxftJDwDIEdih_VydYcL5CI-pT@ec2-54-204-43-139.compute-1.amazonaws.com:5432/diedpheq6q045 とする。

転送

$ taps push postgres://dyzpnfomdzrvtv:HxftJDwDIEdih_VydYcL5CI-pT@ec2-54-204-43-139.compute-1.amazonaws.com:5432/diedpheq6q045   http://<basic認証名前>:<basic認証パスワード>@<サーバーIPアドレス>:5000/