Unicorn + Nginx并发和数据重复

时间:2015-05-26 16:45:45

标签: ruby-on-rails ruby-on-rails-3 nginx concurrency unicorn

我有4名Nginx工作人员和4名独角兽工人。我们在一些验证唯一名称的模型中遇到了并发问题。当我们在同一资源上同时发送多个请求时,我们会获得重复的名称。例如,如果我们发送大约10个创建许可证的请求,我们会得到重复的serial_numbers ...

以下是一些背景信息:

模型(简化)

class License < ActiveRecord::Base
  validates :serial_number, :uniqueness => true
end

Unicorn.rb

APP_PATH = '.../manager'

worker_processes 4
working_directory APP_PATH # available in 0.94.0+

listen ".../manager/tmp/sockets/manager_rails.sock", backlog: 1024
listen 8080, :tcp_nopush => true # uncomment to listen to TCP port as well

timeout 600
pid "#{APP_PATH}/tmp/pids/unicorn.pid"
stderr_path "#{APP_PATH}/log/unicorn.stderr.log"
stdout_path "#{APP_PATH}/log/unicorn.stdout.log"

preload_app true

GC.copy_on_write_friendly = true if GC.respond_to?(:copy_on_write_friendly=)

check_client_connection false

run_once = true

before_fork do |server, worker|
  ActiveRecord::Base.connection.disconnect! if defined?(ActiveRecord::Base)
  MESSAGE_QUEUE.close
end

after_fork do |server, worker|
  ActiveRecord::Base.establish_connection if defined?(ActiveRecord::Base)
end

Nginx.conf(简化)

worker_processes 4;

events {
  multi_accept off;
  worker_connections 1024;
  use epoll;
  accept_mutex off;
}

upstream app_server {
  server unix:/home/blueserver/symphony/manager/tmp/sockets/manager_rails_write.sock fail_timeout=0;
}

try_files $uri @app;

location @app {
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_set_header Host $http_host;
  proxy_redirect off;
  proxy_connect_timeout      600;
  proxy_send_timeout         600;
  proxy_read_timeout         600;
  proxy_pass http://app_server;
}

每次我发送多个请求(超过4个)以创建许可证时,我都会得到一些重复项。我理解为什么。这是因为每个独角兽进程都没有创建serial_number的资源。所以,它允许多次创建它......

ActiveRecord正在验证进程级别而不是数据库级别的字段的唯一性。一种解决方法是将验证移动到数据库(但这将非常麻烦且难以维护)。

另一种解决方法是将写入请求(POST / PUT / DELETE)限制为仅一个独角兽,并有多个独角兽来回复读取请求(GET)。在Nginx的位置有这样的东西...

# 4 unicorn workers for GET requests
proxy_pass http://app_read_server;

# 1 unicorn worker for POST/PUT/DELETE requests
limit_except GET {
  proxy_pass http://app_write_server;
}

我们目前正在使用它。它修复了并发问题。但是,一个写入服务器不足以在高峰时间回复,并且会造成瓶颈。

有任何想法解决Nginx + Unicorn的并发性和可伸缩性问题吗?

2 个答案:

答案 0 :(得分:2)

看一下事务隔离。例如,PostgreSQL - http://www.postgresql.org/docs/current/static/transaction-iso.html

答案 1 :(得分:1)

通常情况下,您可以采取两种方式:

  • 对唯一键列使用唯一索引(通过迁移)并捕获适当的异常;

  • here描述的方式维护数据库约束,并捕获适当的异常。

或使用具有隔离级别的PostureSQL事务&#34;序列化&#34;这基本上是将平行翻译转换为连续翻译,正如Andrey Kryachkov早期描述的那样。