【问题标题】:Rails app keeps crashing when experiencing heavy loadRails 应用程序在负载过重时不断崩溃
【发布时间】:2018-12-02 14:12:25
【问题描述】:

我正在测试我的应用程序,因为我预计下周的负载会很重。我目前正在使用 BlazeMeter 来模拟负载。我的服务器使用 m5.large EC2 实例托管在 AWS Elasticbeanstalk 和 RDS 上。我已经使用 Puma、Capistrano 和 Nginx 设置了我的应用程序。我的配置如下:

//nginx.conf

upstream app {
  server unix: ///home/deploy/apps/appname/shared/tmp/sockets/appname-puma.sock;
}

server {
  listen 80;
  server_name example.com;

  root / home / deploy / apps / appname / current / public;

  if ($http_x_forwarded_proto != "https") {
    return 301 https: //$server_name$request_uri;
  }
}

server {
  listen 443 default_server http2;

  root / home / deploy / apps / appname / current / public;

  try_files / system / maintenance.html $uri / index.html $uri $uri.html @app;

  access_log /
    var / log / nginx / access.log main;
  access_log /
    var / log / nginx / healthd / application.log.$year - $month - $day - $hour healthd;
  error_log /
    var / log / nginx / error.log debug;

  location / assets {
    alias /
      var / app / current / public / assets;
    gzip_static on;
    gzip on;
    expires max;
    add_header Cache - Control public;
  }

  location~ * \.(jpg | jpeg | gif | css | png | js | ico | svg | svgz) $ {
    gzip_static on;
    gzip on;
    expires max;
    add_header Cache - Control public;
  }

  location @app {
    proxy_pass http: //app; # match the name of upstream directive which is defined above
      proxy_set_header Host $http_host;
    proxy_set_header X - Real - IP $remote_addr;
    proxy_set_header X - Forwarded - For $proxy_add_x_forwarded_for;
    proxy_set_header X - Forwarded - Proto $scheme;
    proxy_set_header HTTP_CLIENT_IP $remote_addr;
  }

  error_page 500 502 503 504 / 500. html;
  location / 500. html {}
  error_page 404 / 404. html;
  location / 404. html {}
  error_page 422 / 422. html;
  location / 422. html {}
}
##config/deploy.rb

# config valid only for current version of Capistrano
lock "3.8.2"

set :application, "appname"
set :repo_url, #"censored"
set :user,            'deploy'
set :puma_threads,    [16, 64]
set :puma_workers,    2

set :pty, true
set :use_sudo,        false
set :stage,           :production
set :deploy_via,      :remote_cache
set :deploy_to,       "/home/#{fetch(:user)}/apps/#{fetch(:application)}"#{}"/var/app/current"
set :puma_bind,       "unix://#{shared_path}/tmp/sockets/#{fetch(:application)}-puma.sock"
set :puma_state,      "#{shared_path}/tmp/pids/puma.state"
set :puma_pid,        "#{shared_path}/tmp/pids/puma.pid"
set :puma_access_log, "#{release_path}/log/puma.error.log"
set :puma_error_log,  "#{release_path}/log/puma.access.log"
set :ssh_options,     { forward_agent: true, user: fetch(:user), keys: %w(~/.ssh/id_rsa.pub) }
set :puma_preload_app, true
set :puma_worker_timeout, nil
set :puma_init_active_record, true  # Change to false when not using ActiveRecord

append :linked_files, %w{config/database.yml}
append :linked_dirs, ".bundle", "tmp", "public/system"#,  %w{bin log tmp/pids tmp/cache tmp/store vendor/bundle public/system}

namespace :puma do
  desc 'Create Directories for Puma Pids and Socket'
  task :make_dirs do
    on roles(:app) do
      execute "mkdir #{shared_path}/tmp/sockets -p"
      execute "mkdir #{shared_path}/tmp/pids -p"
    end
  end

  before :start, :make_dirs
end

