2

我们的 Rails 应用程序有两个部署到服务器的环境,一个是暂存环境,另一个是默认的生产环境。

staging.rb 文件是 config/environments 文件夹中的 production.rb 的副本。两者的区别在于 whiny nils 设置为 true:

config.whiny_nils = true

由于 Rails 应用程序主要用于它的 API,因此我们在我们的一个内部临时服务器上运行它以供开发人员使用。这行得通,顺利进行了近 4 个月。当需要转移到我们的生产服务器时,每当 POST 或 PUT 带有很大(有时非常非常大)的主体时,堆栈就会开始持续崩溃。在两台服务器之间进行测试时,登台服务器完美地处理了相同的请求。

崩溃/挂起中最令人沮丧的部分是缺少日志或追踪堆栈中发生崩溃的位置(nginx、phusion 乘客、ruby 1.9 补丁级别 243、rails 2.3.4)。nginx 错误日志、rails 日志或我们能找到的任何地方都没有出现任何内容。由于我们使用更新版本的 nginx、passenger 和 ruby​​ 运行生产服务器(补丁级别高于 staging,但仍然是 1.9),我们开始一次恢复每个组件,甚至转移所有可执行文件和支持文件(基本上我们在 /usr/local 中安装的所有内容)到生产机器无济于事。就在我们即将擦拭机器并再次尝试每一步时,有人建议将生产机器切换到“暂存”环境。. . 就像魔术一样,问题解决了!

想知道可能导致错误的原因,我们开始梳理 Rails 核心、我们自己的代码和我们所有的插件,寻找一些线索,了解是什么可能导致生产环境中出现如此大规模的挂起/崩溃,一次再次无济于事。

我能找到的唯一线索是行为。当测试“on”应用程序(rails 应用程序实际提供的页面之一)时,我会通过发送请求使应用程序崩溃,然后在频繁刷新(通常是 3-4 次)后,我将能够从Nginx 日志,最终应用程序将再次开始处理请求。错误如下:

    故障安全响应期间出错:不兼容的字符编码:UTF-8 和 ASCII-8BIT
    2009/10/09 17:52:40 [错误] 8691#0: *88 上游过早关闭连接,同时从上游读取响应标头,客户端:*我的 IP 地址*,服务器:myapp.mydomain.com,请求:“GET /api/sections/4/edit HTTP/1.1”,上游:“passenger://unix:/tmp/passenger.8677/master/helper_server.sock:”,主机:“myapp.mydomain.com”
    *** 应用程序中的异常 NoMethodError(nil:NilClass 的未定义方法“每个”)(进程 8703):来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger /rack/request_handler.rb:95:in `process_request'
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/abstract_request_handler.rb:206:in `main_loop'
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/railz/application_spawner.rb:376:in `start_request_handler'
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/railz/application_spawner.rb:334:in `block in handle_spawn_application'
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/utils.rb:182:in `safe_fork'
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/railz/application_spawner.rb:332:in `handle_spawn_application'
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/abstract_server.rb:351:in `main_loop'
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/abstract_server.rb:195:in `start_synchronously'
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/abstract_server.rb:162:in `start'
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/railz/application_spawner.rb:213:in `start'
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/spawn_manager.rb:261:in `block (2 levels) in spawn_rails_application'
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/abstract_server_collection.rb:126:in `lookup_or_add'
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/spawn_manager.rb:255:in `block in spawn_rails_application'
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/abstract_server_collection.rb:80:in `block in synchronize'
    来自:8:在“同步”中
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/abstract_server_collection.rb:79:in `synchronize'
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/spawn_manager.rb:254:in `spawn_rails_application'
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/spawn_manager.rb:153:in `spawn_application'
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/spawn_manager.rb:286:in `handle_spawn_application'
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/abstract_server.rb:351:in `main_loop'
    来自 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/lib/phusion_passenger/abstract_server.rb:195:in `start_synchronously'
    从 /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.4/bin/passenger-spawn-server:61:in `'

通常当出现字符编码错误时,我的第一轮是 ruby​​ 1.9 。. . 但是,从我的测试中您可以看出,两台机器上的版本相同!

毕竟,我想我想知道。. . 有人知道发生了什么吗?显然,我们暂时可以在 staging 中运行我们的应用程序,但我担心我可能发现了一些更深层次的问题需要解决。关于我应该寻找发生这种情况的下一个地方有什么想法吗?

我们的设置:Mac OS X 服务器:10.6.1、
Rails 2.3.4、
Ruby 1.9p243、
Nginx 0.8.17、
Passenger 2.2.5

我们需要的宝石:
environment.rb
守护进程
rmagick
test.rb
rspec
rspec-rails
factory-girl
rack-test

我们安装的插件:
acts-as-dag(用于创建有向无环图的活动记录插件)
daemon_generator
globalize2
no-peeping-toms(用于测试)
thinking-sphinx


更新(响应 khellll):

我试图将 config.whiny_nils = true 添加到生产环境,但是仍然发生崩溃。

另外,我回到我们的登台服务器并将环境设置为“生产”。. .同样的崩溃!

对我所说的“大型”请求主体的含义进行了一些澄清。会持续使应用程序崩溃的 POST/PUT 之一是大约 20,000 个字符(json)。由于 API 在一天中始终以小的 PUTS/POSTS 使用并保持运行,但只有在发出这些较大的请求时才会崩溃/挂起,我假设两者是连接的。

就 Rack/Ruby 1.9 而言。由于那里有大量关于 Rack 和 1.9 的信息,我确实将我们的 Rack gem 升级到了 git 存储库中的最新版本(据说修复了 1.9 的一些问题)。我读过关于 rewindable_input、ruby 1.9 等的大量困难……但是,由于我没有遇到我在其他 1.9 应用程序中遇到的 rewindable_input 错误,我确实认为这是一个不同的问题。此外,我在更改 rails 环境解决问题时排除了 Rack(当我搜索 Rack 源代码时,似乎没有任何特定于环境的方法会导致错误)。

希望这可以帮助!


更新以回应 pauliephonic

根本没有消息命中 Rails 日志(这实际上促使我在我们的 Web 堆栈中搜索了一段时间以查找该问题)。我认为发生崩溃/挂起的线索是,一旦发出大请求,应用程序在每个请求上只返回 500 个错误,但是这 500 个错误不会显示在 Rails 日志中。

我们的数据库配置是一样的(我们使用的是mysql集群,所以字面上是一样的,现在暂时使用本地mysql数据库,但是无论使用什么数据库都确认错误退出)

就多字节/ unicode而言。. . 我们正在一个国际化的应用程序中工作。. . 但是我不认为rails处理生产和其他人之间的unicode更改的方式对吗?正如我上面所说,这发生在POSTor上PUT。我在调试期间测试的方法是转到我的一个大型、高度嵌套的模型的相同编辑页面,然后尝试“保存”它。这会在生产中使应用程序崩溃,但不会在暂存中使应用程序崩溃。每次我测试相同的字符、相同的内容、相同的按钮、相同的行为。. . 根据环境做出不同的反应。我什至不能胡椒puts我的代码中到处都是语句,因为(看起来)请求没有进入 rails 应用程序。我的 Rails 日志或 Nginx 错误日志中没有收到任何错误消息(保存我在多次刷新时发布的那个)。

4

4 回答 4

0

我能理解的是,这一切config.whiny_nils都在发挥作用。如果您是我,我会查看activesupport/lib/active_support/whiny_nils.rb文件(看起来很简单)并尝试从那里玩弄它以了解有什么不同。我相信这与您在生产环境中遇到的异常类型有关,在使用 whiny_nils 时可能不会引发。

我相信您还需要提供有关“发布大型正文使我们的堆栈崩溃”部分的更多详细信息,因为这可能是 Rack 和 Ruby 1.9 的问题

于 2009-10-10T02:51:59.647 回答
0

在过去的几个月里,我遇到了类似的问题——直到最近才真正调试它。就我而言,告诉Passenger 将临时缓冲区文件放在哪里就可以了。难以找到的原因不仅是日志文件中缺少错误消息,而且该缓冲区不仅用于多部分帖子,还用于任何类型的大型帖子正文。

PassengerUploadBufferDir /tmp
于 2009-11-06T19:32:03.127 回答
0

从表面上看,这个错误是 Ruby 对编码的挑剔。您有一个它认为是 UTF-8 的字符串,并且您将其视为原始字节,可能是正确的。您需要识别有问题的字符串并调用buggy_string.force_encoding(Encoding::ASCII_8BIT)它。但是,如果我知道哪段代码在那个字符串上运行,或者为什么它只在生产中发生,那就见鬼了。发现问题实际上在Passenger的内心深处,我不会感到惊讶。

关于暂存和生产之间的区别,几乎可以肯定的是,应该将某些内容作为字节字符串移动,并且将其视为字符串。有大量代码只发生在生产环境中(比如缓存),如果有任何代码这样做,那就是你的问题。

whiny_nils件事很可能无关紧要。

于 2009-10-19T23:14:27.800 回答
0

我会尝试在 apache/passenger 上运行该应用程序,看看问题是否特定于 nginx/passenger

于 2009-10-20T03:42:24.640 回答