namespace :deploy do
  desc "Make sure local git is in sync with remote."
  task :check_revision do
    on roles(:app) do
      unless `git rev-parse HEAD` == `git rev-parse origin/master`
        puts "WARNING: HEAD is not the same as origin/master"
        puts "Run `git push` to sync changes."
        exit
      end
    end
  end

  desc 'Initial Deploy'
  task :initial do
    on roles(:app) do
      before 'deploy:restart', 'puma:start'
      invoke 'deploy'
    end
  end

  desc 'Restart application'
  task :restart do
    on roles(:app), in: :sequence, wait: 5 do
      invoke 'puma:restart'
    end
  end

  before :starting,     :check_revision
  after  :finishing,    :compile_assets
end

有很多测试失败并且错误百分比很高。根据我在 elasticbeanstalk 的日志,

[error] 2465#0: *2262 testing "/var/app/current/public/assets" 存在失败(2:没有这样的文件或目录)

[crit] 2465#0: *2216 connect() to unix:///var/run/puma/my_app.sock 在连接到上游时失败(2:没有这样的文件或目录)

我是新手,我不知道为什么会这样!任何帮助表示赞赏!谢谢!

更新 1:我的网站在达到一定数量的模拟用户后也会显示502 Bad Gateway Nginx

更新 2: 就像 Myst 指出的那样,我也在使用数据库。

default: &default
    adapter: sqlite3
    pool: 5
    timeout: 5000

development:
    <<: *default
    database: db/development.sqlite3

test:
    <<: *default
    adapter: mysql2
    encoding: utf8
    database: <%= ENV['RDS_DB_NAME'] %>
    username: <%= ENV['RDS_USERNAME'] %>  
    password: <%= ENV['RDS_PASSWORD'] %>
    host: <%= ENV['RDS_HOSTNAME'] %> 
    port: <%= ENV['RDS_PORT'] %>

production:
    <<: *default
    adapter: mysql2
    encoding: utf8
    database: <%= ENV['RDS_DB_NAME'] %>  
    username: <%= ENV['RDS_USERNAME'] %>
    password: <%= ENV['RDS_PASSWORD'] %>
    host: <%= ENV['RDS_HOSTNAME'] %> 
    port: <%= ENV['RDS_PORT'] %>
    pool: 50 #20
    timeout: 10000

版本: capistrano3-美洲狮 (3.1.0) 红宝石 (2.3.0) 导轨 (4.2.8) mysql2 (0.4.9)

【问题讨论】:

  • 您在使用数据库吗?可能是您的数据库连接不足,使 64 线程计数毫无意义 - 请查看(并添加)数据库配置文件和数据库连接池计数。
  • P.S. Rails 通常是瓶颈,而不是服务器,但如果 R​​ails 应用程序足够快,您可以考虑使用 C 扩展(非 Ruby)应用程序服务器,它可能会提供更好的性能(即 iodine 或 agoo)。我偏爱碘,因为我是作者。
  • @Myst 是的,我正在使用数据库,我将很快添加我的配置文件。
  • 1.数据库配置中的pool 应该(至少)等于线程数,否则您的线程将等待数据库连接可用。有时使用更高的数字,我不知道为什么,但无论哪种方式,至少与线程数相同的数字。 2. 预加载应用程序后,必须关闭所有数据库连接,因此在 Puma 工作人员中打开新连接。如果您不知道该怎么做,请将 preloading 设置为 false。

标签: ruby-on-rails nginx amazon-ec2 capistrano puma


【解决方案1】:

一般来说 - 在处理高负载时,最好先衡量机器指标 - 就 RPS/同时客户端而言,它在稳定的情况下可以承受多少负载。并且在这个测试中——LA、内存使用、IO来确定当前的瓶颈是什么资源。

在 nginx (server unix:///... max_conns=20;) 中设置上游连接限制,默认情况下是无限的,在压力测试下这可能会导致工作人员膨胀并出现内存不足的错误。 一旦工作人员死亡 - nginx 无法连接到套接字并报告错误 502。

看看你的puma_error_log(好像和配置中的访问日志混淆了)有没有异常。

此外,由于您只有 2 个 cpu 内核 - 我怀疑是否需要 64 个线程乘以 2 个工作人员,除非您的大多数请求导致等待对外部 api 的调用。

【讨论】:

  • unless most of your requests result in waiting for calls to an external api - 大多数请求很可能会阻塞在数据库 IO 上...使得高线程数可能是正确的方法。
  • 错误仍然存​​在,所以现在我正在尝试使用这些数字,看看哪个配置会改善这种情况
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-26
  • 2012-07-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多